feat(mail): map standard IMAP folders per profile
This commit is contained in:
@@ -8,6 +8,7 @@ from govoplan_mail.backend.config import ImapConfig
|
||||
from govoplan_mail.backend.sending.imap import (
|
||||
ImapAppendError,
|
||||
ImapConfigurationError,
|
||||
_detect_standard_folder_mappings,
|
||||
_detect_sent_folder,
|
||||
_extract_mailbox_name,
|
||||
_fetch_message_by_uid,
|
||||
@@ -18,6 +19,7 @@ from govoplan_mail.backend.sending.imap import (
|
||||
_select_readonly,
|
||||
_sequence_set,
|
||||
append_message_to_sent,
|
||||
list_imap_folders,
|
||||
list_imap_messages,
|
||||
list_imap_uids_since,
|
||||
)
|
||||
@@ -79,6 +81,45 @@ class ImapFolderParserTests(unittest.TestCase):
|
||||
"Gesendet",
|
||||
)
|
||||
|
||||
def test_detects_all_standard_folder_roles_by_flag_then_name(self):
|
||||
self.assertEqual(
|
||||
{
|
||||
"inbox": "INBOX",
|
||||
"sent": "Gesendete Elemente",
|
||||
"drafts": "Entwürfe",
|
||||
"trash": "Deleted",
|
||||
"archive": "All Mail",
|
||||
"junk": "Spam",
|
||||
},
|
||||
_detect_standard_folder_mappings(
|
||||
[
|
||||
("INBOX", set()),
|
||||
("Gesendete Elemente", set()),
|
||||
("Entwürfe", set()),
|
||||
("Deleted", {"\\trash"}),
|
||||
("All Mail", {"\\all"}),
|
||||
("Spam", {"\\junk"}),
|
||||
]
|
||||
),
|
||||
)
|
||||
|
||||
def test_mock_folder_listing_exposes_detected_standard_mappings(self):
|
||||
result = list_imap_folders(
|
||||
imap_config=ImapConfig(host="mock.imap.local"), include_status=False
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
{
|
||||
"inbox": "INBOX",
|
||||
"sent": "Sent",
|
||||
"drafts": "Drafts",
|
||||
"trash": "Trash",
|
||||
"archive": "Archive",
|
||||
},
|
||||
result.detected_folder_mappings,
|
||||
)
|
||||
self.assertEqual("Sent", result.detected_sent_folder)
|
||||
|
||||
|
||||
class ImapMessagePaginationTests(unittest.TestCase):
|
||||
def test_mock_message_cursor_preserves_order_and_resets_when_stale(self):
|
||||
|
||||
@@ -290,6 +290,51 @@ class MailProfileTransportHelperTests(unittest.TestCase):
|
||||
self.assertEqual(audit.call_args.kwargs["details"]["protocol"], "imap")
|
||||
self.assertNotIn("imap-secret", repr(audit.call_args.kwargs))
|
||||
|
||||
def test_apply_transport_update_persists_standard_folder_mappings(self):
|
||||
profile = SimpleNamespace(
|
||||
id="profile-folders",
|
||||
tenant_id="tenant-1",
|
||||
scope_type="tenant",
|
||||
scope_id="tenant-1",
|
||||
smtp_config={"host": "smtp.example.org"},
|
||||
smtp_username=None,
|
||||
smtp_password_encrypted=None,
|
||||
smtp_transport_revision="smtp-before",
|
||||
imap_config={"host": "imap.example.org", "sent_folder": "Legacy Sent"},
|
||||
imap_username=None,
|
||||
imap_password_encrypted=None,
|
||||
imap_transport_revision="imap-before",
|
||||
)
|
||||
session = SimpleNamespace(flush=lambda: None)
|
||||
|
||||
with patch("govoplan_mail.backend.mail_profiles.clear_mailbox_index"):
|
||||
_apply_profile_transport_update(
|
||||
session, # type: ignore[arg-type]
|
||||
profile,
|
||||
user_id="user-1",
|
||||
api_key_id=None,
|
||||
smtp=None,
|
||||
imap=ImapConfig(
|
||||
host="imap.example.org",
|
||||
folder_mappings={
|
||||
"inbox": "INBOX",
|
||||
"sent": "Sent Items",
|
||||
"drafts": "Drafts",
|
||||
},
|
||||
),
|
||||
clear_imap=False,
|
||||
)
|
||||
|
||||
self.assertEqual(profile.imap_config["sent_folder"], "Sent Items")
|
||||
self.assertEqual(
|
||||
profile.imap_config["folder_mappings"],
|
||||
{
|
||||
"inbox": "INBOX",
|
||||
"sent": "Sent Items",
|
||||
"drafts": "Drafts",
|
||||
},
|
||||
)
|
||||
|
||||
def test_imap_password_replacement_clears_cache_without_rotating_identity_revision(self):
|
||||
profile = SimpleNamespace(
|
||||
id="profile-1",
|
||||
|
||||
Reference in New Issue
Block a user