from pydantic import BaseModel, model_validator, Field, HttpUrl from enum import StrEnum from typing import Annotated, Self from fiber_package.util import GroupRef from datetime import datetime # may be moved to another file if used elsewhere ''' The category is only used to place the communication correctly in the weekly mailing and the board-website, it is not visible (or relevant) to readers ''' class CommunicationCategory(StrEnum): announcement = "announcement" news = "news" activity = "activity" ''' A "communication" is a piece of communication/promotion to be shared with members, which may appear on the website and in the weekly mailing. ''' class CommunicationModel(BaseModel): category: CommunicationCategory name_en: str name_nl: str subtitle_en: str subtitle_nl: str # subtitles currently (2026) appear only in the table of contents in the # weekly mailing; they are meant to be a short catchy flavour text description_en: str description_nl: str image: HttpUrl | None # often, a poster comes associated with a communication (in particular if # it's an activity). In that case, the poster is uploaded to the cloud and # the share link is attached to the communication # TODO: potentially rethink the way images are attached to communications visibility: bool # should this communication be shown to members at all? Useful for # temporarily hiding a communication only_members: bool # is this communication only visible to members? This refers to visibility # on the website, i.e. is this only visible to visitors who are logged in? archived: bool # an archived communication cannot be edited, only viewed for future # reference class ActivityModel(CommunicationModel): category: Annotated[ CommunicationCategory, Field(pattern=CommunicationCategory.activity) ] signuplist: GroupRef = GroupRef("signuplist", None) # TODO: validate that a signuplist can only be attached if category is # activity? Or should this not be validated? start_time: datetime end_time: datetime @model_validator(mode='after') def check_end_after_start(self) -> Self: if self.end_time < self.start_time: raise ValueError("End time cannot be earlier than start time") return self