309 lines
7.2 KiB
Python
309 lines
7.2 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
|
|
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
|
|
org_role: Literal["user", "admin"] = "user"
|
|
send_invitation: bool = True
|
|
password: str | None = Field(default=None, min_length=8, max_length=128)
|
|
|
|
|
|
class OrgMemberRead(BaseModel):
|
|
id: UUID
|
|
email: EmailStr
|
|
first_name: str
|
|
last_name: str
|
|
org_role: str
|
|
member_status: str
|
|
is_domain_owner: bool = False
|
|
groups: list[str] = Field(default_factory=list)
|
|
created_at: datetime
|
|
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
|
|
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 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)
|