Add birthday calendar backend support
Birthday calendars are ordinary local calendars flagged is_birthday, so they
flow to all clients via the merge read and inherit sharing/colors/reminders.
- models: LocalCalendar.is_birthday + birthday_notify_days_before;
LocalEvent.external_uid (Contacts dedup) + birth_year
- build_local_event_dict: server-computed display_title "Name (age)" per
occurrence, is_birthday flag for the client cake icon, and a reminder injected
from birthday_notify_days_before so mobile schedulers fire it
- groups combined view keeps the birthday display_title instead of overwriting it
- local_router: calendar flags + event fields on create/update, plus
GET /calendars/{id}/birthdays for importer reconcile by external_uid
- additive SQLite migrations
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -132,6 +132,25 @@ def build_local_event_dict(
|
||||
"private": bool(ev.is_private),
|
||||
"reminders": [int(x) for x in (ev.reminders or "").split(",") if x.strip().lstrip("-").isdigit()],
|
||||
}
|
||||
# Birthday calendars: the server owns the presentation. It flags the event so
|
||||
# clients can show a cake icon, appends the age computed for THIS occurrence
|
||||
# (so it stays correct as years pass), and — when the calendar defines a
|
||||
# "notify N days before" — injects a reminder so the mobile schedulers fire
|
||||
# it. Web has no notification delivery, so the reminder is display-only there.
|
||||
if getattr(cal, "is_birthday", False):
|
||||
d["is_birthday"] = True
|
||||
display = ev.title
|
||||
if ev.birth_year:
|
||||
try:
|
||||
occ_year = int(str(d["start"])[:4])
|
||||
age = occ_year - int(ev.birth_year)
|
||||
if age >= 0:
|
||||
display = f"{ev.title} ({age})"
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
d["display_title"] = display
|
||||
if not d["reminders"] and cal.birthday_notify_days_before is not None:
|
||||
d["reminders"] = [int(cal.birthday_notify_days_before) * 1440]
|
||||
if owner is not None:
|
||||
d["owner"] = owner
|
||||
if is_group_event:
|
||||
|
||||
Reference in New Issue
Block a user