Add hierarchical mail servers and credentials

This commit is contained in:
2026-07-28 19:32:56 +02:00
parent 2813c671c0
commit 3735027b3d
15 changed files with 4105 additions and 246 deletions
+126 -1
View File
@@ -3,7 +3,7 @@ from __future__ import annotations
from datetime import datetime
from typing import Any, Literal
from pydantic import BaseModel, ConfigDict, Field, model_validator
from pydantic import BaseModel, ConfigDict, Field, SecretStr, model_validator
from govoplan_core.api.v1.schemas import DeltaDeletedItem
from govoplan_mail.backend.config import (
@@ -103,6 +103,7 @@ class MailServerProfileCreateRequest(BaseModel):
slug: str | None = Field(default=None, max_length=100)
description: str | None = None
is_active: bool = True
inherit_to_lower_scopes: bool = True
scope_type: MailProfileScope = "tenant"
scope_id: str | None = None
smtp: SmtpServerConfig
@@ -137,6 +138,7 @@ class MailServerProfileUpdateRequest(BaseModel):
slug: str | None = Field(default=None, max_length=100)
description: str | None = None
is_active: bool | None = None
inherit_to_lower_scopes: bool | None = None
smtp: SmtpServerConfig | None = None
imap: ImapServerConfig | None = None
credentials: MailServerProfileCredentialsPayload = Field(default_factory=MailServerProfileCredentialsPayload)
@@ -167,6 +169,127 @@ class MailServerProfileUpdateRequest(BaseModel):
)
class MailCredentialEnvelopeResponse(BaseModel):
id: str
binding_id: str | None = None
server_id: str | None = None
tenant_id: str | None = None
scope_type: MailProfileScope
scope_id: str | None = None
name: str
description: str | None = None
credential_kind: str
public_data: dict[str, Any] = Field(default_factory=dict)
secret_keys: list[str] = Field(default_factory=list)
secret_configured: bool = False
allowed_modules: list[str] = Field(default_factory=list)
allowed_server_refs: list[str] = Field(default_factory=list)
inherit_to_lower_scopes: bool = False
is_default: bool = False
is_active: bool = True
revision: str
created_at: datetime
updated_at: datetime
deleted_at: datetime | None = None
class MailServerEndpointResponse(BaseModel):
id: str
profile_id: str
tenant_id: str | None = None
protocol: Literal["smtp", "imap"]
name: str
config: dict[str, Any] = Field(default_factory=dict)
scope_type: MailProfileScope
scope_id: str | None = None
inherit_to_lower_scopes: bool = True
is_default: bool = False
is_active: bool = True
transport_revision: str
credentials: list[MailCredentialEnvelopeResponse] = Field(default_factory=list)
created_at: datetime
updated_at: datetime
class MailServerEndpointCreateRequest(BaseModel):
model_config = ConfigDict(extra="forbid")
protocol: Literal["smtp", "imap"]
name: str = Field(min_length=1, max_length=255)
config: dict[str, Any] = Field(default_factory=dict)
inherit_to_lower_scopes: bool | None = None
is_default: bool = False
is_active: bool = True
class MailServerEndpointUpdateRequest(BaseModel):
model_config = ConfigDict(extra="forbid")
name: str | None = Field(default=None, max_length=255)
config: dict[str, Any] | None = None
inherit_to_lower_scopes: bool | None = None
is_default: bool | None = None
is_active: bool | None = None
class MailCredentialCreateRequest(BaseModel):
model_config = ConfigDict(extra="forbid")
name: str = Field(min_length=1, max_length=255)
description: str | None = None
credential_kind: str = "username_password"
username: str | None = None
password: str | None = None
public_data: dict[str, Any] = Field(default_factory=dict)
secret_data: dict[str, Any] = Field(default_factory=dict)
inherit_to_lower_scopes: bool | None = None
allowed_modules: list[str] = Field(default_factory=lambda: ["mail"])
allowed_server_refs: list[str] = Field(default_factory=list)
is_default: bool = False
class MailCampaignCredentialCreateRequest(BaseModel):
model_config = ConfigDict(extra="forbid")
name: str = Field(min_length=1, max_length=255)
username: str = Field(min_length=1, max_length=320)
password: SecretStr
server_ids: list[str] = Field(min_length=1)
class MailCredentialBindRequest(BaseModel):
model_config = ConfigDict(extra="forbid")
credential_id: str = Field(min_length=1)
is_default: bool = False
class MailCredentialUpdateRequest(BaseModel):
model_config = ConfigDict(extra="forbid")
name: str | None = Field(default=None, max_length=255)
description: str | None = None
username: str | None = None
password: str | None = None
public_data: dict[str, Any] | None = None
secret_data: dict[str, Any] | None = None
inherit_to_lower_scopes: bool | None = None
allowed_modules: list[str] | None = None
allowed_server_refs: list[str] | None = None
is_default: bool | None = None
is_active: bool | None = None
class MailCredentialUnlinkRequest(BaseModel):
model_config = ConfigDict(extra="forbid")
retire_if_unused: bool = False
class MailCredentialListResponse(BaseModel):
credentials: list[MailCredentialEnvelopeResponse] = Field(default_factory=list)
class MailServerProfileResponse(BaseModel):
id: str
tenant_id: str | None = None
@@ -176,11 +299,13 @@ class MailServerProfileResponse(BaseModel):
slug: str
description: str | None = None
is_active: bool
inherit_to_lower_scopes: bool = True
smtp: dict[str, Any]
imap: dict[str, Any] | None = None
credentials: dict[str, Any] = Field(default_factory=dict)
smtp_password_configured: bool = False
imap_password_configured: bool = False
servers: list[MailServerEndpointResponse] = Field(default_factory=list)
created_at: datetime
updated_at: datetime