from collections import OrderedDict, Counter
from onegov.activity import Activity, Attendee, Occasion, OccasionCollection
from onegov.user import User
from typing import NamedTuple, TYPE_CHECKING
if TYPE_CHECKING:
from onegov.activity.models import Period, PeriodMeta
from sqlalchemy.orm import Query, Session
from typing import TypedDict, Self
from uuid import UUID
[docs]
class OccasionAttendee(NamedTuple):
[docs]
class OccasionAttendeeCollection(OccasionCollection):
def __init__(
self,
session: 'Session',
period: 'Period | PeriodMeta',
activity: Activity,
username: str | None = None
) -> None:
super().__init__(session)
[docs]
self.username = username
[docs]
self.activity = activity
@property
[docs]
def period_id(self) -> 'UUID':
return self.period.id
@property
[docs]
def activity_name(self) -> str:
return self.activity.name
[docs]
def for_period(self, period: 'Period | PeriodMeta') -> 'Self':
return self.__class__(
self.session, period, self.activity, self.username)
[docs]
def query(self) -> 'Query[Occasion]':
q = super().query()
q = q.join(Occasion.activity)
# this will implicitly filter out all occasions without attendees:
q = q.join(Occasion.accepted)
q = q.filter(Occasion.period_id == self.period_id)
q = q.filter(Occasion.activity_id == self.activity.id)
if self.username:
q = q.filter(Activity.username == self.username)
return q.order_by(Activity.title, Occasion.order, Occasion.id)
[docs]
def occasions(self) -> dict[Occasion, list[OccasionAttendee]]:
occasions = OrderedDict()
attendees = {
attendee.id: attendee for attendee in self.session.query(Attendee)
}
contacts: dict[str, ContactInfo] = {
u.username: {
'emergency': u.data and u.data.get('emergency'),
'email': u.data and u.data.get('email') or u.username,
'place': u.data and u.data.get('place'),
}
for u in self.session.query(
User.username, User.data
)
}
for o in self.query():
group_codes = Counter(b.group_code for b in o.accepted)
occasions[o] = [
OccasionAttendee(
attendee=attendees[b.attendee_id],
info=contacts[b.username],
group_code=(
group_codes[b.group_code] > 1 and b.group_code or None
)
) for b in sorted(
o.accepted,
key=lambda b: attendees[b.attendee_id].name
)
]
return occasions