agentic.email/backend/app/schemas.py
2026-10-04 20:50:47 +05:30

354 lines
8.4 KiB
Python

from datetime import datetime, timezone
from datetime import date
from typing import Literal
from uuid import UUID
from pydantic import BaseModel, ConfigDict, EmailStr, Field
class AccountRegister(BaseModel):
account_type: Literal["individual", "company"]
email_name: str = Field(
min_length=1,
max_length=64,
pattern=r"^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,62}[A-Za-z0-9])?$",
)
company_domain: str | None = Field(default=None, max_length=253)
first_name: str = Field(min_length=1, max_length=80)
last_name: str = Field(min_length=1, max_length=80)
date_of_birth: date
phone_number: str = Field(
min_length=7,
max_length=24,
pattern=r"^\+?[0-9][0-9 ()-]{5,22}[0-9]$",
)
password: str = Field(min_length=8, max_length=128)
class AccountRead(BaseModel):
id: UUID
account_type: str
email: EmailStr
first_name: str
last_name: str
date_of_birth: date
phone_number: str
company_domain: str | None
is_domain_owner: bool = False
must_change_password: bool = False
created_at: datetime
model_config = ConfigDict(from_attributes=True)
class LoginRequest(BaseModel):
email: EmailStr
password: str = Field(min_length=1, max_length=128)
class AuthResponse(BaseModel):
access_token: str
token_type: Literal["bearer"] = "bearer"
account: AccountRead
class OrgMemberCreate(BaseModel):
first_name: str = Field(min_length=1, max_length=80)
last_name: str = Field(min_length=1, max_length=80)
email: EmailStr
invitation_email: EmailStr | None = None
section_id: UUID | None = None
org_role: Literal["user", "admin"] = "user"
send_invitation: bool = True
force_password_change: bool = False
password: str = Field(min_length=8, max_length=128)
class OrgMemberRead(BaseModel):
id: UUID
email: EmailStr
invitation_email: EmailStr | None = None
first_name: str
last_name: str
org_role: str
member_status: str
must_change_password: bool = False
is_domain_owner: bool = False
section_id: UUID | None = None
section_name: str | None = None
invitation_sent: bool = False
created_at: datetime
model_config = ConfigDict(from_attributes=True)
class OrgSectionCreate(BaseModel):
name: str = Field(min_length=1, max_length=120)
class OrgSectionRead(BaseModel):
id: UUID
name: str
created_at: datetime
model_config = ConfigDict(from_attributes=True)
class PasswordChangeRequest(BaseModel):
current_password: str = Field(min_length=1, max_length=128)
new_password: str = Field(min_length=8, max_length=128)
class OrgMemberListResponse(BaseModel):
items: list[OrgMemberRead]
counts: dict[str, int]
class MailGroupCreate(BaseModel):
name: str = Field(min_length=1, max_length=120)
email: EmailStr
group_type: Literal["distribution", "dynamic"] = "distribution"
member_ids: list[UUID] = Field(default_factory=list)
class MailGroupRead(BaseModel):
id: UUID
name: str
email: EmailStr
group_type: str
member_count: int
created_at: datetime
model_config = ConfigDict(from_attributes=True)
class MailGroupListResponse(BaseModel):
items: list[MailGroupRead]
counts: dict[str, int]
class MailAliasCreate(BaseModel):
alias_address: EmailStr
forwards_to: EmailStr
alias_type: Literal["user", "group"] = "user"
is_domain_alias: bool = False
class MailAliasRead(BaseModel):
id: UUID
alias_address: EmailStr
forwards_to: EmailStr
alias_type: str
is_domain_alias: bool
status: str
created_at: datetime
model_config = ConfigDict(from_attributes=True)
class MailAliasListResponse(BaseModel):
items: list[MailAliasRead]
counts: dict[str, int]
class OrgSecuritySettingsRead(BaseModel):
require_strong_passwords: bool
require_mfa_admins: bool
require_mfa_all_users: bool
session_timeout_minutes: int
model_config = ConfigDict(from_attributes=True)
class OrgSecuritySettingsUpdate(BaseModel):
require_strong_passwords: bool | None = None
require_mfa_admins: bool | None = None
require_mfa_all_users: bool | None = None
session_timeout_minutes: int | None = Field(default=None, ge=15, le=1440)
class OrgMemberRoleUpdate(BaseModel):
org_role: Literal["user", "admin"]
class EmailCreate(BaseModel):
recipients: list[EmailStr] = Field(min_length=1)
cc: list[EmailStr] = Field(default_factory=list)
bcc: list[EmailStr] = Field(default_factory=list)
subject: str = Field(default="", max_length=998, pattern=r"^[^\r\n]*$")
body_text: str = ""
body_html: str | None = None
class EmailRead(EmailCreate):
id: str
sender: EmailStr
status: str
created_at: datetime
class MailAddress(BaseModel):
name: str
address: str
class AttachmentRead(BaseModel):
filename: str
content_type: str
size: int
content_id: str | None = None
disposition: str = "attachment"
class MessageSummary(BaseModel):
id: str
mailbox: Literal["inbox", "sent", "trash"]
direction: Literal["inbound", "outbound"]
sender: MailAddress
recipients: list[MailAddress]
subject: str
snippet: str
status: str
created_at: datetime
is_read: bool
is_starred: bool = False
trashed_at: datetime | None = None
attachments: list[AttachmentRead] = Field(default_factory=list)
class MessageRead(MessageSummary):
cc: list[MailAddress] = Field(default_factory=list)
bcc: list[MailAddress] = Field(default_factory=list)
reply_to: list[MailAddress] = Field(default_factory=list)
body_text: str = ""
body_html: str | None = None
message_id: str | None = None
class MessageReadState(BaseModel):
is_read: bool
class MessageStarState(BaseModel):
is_starred: bool
class StickyNoteCreate(BaseModel):
title: str = Field(min_length=1, max_length=120)
body: str = Field(default="", max_length=2000)
tags: list[str] = Field(default_factory=list, max_length=5)
color: Literal["yellow", "green", "blue", "pink"] = "yellow"
class StickyNoteUpdate(BaseModel):
title: str | None = Field(default=None, min_length=1, max_length=120)
body: str | None = Field(default=None, max_length=2000)
tags: list[str] | None = Field(default=None, max_length=5)
color: Literal["yellow", "green", "blue", "pink"] | None = None
class StickyNoteRead(StickyNoteCreate):
id: str
created_at: datetime
updated_at: datetime
class MessagePage(BaseModel):
items: list[MessageSummary]
next_cursor: str | None = None
class DomainCreate(BaseModel):
domain_name: str = Field(min_length=3, max_length=253)
account_id: UUID | None = None
class DomainNameCreate(BaseModel):
domain_name: str = Field(min_length=3, max_length=253)
class DnsRecordRead(BaseModel):
id: UUID
record_type: str
host: str
value: str
purpose: str
ttl: int
model_config = ConfigDict(from_attributes=True)
class DnsVerificationCheck(BaseModel):
purpose: str
verified: bool
message: str
class DnsVerificationResponse(BaseModel):
domain: str
status: str
verified: bool
checks: list[DnsVerificationCheck]
class MailDomainRead(BaseModel):
id: UUID
domain_name: str
domain_type: str
account_id: UUID | None
mail_host: str
dkim_selector: str
status: str
created_at: datetime
dns_records: list[DnsRecordRead] = []
model_config = ConfigDict(from_attributes=True)
class SmtpCredentialCreate(BaseModel):
label: str = Field(default="default", min_length=1, max_length=120)
class SmtpCredentialRead(BaseModel):
id: UUID
username: str
label: str
is_active: bool
created_at: datetime
model_config = ConfigDict(from_attributes=True)
class SmtpCredentialCreated(SmtpCredentialRead):
password: str
smtp_host: str
smtp_port: int
use_tls: bool
class DnsSetupRequest(BaseModel):
domain: str = Field(min_length=3, max_length=253)
mail_server_ip: str = Field(min_length=3, max_length=45)
class DnsSetupRecord(BaseModel):
record_type: str
host: str
value: str
purpose: str
ttl: int
priority: int | None = None
class DnsSetupResponse(BaseModel):
domain: str
mail_host: str
app_public_host: str
mail_server_ip: str
is_platform_domain: bool
sections: dict[str, list[DnsSetupRecord]]
notes: list[str] = Field(default_factory=list)
def utc_now() -> datetime:
return datetime.now(timezone.utc)