M6 hosted mailboxes (off by default); dark message mode; fixes
Hosted mailboxes (SPEC App. D), behind HOSTED_MAILBOXES (off: unchanged):
- Stalwart mail server, provisioned by `python -m app.hosted.provision`;
directory read from a Postgres view, app passwords only for mail apps
- native account per user, the worker signs in as master for the user
- raw messages of hosted mailboxes only cached, fetched back on demand
- migrations 0025 (accounts.kind, directory view), 0026 (IMAP ids bigint)
Mail:
- dark message mode switch in the reading pane (Thunderbird's algorithm)
- moves and folder creation quote the folder name ("Deleted Items"):
swipe-to-delete / Trash no longer bounce back
- thread unread counters: lock before recount, sorted lock order,
UIDVALIDITY re-import recounts, nightly repair_threads
- sidebar accounts sorted alphabetically, more space above headings
Settings: Security headings renamed; antispam accounts are explicit
(none ticked = none filtered), input widths, Activity hidden.
Plugin bundles served with Cache-Control: no-cache.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -115,7 +115,15 @@ async def test_settings_defaults_then_merge(ctx: _Ctx) -> None:
|
||||
s = (await ctx.client_a.get(f"{BASE}/settings")).json()
|
||||
assert (s["move_threshold"], s["banner_threshold"]) == (12.0, 6.0)
|
||||
assert s["network_checks"] is False # privacy default (§C.2)
|
||||
assert s["enabled_accounts"] == [] # empty = every account
|
||||
assert s["enabled_accounts"] is None # every account
|
||||
|
||||
# Every account off is stored as such (not read back as "all on"), and
|
||||
# all_accounts goes back to every account.
|
||||
s = (await ctx.client_a.patch(f"{BASE}/settings", json={"enabled_accounts": []})).json()
|
||||
assert s["enabled_accounts"] == []
|
||||
assert (await ctx.client_a.get(f"{BASE}/settings")).json()["enabled_accounts"] == []
|
||||
s = (await ctx.client_a.patch(f"{BASE}/settings", json={"all_accounts": True})).json()
|
||||
assert s["enabled_accounts"] is None
|
||||
|
||||
# PATCH merges: the field we leave out keeps its value.
|
||||
s = (await ctx.client_a.patch(f"{BASE}/settings", json={"move_threshold": 15.0})).json()
|
||||
|
||||
Reference in New Issue
Block a user