Reduce mailcat to reporting and reorder tools
The prompts used to arrive at this change since the previous commit User said the real hans mailbox has been reordered, Roundcube filters are uploaded, the sorter and web rule interface are no longer needed, then asked to keep logs and perform the cleanup while retaining unsubscribe capability. Any special observations that may be relevant for version management for this version. Be brief. Kept daily report, Sieve policy, folder/reorder scripts, unsubscribe script/data, and log/state files. Removed live sorter, web UI, deploy helpers, old analysis artifacts, backup mirror, and obsolete tests. Verification passed; verplaats_log.json, plan.md, and roundcube.txt remain unstaged/local.
This commit is contained in:
@@ -1,51 +0,0 @@
|
||||
import base64
|
||||
import json
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from manage_routes_web import basic_auth_ok, load_routes, save_routes, validate_routes
|
||||
|
||||
|
||||
class ManageRoutesWebTests(unittest.TestCase):
|
||||
def test_validate_routes_normalizes_domains_and_mailbox(self):
|
||||
routes = validate_routes([
|
||||
{"domains": [" Example.COM ", "example.com"], "mailbox": " Diensten.Test "}
|
||||
])
|
||||
self.assertEqual(routes, [{"domains": ["example.com"], "mailbox": "Diensten.Test"}])
|
||||
|
||||
def test_validate_routes_rejects_duplicate_domain_across_routes(self):
|
||||
with self.assertRaisesRegex(ValueError, "already used"):
|
||||
validate_routes([
|
||||
{"domains": ["example.com"], "mailbox": "Diensten.Een"},
|
||||
{"domains": ["EXAMPLE.com"], "mailbox": "Diensten.Twee"},
|
||||
])
|
||||
|
||||
def test_save_routes_writes_backup_and_normalized_json(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
path = Path(tmp) / "domain_routes.json"
|
||||
path.write_text(
|
||||
json.dumps([{"domains": ["old.example"], "mailbox": "Diensten.Oud"}]) + "\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
saved = save_routes(
|
||||
[{"domains": [" New.EXAMPLE "], "mailbox": " Diensten.Nieuw "}],
|
||||
path,
|
||||
)
|
||||
|
||||
self.assertEqual(saved, [{"domains": ["new.example"], "mailbox": "Diensten.Nieuw"}])
|
||||
self.assertEqual(load_routes(path), saved)
|
||||
backup = path.with_suffix(".json.bak")
|
||||
self.assertTrue(backup.exists())
|
||||
self.assertIn("old.example", backup.read_text(encoding="utf-8"))
|
||||
|
||||
def test_basic_auth_ok_accepts_exact_credentials(self):
|
||||
token = base64.b64encode(b"mailcat:secret").decode("ascii")
|
||||
self.assertTrue(basic_auth_ok(f"Basic {token}", "mailcat", "secret"))
|
||||
self.assertFalse(basic_auth_ok(f"Basic {token}", "mailcat", "wrong"))
|
||||
self.assertFalse(basic_auth_ok(None, "mailcat", "secret"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -1,50 +0,0 @@
|
||||
import unittest
|
||||
|
||||
from mail_imap_ops import destination_from_header
|
||||
from sort_mail_daemon import mark_processed, processed_set, reset_on_uidvalidity_change
|
||||
|
||||
|
||||
class SortMailDaemonTests(unittest.TestCase):
|
||||
def test_destination_from_header_routes_ai_provider(self):
|
||||
header = (
|
||||
b"From: Claude Team <hello@claude.com>\r\n"
|
||||
b"Subject: Product update\r\n"
|
||||
b"Date: Tue, 01 Jul 2025 10:00:00 +0000\r\n"
|
||||
b"\r\n"
|
||||
)
|
||||
self.assertEqual(destination_from_header(header), "INBOX.Diensten.AI.Claude")
|
||||
|
||||
def test_destination_from_header_routes_invoice_by_quarter(self):
|
||||
header = (
|
||||
b"From: Billing <billing@example.com>\r\n"
|
||||
b"Subject: Your invoice\r\n"
|
||||
b"Date: Tue, 15 Apr 2025 10:00:00 +0000\r\n"
|
||||
b"\r\n"
|
||||
)
|
||||
self.assertEqual(destination_from_header(header), "INBOX.Financieel.Facturen.2025.Q2")
|
||||
|
||||
def test_destination_from_header_returns_none_for_unmatched(self):
|
||||
header = (
|
||||
b"From: Person <person@example.invalid>\r\n"
|
||||
b"Subject: Hello\r\n"
|
||||
b"Date: Tue, 01 Jul 2025 10:00:00 +0000\r\n"
|
||||
b"\r\n"
|
||||
)
|
||||
self.assertIsNone(destination_from_header(header))
|
||||
|
||||
def test_uidvalidity_change_resets_processed_uids(self):
|
||||
state = {"folder_state": {"INBOX": {"uidvalidity": "1", "processed_uids": ["10"]}}}
|
||||
reset_on_uidvalidity_change(state, "INBOX", "2")
|
||||
self.assertEqual(processed_set(state, "INBOX"), set())
|
||||
self.assertEqual(state["folder_state"]["INBOX"]["uidvalidity"], "2")
|
||||
|
||||
def test_mark_processed_is_idempotent(self):
|
||||
state = {"folder_state": {}}
|
||||
mark_processed(state, "INBOX", "2")
|
||||
mark_processed(state, "INBOX", "2")
|
||||
mark_processed(state, "INBOX", "1")
|
||||
self.assertEqual(state["folder_state"]["INBOX"]["processed_uids"], ["1", "2"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user