first commit
This commit is contained in:
101
local/models.py
Normal file
101
local/models.py
Normal file
@@ -0,0 +1,101 @@
|
||||
import re
|
||||
from decimal import Decimal
|
||||
from typing import Literal
|
||||
from uuid import UUID
|
||||
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
||||
|
||||
class StrictModel(BaseModel):
|
||||
model_config = ConfigDict(extra='forbid', allow_inf_nan=False)
|
||||
|
||||
class Customer(StrictModel):
|
||||
cnpj: str
|
||||
zap: str
|
||||
mail: str = Field(max_length=254)
|
||||
|
||||
@field_validator('cnpj')
|
||||
@classmethod
|
||||
def cnpj_valid(cls, value):
|
||||
digits = re.sub(r'\D', '', value)
|
||||
if len(digits) != 14 or len(set(digits)) == 1 or not digits.isascii():
|
||||
raise ValueError('Invalid CNPJ')
|
||||
def check(base, weights):
|
||||
rem = sum(int(n) * w for n,w in zip(base, weights)) % 11
|
||||
return 0 if rem < 2 else 11-rem
|
||||
if check(digits[:12], [5,4,3,2,9,8,7,6,5,4,3,2]) != int(digits[12]) or check(digits[:13], [6,5,4,3,2,9,8,7,6,5,4,3,2]) != int(digits[13]):
|
||||
raise ValueError('Invalid CNPJ')
|
||||
return digits
|
||||
|
||||
@field_validator('zap')
|
||||
@classmethod
|
||||
def phone_valid(cls, value):
|
||||
digits = re.sub(r'\D', '', value)
|
||||
if len(digits) not in (10,11) or not digits.isascii():
|
||||
raise ValueError('Invalid phone')
|
||||
return digits
|
||||
|
||||
@field_validator('mail')
|
||||
@classmethod
|
||||
def email_valid(cls, value):
|
||||
if not re.fullmatch(r'[^\s@]+@[^\s@]+\.[a-zA-Z]{2,}', value.strip()):
|
||||
raise ValueError('Invalid email')
|
||||
return value.strip()
|
||||
|
||||
class Freight(StrictModel):
|
||||
service: Literal['pickup','mock-standard'] = 'pickup'
|
||||
postal_code: str = Field(default='', max_length=8)
|
||||
|
||||
class UploadStart(StrictModel):
|
||||
name: str = Field(min_length=1, max_length=200, pattern=r'^[^/\\\x00-\x1f]+$')
|
||||
size: int = Field(gt=0, strict=True)
|
||||
|
||||
@field_validator('name')
|
||||
@classmethod
|
||||
def artwork_extension(cls, value):
|
||||
# Union of existing Site product formats; this is NOT malware/pre-flight validation.
|
||||
if not re.search(r'\.(png|jpe?g|webp|tiff?|pdf|psd|psb|ai|cdr)$', value, re.I):
|
||||
raise ValueError('Unsupported artwork file extension')
|
||||
return value
|
||||
|
||||
class Item(StrictModel):
|
||||
mode: Literal['file','avulsa','uvfile','uv']
|
||||
metres: Decimal = Field(gt=0, le=12000)
|
||||
grade: int = Field(ge=0, le=100, strict=True)
|
||||
uploads: list[UUID] = Field(min_length=1, max_length=20)
|
||||
|
||||
class QuoteRequest(StrictModel):
|
||||
request_key: UUID
|
||||
customer: Customer
|
||||
items: list[Item] = Field(min_length=1, max_length=30)
|
||||
freight: Freight
|
||||
|
||||
class Review(StrictModel):
|
||||
items: list[Item] = Field(min_length=1, max_length=30)
|
||||
|
||||
class Pay(StrictModel):
|
||||
quote_id: UUID
|
||||
|
||||
class Move(StrictModel):
|
||||
state: Literal['rec','tra','fil','imp','cor','fin']
|
||||
version: int = Field(ge=0)
|
||||
reason: str = Field(default='', max_length=1000)
|
||||
|
||||
class Register(StrictModel):
|
||||
customer: Customer
|
||||
password: str = Field(min_length=12, max_length=128)
|
||||
|
||||
class Login(StrictModel):
|
||||
email: str = Field(min_length=3, max_length=254)
|
||||
password: str = Field(min_length=1, max_length=128)
|
||||
|
||||
class OperatorLogin(StrictModel):
|
||||
username: str = Field(min_length=1, max_length=100)
|
||||
password: str = Field(min_length=1, max_length=128)
|
||||
|
||||
class FileReference(StrictModel):
|
||||
upload_id: UUID
|
||||
item_index: int = Field(ge=0, strict=True)
|
||||
|
||||
class ArtworkSubmission(StrictModel):
|
||||
version: int = Field(ge=0, strict=True)
|
||||
files: list[FileReference] = Field(min_length=1, max_length=60)
|
||||
note: str = Field(min_length=1, max_length=1000)
|
||||
Reference in New Issue
Block a user