feat(anhaenge): attachment_count im Termin-JSON

Die Terminliste traegt nur die Anzahl, nicht die Anhaenge selbst. Der
Merge-Read laeuft pro Termin durch eine Schleife -- eine Lazy-Relationship
waere dort eine Abfrage je Termin ueber eine ganze Monatsansicht, und ein
wiederkehrender Termin wuerde dieselbe Liste an jeder Instanz wiederholen.
Stattdessen je Kalender eine gruppierte Abfrage; die Liste holen die
Clients beim Oeffnen der Detailansicht.

mask_busy_event setzt die Zahl ausdruecklich auf 0: dass ein als
"Beschaeftigt" maskierter Termin drei Dateien haette, ist auch eine
Information.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-09-14 10:11:30 +02:00
co-authored by Claude Opus 5
parent 0e8a1a6a3d
commit b885e731ee
5 changed files with 88 additions and 8 deletions
+12 -2
View File
@@ -9,6 +9,7 @@ from pydantic import BaseModel
from sqlalchemy.orm import Session
from sqlalchemy import or_
import attachments_store
import caldav_client
import models
import permissions
@@ -400,6 +401,9 @@ def get_events(
)
.all()
)
# One grouped query for the whole calendar: a per-event lookup here
# would be N+1 across a month view.
att_counts = attachments_store.counts_for_events(db, [e.id for e in local_events])
for ev in local_events:
creator = resolve_creator(ev, name_cache=name_cache)
# A private event belonging to someone else (shared calendar or group
@@ -413,9 +417,15 @@ def get_events(
if foreign_private and visibility == "hidden":
continue
if ev.rrule:
built = expand_recurring_local(ev, local_cal, start_dt, end_dt, creator=creator)
built = expand_recurring_local(
ev, local_cal, start_dt, end_dt, creator=creator,
attachment_count=att_counts.get(ev.id, 0),
)
else:
built = [build_local_event_dict(ev, local_cal, rrule=None, creator=creator)]
built = [build_local_event_dict(
ev, local_cal, rrule=None, creator=creator,
attachment_count=att_counts.get(ev.id, 0),
)]
for b in built:
if shared_owner_name:
b["calendar_name"] = shared_owner_name
+3 -2
View File
@@ -398,6 +398,7 @@ def combined_events(
)
.all()
)
att_counts = attachments_store.counts_for_events(db, [e.id for e in events])
for ev in events:
creator_owner_id = ev.creator_id or owner_id
# Private filtering for events that belong to someone else.
@@ -412,9 +413,9 @@ def combined_events(
creator = {"id": None, "display_name": f"{ev.creator_name_external} (importiert)"}
if ev.rrule:
built = expand_recurring_local(ev, cal, start_dt, end_dt, creator=creator, owner=owner, is_group_event=is_group, read_only=read_only)
built = expand_recurring_local(ev, cal, start_dt, end_dt, creator=creator, owner=owner, is_group_event=is_group, read_only=read_only, attachment_count=att_counts.get(ev.id, 0))
else:
built = [build_local_event_dict(ev, cal, rrule=None, creator=creator, owner=owner, is_group_event=is_group, read_only=read_only)]
built = [build_local_event_dict(ev, cal, rrule=None, creator=creator, owner=owner, is_group_event=is_group, read_only=read_only, attachment_count=att_counts.get(ev.id, 0))]
for b in built:
if ev.is_private and creator_owner_id != current_user.id and visibility_for(creator_owner_id) == "busy":
+5 -1
View File
@@ -110,7 +110,11 @@ def _cal_dict(cal: models.LocalCalendar, *, owned: bool = True,
def _event_dict(ev: models.LocalEvent, cal: models.LocalCalendar, db: Session) -> dict:
return build_local_event_dict(ev, cal, creator=resolve_creator(ev))
counts = attachments_store.counts_for_events(db, [ev.id])
return build_local_event_dict(
ev, cal, creator=resolve_creator(ev),
attachment_count=counts.get(ev.id, 0),
)
# ── Calendar CRUD ─────────────────────────────────────────