Workers, Webhooks, Mail trigger and Claude accounts now render like the Cron page: a collapsed header row (icon · name · chips · toggle) that expands into the editable fields, a Save button only while dirty, and delete behind a confirm at the bottom of the open body. Webhooks, Mail trigger and Accounts each get a page of their own (/settings/<name>) instead of an anchor on the Settings page; the old #anchors forward there. - technical/ItemCard.tsx: the shared card + the field/button/list pieces, Cron refactored onto it (no visual change) - mail trigger: an address can be switched off without being removed — the store keeps a second `disabled` list; the mail service still reads only `emails`, so nothing changes on its side (API + orval types regenerated) - workers: the routing switch is the header toggle; name and account are editable in the body - loginHref / dashboard links point at /settings/accounts Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
46 lines
1.7 KiB
Python
46 lines
1.7 KiB
Python
"""MailTriggerStore — the enabled/disabled sender lists (mail_trigger.py).
|
|
Run with ``python3 -m unittest test_mail_trigger`` from ``backend/`` (stdlib only)."""
|
|
import json
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
from mail_trigger import MailTriggerStore, valid_emails
|
|
|
|
|
|
class ValidEmails(unittest.TestCase):
|
|
def test_normalizes_and_dedupes(self):
|
|
self.assertEqual(valid_emails([" A@x.io ", "a@x.io", "", "b@y.io"]), ["a@x.io", "b@y.io"])
|
|
with self.assertRaises(ValueError):
|
|
valid_emails(["nope"])
|
|
|
|
|
|
class Store(unittest.TestCase):
|
|
def setUp(self):
|
|
self.tmp = tempfile.TemporaryDirectory()
|
|
self.path = Path(self.tmp.name) / "senders.json"
|
|
|
|
def tearDown(self):
|
|
self.tmp.cleanup()
|
|
|
|
def test_set_and_reload_keeps_disabled(self):
|
|
store = MailTriggerStore(str(self.path))
|
|
out = store.set_emails(["a@x.io", "b@x.io"], ["b@x.io", "c@x.io"])
|
|
# an address in both lists is enabled — `emails` wins
|
|
self.assertEqual(out, {"emails": ["a@x.io", "b@x.io"], "disabled": ["c@x.io"]})
|
|
# what the mail service reads: only the enabled ones
|
|
self.assertEqual(json.loads(self.path.read_text())["emails"], ["a@x.io", "b@x.io"])
|
|
again = MailTriggerStore(str(self.path))
|
|
self.assertEqual(again.emails(), ["a@x.io", "b@x.io"])
|
|
self.assertEqual(again.disabled(), ["c@x.io"])
|
|
|
|
def test_legacy_file_without_disabled(self):
|
|
self.path.write_text(json.dumps({"emails": ["a@x.io"]}))
|
|
store = MailTriggerStore(str(self.path))
|
|
self.assertEqual(store.emails(), ["a@x.io"])
|
|
self.assertEqual(store.disabled(), [])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|