feat: times in the reader's own zone; the audit log shows exact moments (milestone 490)
- users.time_zone (0034). An account without one takes the browser's zone on its first page (POST /account/time-zone/adopt, never over a choice made by hand); the session follows the account on every request. - /account: who you are and the zone every page writes its times in, reached from your name in the sidebar. - formatting.when: 'Today 06:58', 'Yesterday 23:41', 'Tue 6 Oct 14:12', '6 Oct 2025 14:12', 24-hour, in the reader's zone; |ago's hover is the exact local moment instead of UTC; tz_label() for column headers. - Audit log: When (EDT) with exact times, one detail fact a line, on classes. - tzdata in the image, and the airgapped smoke checks a zone resolves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -117,6 +117,7 @@ def login_user(user) -> None:
|
||||
session["user_id"] = user.id
|
||||
session["user_role"] = user.role.value
|
||||
session["username"] = user.username
|
||||
session["tz"] = user.time_zone
|
||||
session["login_at"] = time.time()
|
||||
|
||||
|
||||
@@ -127,7 +128,7 @@ async def refresh_session_user() -> None:
|
||||
it began (not since the last request: the cookie is re-signed on every
|
||||
response, so the cookie's own age would let an active session live
|
||||
forever). A user who has been deleted or deactivated is logged out on
|
||||
their next request, and a role change applies at once.
|
||||
their next request, and a role change or a new time zone applies at once.
|
||||
"""
|
||||
user_id = session.get("user_id")
|
||||
if not user_id:
|
||||
@@ -146,6 +147,10 @@ async def refresh_session_user() -> None:
|
||||
return
|
||||
if session.get("user_role") != user.role.value:
|
||||
session["user_role"] = user.role.value
|
||||
# The zone times are written in (milestone 490): a change made on the
|
||||
# Account page, or the browser's zone saved for an account without one.
|
||||
if session.get("tz") != user.time_zone:
|
||||
session["tz"] = user.time_zone
|
||||
|
||||
|
||||
def logout_user() -> None:
|
||||
|
||||
Reference in New Issue
Block a user