from pydantic import BaseModel, constr, field_validator, validator from fastapi import HTTPException, status from typing import Optional from datetime import datetime # Funções para sanitização de entradas (evitar XSS, SQLi etc.) # É importante que esta função seja mantida/implementada no seu ambiente # from actions.validations.text import Text # Descomentar se for usar # Funções para validar URL (ajustar importação conforme seu projeto) # from actions.validations.url import URL # Descomentar se for usar # ---------------------------------------------------- # Schema Base: Usado para leitura (GET, SHOW, INDEX) # Inclui todos os campos, incluindo os gerados pelo banco # ---------------------------------------------------- class AtoDocumentoSchema(BaseModel): ato_documento_id: Optional[int] = None ato_principal_id: Optional[int] = None # bigint NOT NULL url: Optional[str] = None # text NOT NULL nome_documento: Optional[str] = None # varchar(255) NOT NULL tipo_documento: Optional[str] = None # varchar(50) NOT NULL created_at: Optional[datetime] = None updated_at: Optional[datetime] = None class Config: from_attributes = True # ---------------------------------------------------- # Schema para Requisição de ID: Usado em SHOW e DELETE # ---------------------------------------------------- class AtoDocumentoIdSchema(BaseModel): ato_documento_id: int @field_validator("ato_documento_id") def validate_ato_documento_id(cls, v: int): if v <= 0: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=[ { "input": "ato_documento_id", "message": "ID do documento deve ser um valor positivo.", } ], ) return v # ---------------------------------------------------- # Schema para Criação (SAVE): Campos obrigatórios e sem ID # ---------------------------------------------------- class AtoDocumentoSaveSchema(BaseModel): # Campos obrigatórios ato_principal_id: Optional[int] = None # <<< tornar opcional url: str nome_documento: constr(max_length=255) tipo_documento: constr(max_length=50) # Nota: created_at e updated_at são tratados pelo Model/Banco # Validação e Sanitização de URL (chk_url_https) @field_validator("url") def validate_url(cls, v: str): v = v.strip() if not v.startswith("https://"): raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=[ {"input": "url", "message": "A URL do documento deve ser HTTPS."} ], ) # Adicionar aqui a validação de URL (ex: URL.is_valid_url(v)) se disponível return v # Validação e Sanitização de Tipo Documento (chk_tipo_documento_not_empty) @field_validator("tipo_documento") def validate_tipo_documento(cls, v: str): v = v.strip() if not v: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=[ { "input": "tipo_documento", "message": "O tipo de documento não pode ser vazio.", } ], ) # Adicionar aqui a sanitização de texto (ex: Text.sanitize(v)) se disponível return v # Validação e Sanitização de Nome Documento @field_validator("nome_documento") def validate_nome_documento(cls, v: str): v = v.strip() if not v: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=[ { "input": "nome_documento", "message": "O nome do documento não pode ser vazio.", } ], ) return v # ---------------------------------------------------- # Schema para Atualização (UPDATE): Todos opcionais (parciais) # ---------------------------------------------------- class AtoDocumentoUpdateSchema(BaseModel): # Todos os campos são opcionais no UPDATE ato_principal_id: Optional[int] = None url: Optional[str] = None nome_documento: Optional[constr(max_length=255)] = None tipo_documento: Optional[constr(max_length=50)] = None # Validação de URL @field_validator("url") def validate_url(cls, v: Optional[str]): if v is None: return v v = v.strip() if v and not v.startswith("https://"): raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=[ {"input": "url", "message": "A URL do documento deve ser HTTPS."} ], ) return v # Validação de Tipo Documento @field_validator("tipo_documento") def validate_tipo_documento(cls, v: Optional[str]): if v is None: return v v = v.strip() if not v: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=[ { "input": "tipo_documento", "message": "O tipo de documento não pode ser vazio.", } ], ) return v