fix(account): one form and one Save for your account; the same for an account's page in Users
CI / lint (push) Successful in 2s
CI / integration (push) Failing after 1m8s
CI / unit (push) Successful in 1m36s
CI / publish (push) Skipped

Operator review of the Account page: two sections with two different
save buttons, one stuck to the next card and one beside a squeezed hint.
- Account: time zone and Email are one form; POST /account/ saves both,
  nothing unless all of it is valid. /account/email is gone.
- Users › account: Name and Email are one form; the rename route also
  saves the email switches. /settings/users/<id>/email is gone.
- The Email section is a plain section now (email_section); its hint sits
  under the switches, names the zone as the picker does, and links
  Notifications only for an admin.
- apply_email_form leaves a switch the form doesn't carry as it is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 16:05:41 -04:00
co-authored by Claude Opus 5.5
parent 31e32c173c
commit beae8a33f3
8 changed files with 102 additions and 106 deletions
+1 -1
View File
@@ -73,7 +73,7 @@ def test_the_browser_zone_is_adopted_once_and_the_account_page_changes_it(app):
assert out["adopt"] == {"adopted": True} and out["after_adopt"] == "America/New_York"
assert out["again"] == {"adopted": False}
page = out["page"]
assert "times show in <strong>America/New_York</strong> (E" in page # EDT or EST
assert "times show in <strong>New York</strong> (E" in page # EDT or EST
assert '<option value="America/New_York" selected>New York</option>' in page
assert "/account/time-zone/adopt" not in page # nothing left to adopt
assert out["save"] == (302, "/account/") and out["after_save"] == "Europe/London"
+13 -11
View File
@@ -174,25 +174,27 @@ def test_an_account_sets_its_own_address_and_switches_and_an_admin_can_too(app):
async def _go():
viewer, vid = await _client(app, role="viewer")
page = await (await viewer.get("/account/")).get_data(as_text=True)
assert 'action="/account/email"' in page and "As for viewers (on)" in page
assert page.count("<form") == 1 and 'name="notify_alerts"' in page and "As for viewers (on)" in page
resp = await viewer.post("/account/email", headers=CSRF, form={
"email": "nope@oidc", "notify_alerts": "off", "notify_report": ""})
mine = {"time_zone": "Europe/Paris", "notify_alerts": "off", "notify_report": ""}
resp = await viewer.post("/account/", headers=CSRF, form=mine | {"email": "nope@oidc"})
assert resp.status_code == 400 and "mail can reach" in await resp.get_data(as_text=True)
assert (await _user(app, vid)).time_zone is None # nothing saved from a bad form
address = f"v-{vid[:8]}@example.com"
assert (await viewer.post("/account/email", headers=CSRF, form={
"email": address, "notify_alerts": "off", "notify_report": ""})).status_code == 302
assert (await viewer.post("/account/", headers=CSRF, form=mine | {"email": address})).status_code == 302
me = await _user(app, vid)
assert (me.email, me.notify_alerts, me.notify_report) == (address, False, None)
assert [a for a, _ in await _audits(app, vid)] == ["account.email"]
assert (me.email, me.notify_alerts, me.notify_report, me.time_zone) == (address, False, None, "Europe/Paris")
assert [a for a, _ in await _audits(app, vid)] == ["account.time_zone", "account.email"]
admin, aid = await _client(app)
resp = await admin.post(f"/settings/users/{vid}/email", headers=CSRF,
form={"email": "ignored@example.com", "notify_alerts": "", "notify_report": "off"})
page = await (await admin.get(f"/settings/users/{vid}")).get_data(as_text=True)
assert 'name="notify_report"' in page and "own zone (Paris)" in page
resp = await admin.post(f"/settings/users/{vid}", headers=CSRF, form={
"username": me.username, "email": address, "notify_alerts": "", "notify_report": "off"})
assert resp.status_code == 302
me = await _user(app, vid)
assert (me.email, me.notify_alerts, me.notify_report) == (address, None, False) # address kept
assert [a for a, _ in await _audits(app, aid)] == ["user.email_settings"]
assert (me.email, me.notify_alerts, me.notify_report) == (address, None, False)
assert [a for a, _ in await _audits(app, aid)] == ["user.email_settings"] # not renamed
page = await (await admin.get("/settings/notifications/")).get_data(as_text=True)
assert "Who gets email" in page and 'name="notify.alerts.viewer"' in page and "Also send to" in page