141 lines
4.8 KiB
Python
141 lines
4.8 KiB
Python
from pydantic import BaseModel, constr, field_validator
|
|
from fastapi import HTTPException, status
|
|
from typing import Optional
|
|
from datetime import datetime
|
|
import re
|
|
|
|
# Funções para sanitização de entradas (evitar XSS, SQLi etc.)
|
|
from actions.validations.text import Text
|
|
|
|
# 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
|
|
|
|
|
|
# ----------------------------------------------------
|
|
# Schema Base: Usado para leitura (GET, SHOW, INDEX)
|
|
# Inclui todos os campos, incluindo os gerados pelo banco
|
|
# ----------------------------------------------------
|
|
class AtoParteSchema(BaseModel):
|
|
ato_parte_id: Optional[int] = None
|
|
ato_principal_id: Optional[int] = None # bigint NOT NULL
|
|
nome: Optional[str] = None # varchar(255) NOT NULL
|
|
telefone: Optional[str] = None # varchar(20) DEFAULT NULL
|
|
cpf_cnpj: Optional[str] = None # varchar(20) 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 AtoParteIdSchema(BaseModel):
|
|
ato_parte_id: int
|
|
|
|
@field_validator("ato_parte_id")
|
|
def validate_ato_parte_id(cls, v: int):
|
|
if v <= 0:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
detail=[
|
|
{
|
|
"input": "ato_parte_id",
|
|
"message": "ID da parte deve ser um valor positivo.",
|
|
}
|
|
],
|
|
)
|
|
return v
|
|
|
|
|
|
# ----------------------------------------------------
|
|
# Funções de Validação Comuns
|
|
# ----------------------------------------------------
|
|
|
|
|
|
def validate_cpf_cnpj(cls, v: str):
|
|
v = re.sub(r"[^\d]", "", v).strip() # Remove caracteres não numéricos
|
|
|
|
# chk_cpf_cnpj_formato CHECK (regexp_like(`cpf_cnpj`,_utf8mb4'^[0-9]{11,14}$'))
|
|
if not re.match(r"^\d{11,14}$", v):
|
|
raise HTTPException(
|
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
detail=[
|
|
{
|
|
"input": "cpf_cnpj",
|
|
"message": "CPF/CNPJ deve conter apenas 11 (CPF) ou 14 (CNPJ) dígitos numéricos.",
|
|
}
|
|
],
|
|
)
|
|
return v
|
|
|
|
|
|
def validate_nome_not_empty(cls, v: str):
|
|
v = v.strip()
|
|
if not v:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
detail=[
|
|
{
|
|
"input": "nome",
|
|
"message": "O nome não pode ser vazio.",
|
|
}
|
|
],
|
|
)
|
|
# Sanitiza o campo
|
|
return Text.sanitize_input(v)
|
|
|
|
|
|
# ----------------------------------------------------
|
|
# Schema para Criação (SAVE): Campos obrigatórios e sem ID
|
|
# ----------------------------------------------------
|
|
class AtoParteSaveSchema(BaseModel):
|
|
# Campos obrigatórios
|
|
ato_principal_id: Optional[int] = None # <<< tornar opcional
|
|
nome: constr(max_length=255)
|
|
cpf_cnpj: constr(
|
|
max_length=20
|
|
) # Permitindo até 20 para acomodar a entrada antes de limpar
|
|
|
|
# Campo opcional (nullable na DDL)
|
|
telefone: Optional[constr(max_length=20)] = None
|
|
|
|
# Validação de Nome
|
|
@field_validator("nome")
|
|
def validate_nome(cls, v: str):
|
|
return validate_nome_not_empty(cls, Text.sanitize_input(v))
|
|
|
|
# Validação de CPF/CNPJ
|
|
@field_validator("cpf_cnpj")
|
|
def validate_cpf_cnpj_field(cls, v: str):
|
|
return validate_cpf_cnpj(cls, Text.sanitize_input(v))
|
|
|
|
|
|
# ----------------------------------------------------
|
|
# Schema para Atualização (UPDATE): Todos opcionais (parciais)
|
|
# ----------------------------------------------------
|
|
class AtoParteUpdateSchema(BaseModel):
|
|
# Todos os campos são opcionais no UPDATE
|
|
ato_principal_id: Optional[int] = None
|
|
nome: Optional[constr(max_length=255)] = None
|
|
telefone: Optional[constr(max_length=20)] = None
|
|
cpf_cnpj: Optional[constr(max_length=20)] = None
|
|
|
|
# Validação de Nome
|
|
@field_validator("nome")
|
|
def validate_nome_update(cls, v: Optional[str]):
|
|
if v is None:
|
|
return v
|
|
return validate_nome_not_empty(cls, Text.sanitize_input(v))
|
|
|
|
# Validação de CPF/CNPJ
|
|
@field_validator("cpf_cnpj")
|
|
def validate_cpf_cnpj_update(cls, v: Optional[str]):
|
|
if v is None:
|
|
return Text.sanitize_input(v)
|
|
return validate_cpf_cnpj(cls, Text.sanitize_input(v))
|
|
|
|
# Nota: Telefone não precisa de validação complexa além do constr(max_length)
|
|
# se o objetivo for apenas armazenar a string fornecida.
|