116 lines
No EOL
4.5 KiB
Python
116 lines
No EOL
4.5 KiB
Python
from pydantic import BaseModel, constr, field_validator, model_validator
|
|
from fastapi import HTTPException, status
|
|
from typing import Optional
|
|
from datetime import datetime
|
|
|
|
# Funções utilitárias para sanitização de entradas (evitar XSS, SQLi etc.)
|
|
# É necessário importar a função de sanitização se for utilizada nos validadores
|
|
from actions.validations.text import Text
|
|
|
|
# ----------------------------------------------------
|
|
# Schema base - Representa a estrutura completa do Cliente (usado em Show e Index)
|
|
# ----------------------------------------------------
|
|
class ClientSchema(BaseModel):
|
|
# Campos da DDL, todos opcionais para o Schema base (principalmente para leitura)
|
|
client_id: Optional[int] = None
|
|
cns: Optional[str] = None
|
|
name: Optional[str] = None
|
|
date_register: Optional[datetime] = None
|
|
state: Optional[str] = None
|
|
city: Optional[str] = None
|
|
responsible: Optional[str] = None
|
|
consultant: Optional[str] = None
|
|
type_contract: Optional[str] = None
|
|
status: Optional[str] = None
|
|
|
|
class Config:
|
|
# Permite que o Pydantic mapeie campos vindos do banco (ex: via ORM)
|
|
from_attributes = True
|
|
|
|
# ----------------------------------------------------
|
|
# Schema para operações que requerem apenas o ID
|
|
# ----------------------------------------------------
|
|
class ClientIdSchema(BaseModel):
|
|
client_id: Optional[int] = None
|
|
|
|
# Valida se o ID não está vazio
|
|
@model_validator(mode='after')
|
|
def validate_client_id(self):
|
|
if not self.client_id or self.client_id <= 0:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
detail='O ID do cliente é obrigatório para esta operação.'
|
|
)
|
|
return self
|
|
|
|
# ----------------------------------------------------
|
|
# Schema para localizar cliente pelo CNS
|
|
# ----------------------------------------------------
|
|
class ClientCNSSchema(BaseModel):
|
|
cns: Optional[str] = None
|
|
|
|
# Sanitiza o input
|
|
@field_validator('cns')
|
|
def sanitize_cns(cls, v):
|
|
if v:
|
|
return Text.sanitize_input(v) # Mantendo o padrão de sanitização
|
|
return v
|
|
|
|
# Valida se o campo não está vazio
|
|
@model_validator(mode='after')
|
|
def validate_cns(self):
|
|
if not self.cns or len(self.cns.strip()) == 0:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
detail='Informe um CNS para a busca.'
|
|
)
|
|
return self
|
|
|
|
# ----------------------------------------------------
|
|
# Schema para cadastrar (SAVE) um novo cliente (name é NOT NULL)
|
|
# ----------------------------------------------------
|
|
class ClientSaveSchema(BaseModel):
|
|
# Opcional, pois é AUTO_INCREMENT, mas pode ser usado para Upsert
|
|
client_id: Optional[int] = None
|
|
|
|
# name é NOT NULL na DDL, então é obrigatório no save
|
|
name: constr(min_length=1, max_length=550)
|
|
|
|
# Os demais são NULL DEFAULT ou com DEFAULT, então podem ser Optional na entrada
|
|
cns: Optional[str] = None
|
|
state: Optional[str] = None
|
|
city: Optional[str] = None
|
|
responsible: Optional[str] = None
|
|
consultant: Optional[str] = None
|
|
type_contract: Optional[str] = None
|
|
status: Optional[str] = None
|
|
|
|
# Sanitiza os inputs de string
|
|
@field_validator('cns', 'name', 'state', 'city', 'responsible', 'consultant', 'type_contract')
|
|
def validate_and_sanitize_fields(cls, v):
|
|
if v is not None:
|
|
# Assumindo que Text.sanitize_input existe e faz a sanitização
|
|
return Text.sanitize_input(v)
|
|
return v
|
|
|
|
# ----------------------------------------------------
|
|
# Schema para atualizar (UPDATE) um cliente (tudo opcional)
|
|
# ----------------------------------------------------
|
|
class ClientUpdateSchema(BaseModel):
|
|
# Todos os campos que podem ser atualizados são opcionais
|
|
cns: Optional[str] = None
|
|
name: Optional[constr(min_length=1, max_length=550)] = None
|
|
state: Optional[str] = None
|
|
city: Optional[str] = None
|
|
responsible: Optional[str] = None
|
|
consultant: Optional[str] = None
|
|
type_contract: Optional[str] = None
|
|
status: Optional[str] = None
|
|
|
|
# Sanitiza os inputs de string
|
|
@field_validator('cns', 'name', 'state', 'city', 'responsible', 'consultant', 'type_contract')
|
|
def validate_and_sanitize_fields(cls, v):
|
|
if v is not None:
|
|
# Assumindo que Text.sanitize_input existe e faz a sanitização
|
|
return Text.sanitize_input(v)
|
|
return v |