355 lines
8.1 KiB
Python
355 lines
8.1 KiB
Python
"""Pydantic schemas for the Mail plugin."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field
|
|
|
|
# ─── Mail Accounts ───
|
|
|
|
|
|
class MailAccountCreate(BaseModel):
|
|
model_config = ConfigDict(populate_by_name=True)
|
|
email_address: str = Field(..., min_length=1, max_length=255, alias="email")
|
|
display_name: str = Field(default="", max_length=255)
|
|
imap_host: str = Field(..., min_length=1, max_length=255)
|
|
imap_port: int = Field(default=993, ge=1, le=65535)
|
|
imap_ssl: bool = True
|
|
smtp_host: str = Field(..., min_length=1, max_length=255)
|
|
smtp_port: int = Field(default=587, ge=1, le=65535)
|
|
smtp_tls: bool = True
|
|
username: str = Field(default="", min_length=0, max_length=255)
|
|
password: str = Field(..., min_length=1, max_length=512)
|
|
is_shared: bool = False
|
|
|
|
|
|
class MailAccountUpdate(BaseModel):
|
|
model_config = ConfigDict(populate_by_name=True)
|
|
email_address: str | None = Field(None, min_length=1, max_length=255, alias="email")
|
|
display_name: str | None = Field(None, max_length=255)
|
|
imap_host: str | None = Field(None, min_length=1, max_length=255)
|
|
imap_port: int | None = Field(None, ge=1, le=65535)
|
|
imap_ssl: bool | None = None
|
|
smtp_host: str | None = Field(None, min_length=1, max_length=255)
|
|
smtp_port: int | None = Field(None, ge=1, le=65535)
|
|
smtp_tls: bool | None = None
|
|
username: str | None = Field(None, min_length=1, max_length=255)
|
|
password: str | None = Field(None, min_length=1, max_length=512)
|
|
is_shared: bool | None = None
|
|
is_active: bool | None = None
|
|
|
|
|
|
class MailAccountResponse(BaseModel):
|
|
id: str
|
|
email: str
|
|
email_address: str
|
|
display_name: str
|
|
imap_host: str
|
|
imap_port: int
|
|
imap_ssl: bool
|
|
smtp_host: str
|
|
smtp_port: int
|
|
smtp_tls: bool
|
|
username: str
|
|
is_shared: bool
|
|
is_active: bool
|
|
created_at: datetime | None = None
|
|
updated_at: datetime | None = None
|
|
|
|
|
|
class SharedMailboxUserAssign(BaseModel):
|
|
user_ids: list[str] = Field(default_factory=list)
|
|
|
|
|
|
class DelegateCreate(BaseModel):
|
|
delegate_user_id: str
|
|
access_level: str = Field("read", pattern="^(read|full)$")
|
|
|
|
|
|
class SendPermissionCreate(BaseModel):
|
|
user_id: str
|
|
|
|
|
|
# ─── Mail Folders ───
|
|
|
|
|
|
class MailFolderCreate(BaseModel):
|
|
account_id: str
|
|
name: str = Field(..., min_length=1, max_length=255)
|
|
imap_name: str = Field(..., min_length=1, max_length=255)
|
|
parent_id: str | None = None
|
|
|
|
|
|
class MailFolderUpdate(BaseModel):
|
|
name: str | None = Field(None, min_length=1, max_length=255)
|
|
|
|
|
|
class MailFolderResponse(BaseModel):
|
|
id: str
|
|
account_id: str
|
|
name: str
|
|
imap_name: str
|
|
parent_id: str | None = None
|
|
is_standard: bool
|
|
unread_count: int
|
|
total_count: int
|
|
|
|
|
|
# ─── Mails ───
|
|
|
|
|
|
class MailSendRequest(BaseModel):
|
|
account_id: str
|
|
to: list[str] = Field(..., min_length=1)
|
|
cc: list[str] = Field(default_factory=list)
|
|
bcc: list[str] = Field(default_factory=list)
|
|
subject: str = Field(default="", max_length=512)
|
|
body_html: str = ""
|
|
body_text: str = ""
|
|
in_reply_to: str | None = None
|
|
references_header: str | None = None
|
|
signature_id: str | None = None
|
|
template_id: str | None = None
|
|
template_vars: dict[str, str] = Field(default_factory=dict)
|
|
attachments: list[str] = Field(default_factory=list)
|
|
|
|
|
|
class MailReplyRequest(BaseModel):
|
|
body_html: str = ""
|
|
body_text: str = ""
|
|
reply_to_all: bool = False
|
|
signature_id: str | None = None
|
|
|
|
|
|
class MailForwardRequest(BaseModel):
|
|
to: list[str] = Field(..., min_length=1)
|
|
cc: list[str] = Field(default_factory=list)
|
|
body_html: str = ""
|
|
body_text: str = ""
|
|
signature_id: str | None = None
|
|
|
|
|
|
class MailFlagsUpdate(BaseModel):
|
|
is_seen: bool | None = None
|
|
is_flagged: bool | None = None
|
|
is_draft: bool | None = None
|
|
is_answered: bool | None = None
|
|
is_forwarded: bool | None = None
|
|
|
|
|
|
class MailResponse(BaseModel):
|
|
id: str
|
|
account_id: str
|
|
folder_id: str
|
|
message_id: str
|
|
thread_id: str
|
|
in_reply_to: str | None = None
|
|
subject: str
|
|
from_address: str
|
|
to_addresses: str
|
|
cc_addresses: str
|
|
bcc_addresses: str
|
|
body_text: str
|
|
body_html_sanitized: str
|
|
is_seen: bool
|
|
is_flagged: bool
|
|
is_draft: bool
|
|
is_answered: bool
|
|
is_forwarded: bool
|
|
has_attachments: bool
|
|
size_bytes: int
|
|
received_at: datetime | None = None
|
|
sent_at: datetime | None = None
|
|
contact_id: str | None = None
|
|
company_id: str | None = None
|
|
attachments: list[dict] = Field(default_factory=list)
|
|
labels: list[dict] = Field(default_factory=list)
|
|
|
|
|
|
class MailListResponse(BaseModel):
|
|
mails: list[MailResponse]
|
|
total: int
|
|
page: int
|
|
page_size: int
|
|
|
|
|
|
class MailLinkRequest(BaseModel):
|
|
contact_id: str | None = None
|
|
company_id: str | None = None
|
|
|
|
|
|
class MailCreateEventRequest(BaseModel):
|
|
calendar_id: str
|
|
title: str | None = None
|
|
start: str | None = None
|
|
end: str | None = None
|
|
description: str | None = None
|
|
|
|
|
|
class ThreadResponse(BaseModel):
|
|
thread_id: str
|
|
subject: str
|
|
mail_count: int
|
|
mails: list[MailResponse] = Field(default_factory=list)
|
|
|
|
|
|
# ─── Templates ───
|
|
|
|
|
|
class MailTemplateCreate(BaseModel):
|
|
name: str = Field(..., min_length=1, max_length=255)
|
|
subject: str = Field(default="", max_length=512)
|
|
body_html: str = ""
|
|
|
|
|
|
class MailTemplateResponse(BaseModel):
|
|
id: str
|
|
name: str
|
|
subject: str
|
|
body_html: str
|
|
|
|
|
|
class TemplateSubstituteRequest(BaseModel):
|
|
template_id: str
|
|
variables: dict[str, str] = Field(default_factory=dict)
|
|
|
|
|
|
# ─── Signatures ───
|
|
|
|
|
|
class MailSignatureCreate(BaseModel):
|
|
name: str = Field(..., min_length=1, max_length=255)
|
|
body_html: str = ""
|
|
account_id: str | None = None
|
|
is_default: bool = False
|
|
|
|
|
|
class MailSignatureResponse(BaseModel):
|
|
id: str
|
|
name: str
|
|
body_html: str
|
|
account_id: str | None = None
|
|
is_default: bool
|
|
|
|
|
|
# ─── Rules ───
|
|
|
|
|
|
class MailRuleCreate(BaseModel):
|
|
name: str = Field(..., min_length=1, max_length=255)
|
|
account_id: str | None = None
|
|
priority: int = 0
|
|
is_active: bool = True
|
|
conditions: dict = Field(default_factory=dict)
|
|
actions: dict = Field(default_factory=dict)
|
|
|
|
|
|
class MailRuleResponse(BaseModel):
|
|
id: str
|
|
name: str
|
|
account_id: str | None = None
|
|
priority: int
|
|
is_active: bool
|
|
conditions: dict
|
|
actions: dict
|
|
|
|
|
|
# ─── Vacation ───
|
|
|
|
|
|
class VacationConfig(BaseModel):
|
|
account_id: str
|
|
is_enabled: bool = True
|
|
subject: str = Field(default="Out of Office", max_length=512)
|
|
body_text: str = ""
|
|
body_html: str = ""
|
|
start_date: str | None = None
|
|
end_date: str | None = None
|
|
|
|
|
|
class VacationResponse(BaseModel):
|
|
is_enabled: bool
|
|
subject: str
|
|
body_text: str
|
|
body_html: str
|
|
|
|
|
|
# ─── PGP ───
|
|
|
|
|
|
class PgpKeyImport(BaseModel):
|
|
private_key_armored: str = Field(..., min_length=1)
|
|
passphrase: str = Field(default="", max_length=255)
|
|
|
|
|
|
class PgpKeyResponse(BaseModel):
|
|
id: str
|
|
key_id: str
|
|
public_key_armored: str
|
|
|
|
|
|
class ContactPgpKeyCreate(BaseModel):
|
|
public_key_armored: str = Field(..., min_length=1)
|
|
|
|
|
|
class ContactPgpKeyResponse(BaseModel):
|
|
id: str
|
|
contact_id: str
|
|
public_key_armored: str
|
|
key_id: str
|
|
|
|
|
|
class PgpEncryptRequest(BaseModel):
|
|
recipient_email: str
|
|
plaintext: str
|
|
|
|
|
|
class PgpDecryptRequest(BaseModel):
|
|
ciphertext: str
|
|
passphrase: str = ""
|
|
|
|
|
|
# ─── Labels ───
|
|
|
|
|
|
class MailLabelCreate(BaseModel):
|
|
name: str = Field(..., min_length=1, max_length=100)
|
|
color: str = Field(default="#808080", max_length=20)
|
|
|
|
|
|
class MailLabelResponse(BaseModel):
|
|
id: str
|
|
name: str
|
|
color: str
|
|
|
|
|
|
class MailLabelAssign(BaseModel):
|
|
label_id: str
|
|
|
|
|
|
# ─── Search ───
|
|
|
|
|
|
class MailSearchResponse(BaseModel):
|
|
results: list[MailResponse]
|
|
total: int
|
|
|
|
|
|
# ─── Connection Test ───
|
|
|
|
|
|
class ConnectionTestRequest(BaseModel):
|
|
imap_host: str
|
|
imap_port: int = 993
|
|
smtp_host: str
|
|
smtp_port: int = 587
|
|
username: str
|
|
password: str
|
|
|
|
|
|
class ConnectionTestResponse(BaseModel):
|
|
imap_ok: bool
|
|
smtp_ok: bool
|
|
message: str
|