feat: weekly digest + local-time quiet hours
Weekly Digest (send_weekly_digest Celery task): - Runs every Monday 8:30 AM UTC via beat schedule - Queries all followed bills updated in the past 7 days per user - Sends low-priority ntfy push (Priority: low, Tags: newspaper,calendar) - Creates a NotificationEvent (weekly_digest type) for RSS feed visibility - Admin can trigger immediately via POST /api/admin/trigger-weekly-digest - Manual Controls panel now includes "Send Weekly Digest" button Local-time quiet hours: - Browser auto-detects IANA timezone via Intl.DateTimeFormat().resolvedOptions().timeZone - Timezone saved to notification_prefs alongside quiet_hours_start/end on Save - Dispatcher converts UTC → user's local time (zoneinfo stdlib) before hour comparison - Falls back to UTC if timezone absent or unrecognised - Quiet hours UI: 12-hour AM/PM selectors, shows detected timezone as hint - Clearing quiet hours also clears stored timezone Co-Authored-By: Jack Levy
This commit is contained in:
@@ -18,9 +18,10 @@ class NotificationSettingsResponse(BaseModel):
|
||||
# Digest
|
||||
digest_enabled: bool = False
|
||||
digest_frequency: str = "daily" # daily | weekly
|
||||
# Quiet hours (UTC hour integers 0-23, None = disabled)
|
||||
# Quiet hours — stored as local-time hour integers (0-23); timezone is IANA name
|
||||
quiet_hours_start: Optional[int] = None
|
||||
quiet_hours_end: Optional[int] = None
|
||||
timezone: Optional[str] = None # IANA name, e.g. "America/New_York"
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
@@ -37,6 +38,7 @@ class NotificationSettingsUpdate(BaseModel):
|
||||
digest_frequency: Optional[str] = None
|
||||
quiet_hours_start: Optional[int] = None
|
||||
quiet_hours_end: Optional[int] = None
|
||||
timezone: Optional[str] = None # IANA name sent by the browser on save
|
||||
|
||||
|
||||
class NotificationEventSchema(BaseModel):
|
||||
|
||||
Reference in New Issue
Block a user