Release v0.1.2
This commit is contained in:
@@ -25,7 +25,7 @@ from govoplan_core.db.session import get_session
|
||||
from govoplan_mail.backend.mail_profiles import (
|
||||
MailProfileError,
|
||||
create_mail_server_profile,
|
||||
effective_mail_profile_policy,
|
||||
effective_mail_profile_policy_for_scope,
|
||||
get_mail_profile_policy,
|
||||
get_mail_server_profile,
|
||||
imap_config_from_profile,
|
||||
@@ -36,6 +36,7 @@ from govoplan_mail.backend.mail_profiles import (
|
||||
smtp_config_from_profile,
|
||||
update_mail_server_profile,
|
||||
)
|
||||
from govoplan_mail.backend.config import ImapConfig, SmtpConfig
|
||||
from govoplan_mail.backend.sending.imap import ImapAppendError, ImapConfigurationError, get_imap_message, list_imap_folders, list_imap_messages, test_imap_login
|
||||
from govoplan_mail.backend.sending.smtp import test_smtp_login
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -172,7 +173,7 @@ def create_profile(
|
||||
session: Session = Depends(get_session),
|
||||
):
|
||||
_require_profile_write_scope(principal, payload.scope_type)
|
||||
if payload.smtp.password or (payload.imap and payload.imap.password):
|
||||
if payload.credentials_supplied():
|
||||
_require_profile_credentials_scope(principal, payload.scope_type)
|
||||
try:
|
||||
profile = create_mail_server_profile(
|
||||
@@ -182,8 +183,8 @@ def create_profile(
|
||||
name=payload.name,
|
||||
slug=payload.slug,
|
||||
description=payload.description,
|
||||
smtp=payload.smtp,
|
||||
imap=payload.imap,
|
||||
smtp=payload.smtp_config(),
|
||||
imap=payload.imap_config(),
|
||||
is_active=payload.is_active,
|
||||
scope_type=payload.scope_type,
|
||||
scope_id=payload.scope_id,
|
||||
@@ -219,8 +220,18 @@ def update_profile(
|
||||
try:
|
||||
profile = get_mail_server_profile(session, tenant_id=principal.tenant_id, profile_id=profile_id)
|
||||
_require_profile_write_scope(principal, profile.scope_type or "tenant")
|
||||
if (payload.smtp and "password" in payload.smtp.model_fields_set) or (payload.imap and "password" in payload.imap.model_fields_set) or payload.clear_imap:
|
||||
if payload.credentials_supplied() or payload.clear_imap:
|
||||
_require_profile_credentials_scope(principal, profile.scope_type or "tenant")
|
||||
smtp_config = payload.smtp_config()
|
||||
if payload.smtp is None and "smtp" in payload.credentials.model_fields_set:
|
||||
smtp_data = dict(profile.smtp_config or {})
|
||||
smtp_data.update(payload.credentials.smtp.model_dump(mode="json", exclude_unset=True))
|
||||
smtp_config = SmtpConfig.model_validate(smtp_data)
|
||||
imap_config = payload.imap_config()
|
||||
if payload.imap is None and "imap" in payload.credentials.model_fields_set and profile.imap_config:
|
||||
imap_data = dict(profile.imap_config or {})
|
||||
imap_data.update(payload.credentials.imap.model_dump(mode="json", exclude_unset=True))
|
||||
imap_config = ImapConfig.model_validate(imap_data)
|
||||
update_mail_server_profile(
|
||||
session,
|
||||
profile,
|
||||
@@ -230,8 +241,8 @@ def update_profile(
|
||||
slug=payload.slug,
|
||||
description=payload.description if "description" in payload.model_fields_set else None,
|
||||
is_active=payload.is_active,
|
||||
smtp=payload.smtp,
|
||||
imap=payload.imap,
|
||||
smtp=smtp_config,
|
||||
imap=imap_config,
|
||||
clear_imap=payload.clear_imap,
|
||||
)
|
||||
session.commit()
|
||||
@@ -273,16 +284,15 @@ def read_mail_profile_policy(
|
||||
_require_policy_read_scope(principal, scope_type)
|
||||
try:
|
||||
policy = get_mail_profile_policy(session, tenant_id=principal.tenant_id, scope_type=scope_type, scope_id=scope_id)
|
||||
effective = None
|
||||
effective_sources = []
|
||||
if campaign_id:
|
||||
effective_policy = effective_mail_profile_policy(session, tenant_id=principal.tenant_id, campaign_id=campaign_id)
|
||||
effective = effective_policy.as_dict()
|
||||
effective_sources = effective_policy.source_policies
|
||||
elif scope_type == "campaign" and scope_id:
|
||||
effective_policy = effective_mail_profile_policy(session, tenant_id=principal.tenant_id, campaign_id=scope_id)
|
||||
effective = effective_policy.as_dict()
|
||||
effective_sources = effective_policy.source_policies
|
||||
effective_policy = effective_mail_profile_policy_for_scope(
|
||||
session,
|
||||
tenant_id=principal.tenant_id,
|
||||
scope_type=scope_type,
|
||||
scope_id=scope_id,
|
||||
campaign_id=campaign_id,
|
||||
)
|
||||
effective = effective_policy.as_dict()
|
||||
effective_sources = effective_policy.source_policies
|
||||
parent_policy = parent_mail_profile_policy(session, tenant_id=principal.tenant_id, scope_type=scope_type, scope_id=scope_id) if scope_type != "system" else None
|
||||
parent = parent_policy.as_dict() if parent_policy else None
|
||||
parent_sources = parent_policy.source_policies if parent_policy else []
|
||||
@@ -310,12 +320,14 @@ def write_mail_profile_policy(
|
||||
policy=payload.policy.model_dump(mode="json"),
|
||||
)
|
||||
session.commit()
|
||||
effective = None
|
||||
effective_sources = []
|
||||
if scope_type == "campaign" and scope_id:
|
||||
effective_policy = effective_mail_profile_policy(session, tenant_id=principal.tenant_id, campaign_id=scope_id)
|
||||
effective = effective_policy.as_dict()
|
||||
effective_sources = effective_policy.source_policies
|
||||
effective_policy = effective_mail_profile_policy_for_scope(
|
||||
session,
|
||||
tenant_id=principal.tenant_id,
|
||||
scope_type=scope_type,
|
||||
scope_id=scope_id,
|
||||
)
|
||||
effective = effective_policy.as_dict()
|
||||
effective_sources = effective_policy.source_policies
|
||||
parent_policy = parent_mail_profile_policy(session, tenant_id=principal.tenant_id, scope_type=scope_type, scope_id=scope_id) if scope_type != "system" else None
|
||||
parent = parent_policy.as_dict() if parent_policy else None
|
||||
parent_sources = parent_policy.source_policies if parent_policy else []
|
||||
@@ -379,7 +391,7 @@ def list_profile_imap_folders(
|
||||
if imap is None:
|
||||
raise MailProfileError("Mail-server profile has no IMAP configuration")
|
||||
result = list_imap_folders(imap_config=imap)
|
||||
folders = [MailImapFolderResponse(name=item.name, flags=item.flags) for item in result.folders]
|
||||
folders = [MailImapFolderResponse(name=item.name, flags=item.flags, message_count=item.message_count, unseen_count=item.unseen_count) for item in result.folders]
|
||||
return MailImapFolderListResponse(ok=True, host=result.host, port=result.port, security=result.security, message=f"Found {len(folders)} IMAP folder(s).", folders=folders, detected_sent_folder=result.detected_sent_folder)
|
||||
except MailProfileError as exc:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
|
||||
@@ -397,7 +409,7 @@ def list_profile_mailbox_folders(
|
||||
try:
|
||||
imap = _imap_config_for_profile(session, tenant_id=principal.tenant_id, profile_id=profile_id)
|
||||
result = list_imap_folders(imap_config=imap)
|
||||
folders = [MailImapFolderResponse(name=item.name, flags=item.flags) for item in result.folders]
|
||||
folders = [MailImapFolderResponse(name=item.name, flags=item.flags, message_count=item.message_count, unseen_count=item.unseen_count) for item in result.folders]
|
||||
return MailImapFolderListResponse(ok=True, host=result.host, port=result.port, security=result.security, message=f"Found {len(folders)} IMAP folder(s).", folders=folders, detected_sent_folder=result.detected_sent_folder)
|
||||
except MailProfileError as exc:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
|
||||
@@ -412,13 +424,14 @@ def list_profile_mailbox_messages(
|
||||
profile_id: str,
|
||||
folder: str = Query(default="INBOX", min_length=1, max_length=255),
|
||||
limit: int = Query(default=50, ge=1, le=100),
|
||||
offset: int = Query(default=0, ge=0, le=100000),
|
||||
principal: ApiPrincipal = Depends(get_api_principal),
|
||||
session: Session = Depends(get_session),
|
||||
):
|
||||
_require_mailbox_read_scope(principal)
|
||||
try:
|
||||
imap = _imap_config_for_profile(session, tenant_id=principal.tenant_id, profile_id=profile_id)
|
||||
result = list_imap_messages(imap_config=imap, folder=folder, limit=limit)
|
||||
result = list_imap_messages(imap_config=imap, folder=folder, limit=limit, offset=offset)
|
||||
return MailMailboxMessageListResponse(
|
||||
profile_id=profile_id,
|
||||
folder=result.folder,
|
||||
@@ -426,6 +439,8 @@ def list_profile_mailbox_messages(
|
||||
port=result.port,
|
||||
security=result.security,
|
||||
total_count=result.total_count,
|
||||
offset=result.offset,
|
||||
limit=result.limit,
|
||||
messages=[_mailbox_summary_response(message) for message in result.messages],
|
||||
)
|
||||
except MailProfileError as exc:
|
||||
@@ -551,7 +566,7 @@ def list_imap_folder_settings(
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Testing raw credentials requires mail_servers:manage_credentials")
|
||||
try:
|
||||
result = list_imap_folders(imap_config=payload)
|
||||
folders = [MailImapFolderResponse(name=item.name, flags=item.flags) for item in result.folders]
|
||||
folders = [MailImapFolderResponse(name=item.name, flags=item.flags, message_count=item.message_count, unseen_count=item.unseen_count) for item in result.folders]
|
||||
return MailImapFolderListResponse(
|
||||
ok=True,
|
||||
host=result.host,
|
||||
|
||||
Reference in New Issue
Block a user