From 8c9d6bc6eff413476fa75bf5b6d995a72b028fff Mon Sep 17 00:00:00 2001 From: Tiago Scholten Date: Sun, 11 Oct 2026 22:10:58 +0200 Subject: [PATCH 01/23] Started working on events/activities based on Florians work --- src/fiber_package/events/activity.py | 25 ++++++++++++ src/fiber_package/events/communication.py | 46 +++++++++++++++++++++++ src/fiber_package/events/enums.py | 10 +++++ 3 files changed, 81 insertions(+) create mode 100644 src/fiber_package/events/activity.py create mode 100644 src/fiber_package/events/communication.py create mode 100644 src/fiber_package/events/enums.py diff --git a/src/fiber_package/events/activity.py b/src/fiber_package/events/activity.py new file mode 100644 index 0000000..bf63afa --- /dev/null +++ b/src/fiber_package/events/activity.py @@ -0,0 +1,25 @@ +from typing import Annotated, Self + +from .communication import CommunicationModel + +class ActivityModel(CommunicationModel): + category: Annotated[ + CommunicationCategory, + Field(pattern=CommunicationCategory.activity) + ] + + start_time: datetime + end_time: datetime + + + #signuplist: GroupRef | None = None + # TODO: implement signup list (huge modular system) + + # TODO: see Felt 'activiteiten' DB schema. Things like: + # costs, payment method, email, target group, maximal attendees .... + + @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 diff --git a/src/fiber_package/events/communication.py b/src/fiber_package/events/communication.py new file mode 100644 index 0000000..257b632 --- /dev/null +++ b/src/fiber_package/events/communication.py @@ -0,0 +1,46 @@ +from pydantic import BaseModel, model_validator, Field, HttpUrl +from enum import StrEnum +from datetime import datetime + +from fiber_package.base import FiberBaseModel + +from .enums import CommunicationCategory + +''' +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(FiberBaseModel): + category: CommunicationCategory + + name_en: str + name_nl: str + + association_tags = [] + # list of associations this communication belongs to + + 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 = 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 \ No newline at end of file diff --git a/src/fiber_package/events/enums.py b/src/fiber_package/events/enums.py new file mode 100644 index 0000000..84682d2 --- /dev/null +++ b/src/fiber_package/events/enums.py @@ -0,0 +1,10 @@ +from enum import StrEnum + +''' +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" From 337d27425eedbab6b6821ec812dfabb6a4514d54 Mon Sep 17 00:00:00 2001 From: Tiago Scholten Date: Mon, 12 Oct 2026 17:08:05 +0200 Subject: [PATCH 02/23] added payment info to activities --- src/fiber_package/events/activity.py | 6 +++++- src/fiber_package/events/submodels.py | 10 ++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 src/fiber_package/events/submodels.py diff --git a/src/fiber_package/events/activity.py b/src/fiber_package/events/activity.py index bf63afa..0ee85dc 100644 --- a/src/fiber_package/events/activity.py +++ b/src/fiber_package/events/activity.py @@ -1,6 +1,8 @@ from typing import Annotated, Self from .communication import CommunicationModel +from .submodels import ActivityPaymentInfo + class ActivityModel(CommunicationModel): category: Annotated[ @@ -11,12 +13,14 @@ class ActivityModel(CommunicationModel): start_time: datetime end_time: datetime + payment_info: ActivityPaymentInfo | None = None + #signuplist: GroupRef | None = None # TODO: implement signup list (huge modular system) # TODO: see Felt 'activiteiten' DB schema. Things like: - # costs, payment method, email, target group, maximal attendees .... + # email, target group, maximal attendees .... @model_validator(mode='after') def check_end_after_start(self) -> Self: diff --git a/src/fiber_package/events/submodels.py b/src/fiber_package/events/submodels.py new file mode 100644 index 0000000..e933c02 --- /dev/null +++ b/src/fiber_package/events/submodels.py @@ -0,0 +1,10 @@ +from decimal import Decimal +from typing import Annotated + +from pydantic import BaseModel, Field + +class ActivityPaymentInfo(BaseModel): + contribution: Annotated[Decimal, Field(decimal_places=2, ge=0)] + nnv_contribution: Annotated[Decimal | None, Field(None, decimal_places=2, ge=0)] = None + + From 4c62bc4de8aa18dab34c8f525d774f67a40f8746 Mon Sep 17 00:00:00 2001 From: Tiago Scholten Date: Tue, 13 Oct 2026 13:37:57 +0200 Subject: [PATCH 03/23] started working on activity system --- src/fiber_package/events/activity.py | 3 ++ src/fiber_package/events/notes.txt | 48 ++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 src/fiber_package/events/notes.txt diff --git a/src/fiber_package/events/activity.py b/src/fiber_package/events/activity.py index 0ee85dc..969e745 100644 --- a/src/fiber_package/events/activity.py +++ b/src/fiber_package/events/activity.py @@ -10,6 +10,9 @@ class ActivityModel(CommunicationModel): Field(pattern=CommunicationCategory.activity) ] + slug: str + # unique short name used in the public URL + start_time: datetime end_time: datetime diff --git a/src/fiber_package/events/notes.txt b/src/fiber_package/events/notes.txt new file mode 100644 index 0000000..f19315c --- /dev/null +++ b/src/fiber_package/events/notes.txt @@ -0,0 +1,48 @@ +Okay some ideas: + +We want a modular system. +A signup form = list of signup questions +A signup = list of signup answers + + +Examples of questions: +* Dietary restrictions +* Insurance info +* Pick option from list +* Team (interesting one, as people can also make new teams) + + +class SignupQuestion +--> SignupQuestionDiet, SignupQuestionInsurance, SignupQuestionOption .... +Questions differentiate through enum question_type +Questions can have parameters like Option + +-------------- + +Every SignupQuestionXYZ has a SignupAnswerXYZ + + +An activity consists of: +* usual event stuff, email, max_attendees, .... +* a slug! +* dict of SignupQuestions +* list of QuestionOrder + +A signup then consists of: +* ActivityRef (what activity) +* EntityRef (who signed up) +* optional payment_id +* optional is_reserve +* optional confirmed (true if paid) +* dict of SignupAnswers + +-------------- + +When saving a signup, we check: +* get activity +* is person allowed to sign up? +* do we have enough signup answers +* for every answer: does answer validate type of question? + + + From 9729b894772d54e53456670d257cccff95c603ca Mon Sep 17 00:00:00 2001 From: Tiago Scholten Date: Tue, 13 Oct 2026 16:57:27 +0200 Subject: [PATCH 04/23] rename to singular --- src/fiber_package/{events => event}/activity.py | 0 src/fiber_package/{events => event}/communication.py | 0 src/fiber_package/{events => event}/enums.py | 0 src/fiber_package/{events => event}/notes.txt | 0 src/fiber_package/{events => event}/submodels.py | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename src/fiber_package/{events => event}/activity.py (100%) rename src/fiber_package/{events => event}/communication.py (100%) rename src/fiber_package/{events => event}/enums.py (100%) rename src/fiber_package/{events => event}/notes.txt (100%) rename src/fiber_package/{events => event}/submodels.py (100%) diff --git a/src/fiber_package/events/activity.py b/src/fiber_package/event/activity.py similarity index 100% rename from src/fiber_package/events/activity.py rename to src/fiber_package/event/activity.py diff --git a/src/fiber_package/events/communication.py b/src/fiber_package/event/communication.py similarity index 100% rename from src/fiber_package/events/communication.py rename to src/fiber_package/event/communication.py diff --git a/src/fiber_package/events/enums.py b/src/fiber_package/event/enums.py similarity index 100% rename from src/fiber_package/events/enums.py rename to src/fiber_package/event/enums.py diff --git a/src/fiber_package/events/notes.txt b/src/fiber_package/event/notes.txt similarity index 100% rename from src/fiber_package/events/notes.txt rename to src/fiber_package/event/notes.txt diff --git a/src/fiber_package/events/submodels.py b/src/fiber_package/event/submodels.py similarity index 100% rename from src/fiber_package/events/submodels.py rename to src/fiber_package/event/submodels.py From d855b862cac160773284d806fb7a6670e2d73983 Mon Sep 17 00:00:00 2001 From: Tiago Scholten Date: Tue, 13 Oct 2026 21:40:37 +0200 Subject: [PATCH 05/23] Basic signup form & answer system --- .../{event => communication}/activity.py | 18 +++-- .../{event => communication}/communication.py | 12 ++-- .../{event => communication}/enums.py | 0 .../{event => communication}/notes.txt | 0 src/fiber_package/communication/submodels.py | 14 ++++ src/fiber_package/entity/person.py | 4 +- src/fiber_package/event/submodels.py | 10 --- src/fiber_package/refs.py | 13 +++- .../signup/answer/answer_base.py | 8 +++ .../signup/answer/answer_open_questions.py | 9 +++ .../signup/elements/form_base_question.py | 4 ++ .../signup/elements/form_element.py | 8 +++ .../signup/elements/form_open_questions.py | 27 +++++++ .../signup/elements/form_text.py | 9 +++ .../signup/elements/form_title.py | 9 +++ src/fiber_package/signup/enums.py | 14 ++++ src/fiber_package/signup/notes.txt | 70 +++++++++++++++++++ src/fiber_package/signup/signup.py | 16 +++++ 18 files changed, 218 insertions(+), 27 deletions(-) rename src/fiber_package/{event => communication}/activity.py (61%) rename src/fiber_package/{event => communication}/communication.py (89%) rename src/fiber_package/{event => communication}/enums.py (100%) rename src/fiber_package/{event => communication}/notes.txt (100%) create mode 100644 src/fiber_package/communication/submodels.py delete mode 100644 src/fiber_package/event/submodels.py create mode 100644 src/fiber_package/signup/answer/answer_base.py create mode 100644 src/fiber_package/signup/answer/answer_open_questions.py create mode 100644 src/fiber_package/signup/elements/form_base_question.py create mode 100644 src/fiber_package/signup/elements/form_element.py create mode 100644 src/fiber_package/signup/elements/form_open_questions.py create mode 100644 src/fiber_package/signup/elements/form_text.py create mode 100644 src/fiber_package/signup/elements/form_title.py create mode 100644 src/fiber_package/signup/enums.py create mode 100644 src/fiber_package/signup/notes.txt create mode 100644 src/fiber_package/signup/signup.py diff --git a/src/fiber_package/event/activity.py b/src/fiber_package/communication/activity.py similarity index 61% rename from src/fiber_package/event/activity.py rename to src/fiber_package/communication/activity.py index 969e745..e6f0786 100644 --- a/src/fiber_package/event/activity.py +++ b/src/fiber_package/communication/activity.py @@ -1,14 +1,18 @@ -from typing import Annotated, Self +from typing import Literal, Self +from pydantic import model_validator + +from datetime import datetime from .communication import CommunicationModel from .submodels import ActivityPaymentInfo +from .enums import CommunicationCategory +from fiber_package.refs import SignupRefList + +from fiber_package.signup.elements.form_element import FormElement class ActivityModel(CommunicationModel): - category: Annotated[ - CommunicationCategory, - Field(pattern=CommunicationCategory.activity) - ] + category: Literal[CommunicationCategory.activity] slug: str # unique short name used in the public URL @@ -18,9 +22,9 @@ class ActivityModel(CommunicationModel): payment_info: ActivityPaymentInfo | None = None + form: list[FormElement] - #signuplist: GroupRef | None = None - # TODO: implement signup list (huge modular system) + signups: SignupRefList = SignupRefList([], "signup") # TODO: see Felt 'activiteiten' DB schema. Things like: # email, target group, maximal attendees .... diff --git a/src/fiber_package/event/communication.py b/src/fiber_package/communication/communication.py similarity index 89% rename from src/fiber_package/event/communication.py rename to src/fiber_package/communication/communication.py index 257b632..d5b17ee 100644 --- a/src/fiber_package/event/communication.py +++ b/src/fiber_package/communication/communication.py @@ -1,6 +1,4 @@ -from pydantic import BaseModel, model_validator, Field, HttpUrl -from enum import StrEnum -from datetime import datetime +from pydantic import Field, HttpUrl from fiber_package.base import FiberBaseModel @@ -16,7 +14,7 @@ class CommunicationModel(FiberBaseModel): name_en: str name_nl: str - association_tags = [] + association_tags: list[str] = Field(default_factory=list) # list of associations this communication belongs to subtitle_en: str @@ -36,11 +34,11 @@ class CommunicationModel(FiberBaseModel): 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 \ No newline at end of file + # reference diff --git a/src/fiber_package/event/enums.py b/src/fiber_package/communication/enums.py similarity index 100% rename from src/fiber_package/event/enums.py rename to src/fiber_package/communication/enums.py diff --git a/src/fiber_package/event/notes.txt b/src/fiber_package/communication/notes.txt similarity index 100% rename from src/fiber_package/event/notes.txt rename to src/fiber_package/communication/notes.txt diff --git a/src/fiber_package/communication/submodels.py b/src/fiber_package/communication/submodels.py new file mode 100644 index 0000000..ffc6f30 --- /dev/null +++ b/src/fiber_package/communication/submodels.py @@ -0,0 +1,14 @@ +from decimal import Decimal +from typing import Annotated + +from pydantic import BaseModel, Field + +class ActivityPaymentInfo(BaseModel): + contribution: Annotated[ + Decimal, Field(decimal_places=2, ge=0) + ] + nnv_contribution: Annotated[ + Decimal | None, Field(None, decimal_places=2, ge=0) + ] = None + + diff --git a/src/fiber_package/entity/person.py b/src/fiber_package/entity/person.py index 4d05c34..eeabbeb 100644 --- a/src/fiber_package/entity/person.py +++ b/src/fiber_package/entity/person.py @@ -1,4 +1,4 @@ -from pydantic import model_validator, EmailStr, computed_field, field_serializer +from pydantic import model_validator, EmailStr, field_serializer from typing import Self, Literal from datetime import date @@ -31,7 +31,7 @@ class PersonModel(FiberBaseModel): if self.date_of_birth is None: return False if ref_date is None: - ref_data = date.today() + ref_date = date.today() age = ( ref_date.year - self.date_of_birth.year - ( (ref_date.month, ref_date.day) < (self.date_of_birth.month, self.date_of_birth.day) ) diff --git a/src/fiber_package/event/submodels.py b/src/fiber_package/event/submodels.py deleted file mode 100644 index e933c02..0000000 --- a/src/fiber_package/event/submodels.py +++ /dev/null @@ -1,10 +0,0 @@ -from decimal import Decimal -from typing import Annotated - -from pydantic import BaseModel, Field - -class ActivityPaymentInfo(BaseModel): - contribution: Annotated[Decimal, Field(decimal_places=2, ge=0)] - nnv_contribution: Annotated[Decimal | None, Field(None, decimal_places=2, ge=0)] = None - - diff --git a/src/fiber_package/refs.py b/src/fiber_package/refs.py index 6032df2..70879b1 100644 --- a/src/fiber_package/refs.py +++ b/src/fiber_package/refs.py @@ -11,7 +11,8 @@ CollectionName = Literal[ "entity", "committee", "committee_edition", - "guild" + "guild", + "signup" ] C = TypeVar("C", bound=str) @@ -47,3 +48,13 @@ CommitteeEditionRefList = RefList[Literal["committee_edition"]] GuildRef = Ref[Literal["guild"]] GuildRefList = RefList[Literal["guild"]] + +SignupRef = Ref[Literal["signup"]] +SignupRefList = RefList[Literal["signup"]] + +CommunicationRef = Ref[Literal["communication"]] +CommunicationRefList = Ref[Literal["communication"]] + +# Activities are stored in the collection of communications +ActivityRef = CommunicationRef +ActivityRefList = CommunicationRefList diff --git a/src/fiber_package/signup/answer/answer_base.py b/src/fiber_package/signup/answer/answer_base.py new file mode 100644 index 0000000..533793a --- /dev/null +++ b/src/fiber_package/signup/answer/answer_base.py @@ -0,0 +1,8 @@ +from pydantic import BaseModel, ConfigDict +from fiber_package.signup.enums import FormQuestionCategory + +class AnswerBase(BaseModel): + model_config = ConfigDict(extra='allow') + + category: FormQuestionCategory + question_name: str diff --git a/src/fiber_package/signup/answer/answer_open_questions.py b/src/fiber_package/signup/answer/answer_open_questions.py new file mode 100644 index 0000000..a42b09f --- /dev/null +++ b/src/fiber_package/signup/answer/answer_open_questions.py @@ -0,0 +1,9 @@ +from typing import Literal + +from .answer_base import AnswerBase +from fiber_package.signup.enums import FormElementCategory + +class AnswerOpenQuestions(AnswerBase): + category: Literal[FormElementCategory.open_questions] + + answers: list[str] diff --git a/src/fiber_package/signup/elements/form_base_question.py b/src/fiber_package/signup/elements/form_base_question.py new file mode 100644 index 0000000..483d10b --- /dev/null +++ b/src/fiber_package/signup/elements/form_base_question.py @@ -0,0 +1,4 @@ +from .form_element import FormElement + +class FormBaseQuestion(FormElement): + required: bool diff --git a/src/fiber_package/signup/elements/form_element.py b/src/fiber_package/signup/elements/form_element.py new file mode 100644 index 0000000..b68be56 --- /dev/null +++ b/src/fiber_package/signup/elements/form_element.py @@ -0,0 +1,8 @@ +from pydantic import BaseModel, ConfigDict +from fiber_package.signup.enums import FormElementCategory + +class FormElement(BaseModel): + model_config = ConfigDict(extra='allow') + + category: FormElementCategory + name: str diff --git a/src/fiber_package/signup/elements/form_open_questions.py b/src/fiber_package/signup/elements/form_open_questions.py new file mode 100644 index 0000000..9f4d774 --- /dev/null +++ b/src/fiber_package/signup/elements/form_open_questions.py @@ -0,0 +1,27 @@ +from typing import Literal +from pydantic import BaseModel + +from .form_base_question import FormBaseQuestion +from fiber_package.signup.enums import FormElementCategory + +class OpenQuestion(BaseModel): + question_en: str + question_nl: str + + explanation_en: str + explanation_nl: str + + placeholder_en: str = "" + placeholder_nl: str = "" + +class FormOpenQuestions(FormBaseQuestion): + category: Literal[FormElementCategory.open_questions] + + questions: list[OpenQuestion] + + title: str | None = None + pretext: str | None = None + posttext: str | None = None + + + diff --git a/src/fiber_package/signup/elements/form_text.py b/src/fiber_package/signup/elements/form_text.py new file mode 100644 index 0000000..991e42b --- /dev/null +++ b/src/fiber_package/signup/elements/form_text.py @@ -0,0 +1,9 @@ +from typing import Literal + +from .form_element import FormElement +from fiber_package.signup.enums import FormElementCategory + +class FormText(FormElement): + category: Literal[FormElementCategory.text_piece] + + text: str diff --git a/src/fiber_package/signup/elements/form_title.py b/src/fiber_package/signup/elements/form_title.py new file mode 100644 index 0000000..991d532 --- /dev/null +++ b/src/fiber_package/signup/elements/form_title.py @@ -0,0 +1,9 @@ +from typing import Literal + +from .form_element import FormElement +from fiber_package.signup.enums import FormElementCategory + +class FormText(FormElement): + category: Literal[FormElementCategory.title_text] + + title: str diff --git a/src/fiber_package/signup/enums.py b/src/fiber_package/signup/enums.py new file mode 100644 index 0000000..5455ec8 --- /dev/null +++ b/src/fiber_package/signup/enums.py @@ -0,0 +1,14 @@ +from enum import StrEnum +from typing import Literal + +''' +This category is used to differentiate types of form elements +''' +class FormElementCategory(StrEnum): + text_piece = "text_piece" + title_text = "title_text" + open_questions = "open_questions" + +FormQuestionCategory = Literal[ + FormElementCategory.open_questions +] diff --git a/src/fiber_package/signup/notes.txt b/src/fiber_package/signup/notes.txt new file mode 100644 index 0000000..d9a6f03 --- /dev/null +++ b/src/fiber_package/signup/notes.txt @@ -0,0 +1,70 @@ +Felt has sjablonen, stored in config + +sjablonen.(name) has fields: +* naam_nl = default name +* naam_en = ... +* info = used in the sjabloon overview +* types (array_keys ???) +* parameters = dict of parameters & type +* parametes_beschrijving = description of parameters +* parameters_sample = default values of all parameters + +On /activiteiten/bewerk we have a list of if statements +It groups the answers by type +* choises, feedback, teams, dinner, shirtsizes, nnv, +* public transport, reserve list, signups list + +* activites store their "types" as bitmask (1 = medisch, 2 = thuisfront ...) +* stored in models\Parameter +* list of parameter datatypes, + +Why is everything so builtin ?! Crazy. + +List of question types: +* medical --> alergies, meds, extra info +* thuisfront --> name contact, email contact, phone #1, phone #2 +* shirtsize --> pick enum from XXS, XS, S, M, L, XL, XXL +* identification --> document type, document number, expiry date, ... +* nnv --> state (notmember, later, member) & nnv number +* food --> joins for the meal (true/false), diet (text), vegetarian (t/f) +* public transport --> enum (no, week-only, weekend-only) +* travel / zorgverzekering --> verzekeraar, polisnummer, noodnummer, type (zorg of reis) +* questions --> parameter_id, slot, answer +* choices --> parameter_id, slot, choice +* feedback --> feedabck (str) +* team --> teamname (str) + +Maybe a bug? +If nnvbijdrage is set but nnv is not part of activity, +then everybody pays the LOW price as if NNV pays ??!! +Not a bug! You cannot set NNV if NNV is not part of sjabloon! +... its handled by custom js.... + + +omg it is TERRIBLE. In Silk every sjabloon has its OWN template ?! +so much work yikes + +Example for the "Studiereis" sjabloon: +* Some text (incl deadline) --> we can refer to variables and use HTML! +* Header (your signup is coupled to your current account!) +* Health insurance (+ text) +* Medical information (+ text) +* Home stayers (+text & checkmark about International Office) +* Identification (+text) +* NNV (+text) +* T-shirt +* OV +* Feedback + +Pattern: +* (title) (prefix text) item (suffix text) +Then possibly also: +* title-items & text-items + +------------- + +Ideas: +* Modular system! +* Create template activities (by creating activity, store as template & then delete?) + +* Combine complicated questions into custom question (see all above) diff --git a/src/fiber_package/signup/signup.py b/src/fiber_package/signup/signup.py new file mode 100644 index 0000000..c8e07ba --- /dev/null +++ b/src/fiber_package/signup/signup.py @@ -0,0 +1,16 @@ +from typing import Literal + +from fiber_package.base import FiberBaseModel +from fiber_package.refs import EntityRef, ActivityRef + +from fiber_package.signup.answer.answer_base import AnswerBase + +class Signup(FiberBaseModel): + collection_name: Literal["signup"] = "signup" + + attendee: EntityRef + activity: ActivityRef + + answers: list[AnswerBase] + + # TODO: signed_up, is_reserve, payment, confirmed, .... From 0fd92120d95ba40d7c82c321d8d13a774eaba1ed Mon Sep 17 00:00:00 2001 From: Tiago Scholten Date: Tue, 13 Oct 2026 21:47:39 +0200 Subject: [PATCH 06/23] rename + added validation of answer to question --- .../signup/answer/answer_open_questions.py | 2 +- .../{elements => element}/form_base_question.py | 4 ++++ .../signup/{elements => element}/form_element.py | 0 .../{elements => element}/form_open_questions.py | 13 ++++++++++--- .../signup/{elements => element}/form_text.py | 0 .../signup/{elements => element}/form_title.py | 0 6 files changed, 15 insertions(+), 4 deletions(-) rename src/fiber_package/signup/{elements => element}/form_base_question.py (50%) rename src/fiber_package/signup/{elements => element}/form_element.py (100%) rename src/fiber_package/signup/{elements => element}/form_open_questions.py (52%) rename src/fiber_package/signup/{elements => element}/form_text.py (100%) rename src/fiber_package/signup/{elements => element}/form_title.py (100%) diff --git a/src/fiber_package/signup/answer/answer_open_questions.py b/src/fiber_package/signup/answer/answer_open_questions.py index a42b09f..b399dbb 100644 --- a/src/fiber_package/signup/answer/answer_open_questions.py +++ b/src/fiber_package/signup/answer/answer_open_questions.py @@ -6,4 +6,4 @@ from fiber_package.signup.enums import FormElementCategory class AnswerOpenQuestions(AnswerBase): category: Literal[FormElementCategory.open_questions] - answers: list[str] + answer_list: list[str] diff --git a/src/fiber_package/signup/elements/form_base_question.py b/src/fiber_package/signup/element/form_base_question.py similarity index 50% rename from src/fiber_package/signup/elements/form_base_question.py rename to src/fiber_package/signup/element/form_base_question.py index 483d10b..11365f0 100644 --- a/src/fiber_package/signup/elements/form_base_question.py +++ b/src/fiber_package/signup/element/form_base_question.py @@ -2,3 +2,7 @@ from .form_element import FormElement class FormBaseQuestion(FormElement): required: bool + + title: str | None = None + pretext: str | None = None + posttext: str | None = None diff --git a/src/fiber_package/signup/elements/form_element.py b/src/fiber_package/signup/element/form_element.py similarity index 100% rename from src/fiber_package/signup/elements/form_element.py rename to src/fiber_package/signup/element/form_element.py diff --git a/src/fiber_package/signup/elements/form_open_questions.py b/src/fiber_package/signup/element/form_open_questions.py similarity index 52% rename from src/fiber_package/signup/elements/form_open_questions.py rename to src/fiber_package/signup/element/form_open_questions.py index 9f4d774..8ad5de2 100644 --- a/src/fiber_package/signup/elements/form_open_questions.py +++ b/src/fiber_package/signup/element/form_open_questions.py @@ -4,6 +4,8 @@ from pydantic import BaseModel from .form_base_question import FormBaseQuestion from fiber_package.signup.enums import FormElementCategory +from fiber_package.signup.answer.answer_open_questions import AnswerOpenQuestions + class OpenQuestion(BaseModel): question_en: str question_nl: str @@ -19,9 +21,14 @@ class FormOpenQuestions(FormBaseQuestion): questions: list[OpenQuestion] - title: str | None = None - pretext: str | None = None - posttext: str | None = None + def validate_answer(self, answer: AnswerOpenQuestions) -> None: + if answer.question_name != self.name: + raise ValueError("Answer question name does not match.") + + answer_list = answer.answer_list + if len(answer_list) != len(self.questions): + raise ValueError("Length of answer question list does not match.") + diff --git a/src/fiber_package/signup/elements/form_text.py b/src/fiber_package/signup/element/form_text.py similarity index 100% rename from src/fiber_package/signup/elements/form_text.py rename to src/fiber_package/signup/element/form_text.py diff --git a/src/fiber_package/signup/elements/form_title.py b/src/fiber_package/signup/element/form_title.py similarity index 100% rename from src/fiber_package/signup/elements/form_title.py rename to src/fiber_package/signup/element/form_title.py From 0252f2aeb6f6788ad175201155669a191b9dd8dc Mon Sep 17 00:00:00 2001 From: Tiago Scholten Date: Tue, 13 Oct 2026 21:58:34 +0200 Subject: [PATCH 07/23] fixed typo --- src/fiber_package/signup/element/form_title.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fiber_package/signup/element/form_title.py b/src/fiber_package/signup/element/form_title.py index 991d532..d300c64 100644 --- a/src/fiber_package/signup/element/form_title.py +++ b/src/fiber_package/signup/element/form_title.py @@ -3,7 +3,7 @@ from typing import Literal from .form_element import FormElement from fiber_package.signup.enums import FormElementCategory -class FormText(FormElement): +class FormTitle(FormElement): category: Literal[FormElementCategory.title_text] title: str From 6d8b06dfc7583c2a462ec559582fb2276e606f42 Mon Sep 17 00:00:00 2001 From: Tiago Scholten Date: Wed, 14 Oct 2026 09:26:00 +0200 Subject: [PATCH 08/23] consistent naming --- src/fiber_package/signup/signup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fiber_package/signup/signup.py b/src/fiber_package/signup/signup.py index c8e07ba..6b13f63 100644 --- a/src/fiber_package/signup/signup.py +++ b/src/fiber_package/signup/signup.py @@ -5,7 +5,7 @@ from fiber_package.refs import EntityRef, ActivityRef from fiber_package.signup.answer.answer_base import AnswerBase -class Signup(FiberBaseModel): +class SignupModel(FiberBaseModel): collection_name: Literal["signup"] = "signup" attendee: EntityRef From f8c576263ccc4089723b78406f394062a5238bde Mon Sep 17 00:00:00 2001 From: Tiago Scholten Date: Wed, 14 Oct 2026 10:04:28 +0200 Subject: [PATCH 09/23] system for validating answers to signup forms --- src/fiber_package/communication/activity.py | 51 +++++++++++++++++-- .../signup/element/form_base_question.py | 3 ++ .../signup/element/form_base_text.py | 5 ++ .../signup/element/form_open_questions.py | 2 +- src/fiber_package/signup/enums.py | 5 ++ src/fiber_package/signup/util.py | 18 +++++++ 6 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 src/fiber_package/signup/element/form_base_text.py create mode 100644 src/fiber_package/signup/util.py diff --git a/src/fiber_package/communication/activity.py b/src/fiber_package/communication/activity.py index e6f0786..9e9af96 100644 --- a/src/fiber_package/communication/activity.py +++ b/src/fiber_package/communication/activity.py @@ -1,5 +1,5 @@ -from typing import Literal, Self -from pydantic import model_validator +from typing import Literal, Self, Annotated +from pydantic import model_validator, Field from datetime import datetime @@ -8,8 +8,17 @@ from .submodels import ActivityPaymentInfo from .enums import CommunicationCategory from fiber_package.refs import SignupRefList +from fiber_package.signup.signup import SignupModel +from fiber_package.signup.util import validate_answer -from fiber_package.signup.elements.form_element import FormElement +from fiber_package.signup.element.form_base_text import FormBaseText +from fiber_package.signup.element.form_base_question import FormBaseQuestion + +# Special type which uses enum category to decide type! +FieldUnionType = Annotated[ + FormBaseText | FormBaseQuestion, + Field(discriminator="category") +] class ActivityModel(CommunicationModel): category: Literal[CommunicationCategory.activity] @@ -22,7 +31,7 @@ class ActivityModel(CommunicationModel): payment_info: ActivityPaymentInfo | None = None - form: list[FormElement] + form: list[FieldUnionType] signups: SignupRefList = SignupRefList([], "signup") @@ -34,3 +43,37 @@ class ActivityModel(CommunicationModel): if self.end_time < self.start_time: raise ValueError("End time cannot be earlier than start time") return self + + def validate_signup_form(self, signup: SignupModel) -> None: + required = set() + answerable = set() + + question_dict: dict[str, FormBaseQuestion] = {} + + for element in self.form: + if isinstance(element, FormBaseText): + continue + # so we know it is istance of FormBaseQuestion + answerable.add(element.name) + if element.required: + required.add(element.name) + question_dict[element.name] = element + + answers = signup.answers + for answer in answers: + q_name = answer.question_name + if q_name not in answerable: + raise ValueError( + f"Form contains answer to " + f"non-existing question {q_name}." + ) + answerable.remove(q_name) + if answer.question_name in required: + required.remove(q_name) + + question = question_dict[q_name] + validate_answer(question, answer) + + + if len(required) > 0: + raise ValueError("Form does not answer all required questions.") diff --git a/src/fiber_package/signup/element/form_base_question.py b/src/fiber_package/signup/element/form_base_question.py index 11365f0..c0c1942 100644 --- a/src/fiber_package/signup/element/form_base_question.py +++ b/src/fiber_package/signup/element/form_base_question.py @@ -1,6 +1,9 @@ from .form_element import FormElement +from fiber_package.signup.enums import FormQuestionCategory class FormBaseQuestion(FormElement): + category: FormQuestionCategory + required: bool title: str | None = None diff --git a/src/fiber_package/signup/element/form_base_text.py b/src/fiber_package/signup/element/form_base_text.py new file mode 100644 index 0000000..1cffa93 --- /dev/null +++ b/src/fiber_package/signup/element/form_base_text.py @@ -0,0 +1,5 @@ +from .form_element import FormElement +from fiber_package.signup.enums import FormTextCategory + +class FormBaseText(FormElement): + category: FormTextCategory diff --git a/src/fiber_package/signup/element/form_open_questions.py b/src/fiber_package/signup/element/form_open_questions.py index 8ad5de2..c0429a8 100644 --- a/src/fiber_package/signup/element/form_open_questions.py +++ b/src/fiber_package/signup/element/form_open_questions.py @@ -24,7 +24,7 @@ class FormOpenQuestions(FormBaseQuestion): def validate_answer(self, answer: AnswerOpenQuestions) -> None: if answer.question_name != self.name: raise ValueError("Answer question name does not match.") - + answer_list = answer.answer_list if len(answer_list) != len(self.questions): raise ValueError("Length of answer question list does not match.") diff --git a/src/fiber_package/signup/enums.py b/src/fiber_package/signup/enums.py index 5455ec8..6dff12b 100644 --- a/src/fiber_package/signup/enums.py +++ b/src/fiber_package/signup/enums.py @@ -12,3 +12,8 @@ class FormElementCategory(StrEnum): FormQuestionCategory = Literal[ FormElementCategory.open_questions ] + +FormTextCategory = Literal[ + FormElementCategory.text_piece, + FormElementCategory.title_text +] diff --git a/src/fiber_package/signup/util.py b/src/fiber_package/signup/util.py new file mode 100644 index 0000000..91d037f --- /dev/null +++ b/src/fiber_package/signup/util.py @@ -0,0 +1,18 @@ +from fiber_package.signup.element.form_base_question import FormBaseQuestion +from fiber_package.signup.element.form_open_questions import FormOpenQuestions + +from fiber_package.signup.answer.answer_base import AnswerBase +from fiber_package.signup.enums import FormElementCategory + +from fiber_package.signup.answer.answer_open_questions import AnswerOpenQuestions + +def validate_answer(question: FormBaseQuestion, answer: AnswerBase) -> None: + if question.category != answer.category: + raise ValueError("Question and answer category do not match!") + + if question.category == FormElementCategory.open_questions: + question_val = FormOpenQuestions.model_validate(question.model_dump()) + answer_val = AnswerOpenQuestions.model_validate(answer.model_dump()) + question_val.validate_answer(answer_val) + + # TODO: implement From c0e592e97399d80f4dea7372e5d0e2f1c379a2b1 Mon Sep 17 00:00:00 2001 From: Tiago Scholten Date: Wed, 14 Oct 2026 16:54:27 +0200 Subject: [PATCH 10/23] added collection to list --- src/fiber_package/refs.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fiber_package/refs.py b/src/fiber_package/refs.py index 70879b1..b6ddd0a 100644 --- a/src/fiber_package/refs.py +++ b/src/fiber_package/refs.py @@ -12,7 +12,8 @@ CollectionName = Literal[ "committee", "committee_edition", "guild", - "signup" + "signup", + "communication" ] C = TypeVar("C", bound=str) From 0c1683c74bec7f8a3f2212eded54f595c6a9a61c Mon Sep 17 00:00:00 2001 From: Tiago Scholten Date: Wed, 14 Oct 2026 20:25:13 +0200 Subject: [PATCH 11/23] Added function which ckecs if a form category is a question --- src/fiber_package/signup/enums.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/fiber_package/signup/enums.py b/src/fiber_package/signup/enums.py index 6dff12b..d62f853 100644 --- a/src/fiber_package/signup/enums.py +++ b/src/fiber_package/signup/enums.py @@ -1,5 +1,5 @@ from enum import StrEnum -from typing import Literal +from typing import Literal, get_args ''' This category is used to differentiate types of form elements @@ -17,3 +17,6 @@ FormTextCategory = Literal[ FormElementCategory.text_piece, FormElementCategory.title_text ] + +def is_question_category(category: FormElementCategory) -> bool: + return category in get_args(FormQuestionCategory) From 5e7f72ea2fbaad8cdbe7cea846f70959694ffd7e Mon Sep 17 00:00:00 2001 From: Tiago Scholten Date: Wed, 14 Oct 2026 21:31:33 +0200 Subject: [PATCH 12/23] added new union types --- src/fiber_package/communication/activity.py | 15 +++++--------- src/fiber_package/signup/answer/types.py | 10 ++++++++++ src/fiber_package/signup/element/types.py | 22 +++++++++++++++++++++ src/fiber_package/signup/signup.py | 4 ++-- 4 files changed, 39 insertions(+), 12 deletions(-) create mode 100644 src/fiber_package/signup/answer/types.py create mode 100644 src/fiber_package/signup/element/types.py diff --git a/src/fiber_package/communication/activity.py b/src/fiber_package/communication/activity.py index 9e9af96..60fb0b8 100644 --- a/src/fiber_package/communication/activity.py +++ b/src/fiber_package/communication/activity.py @@ -1,5 +1,5 @@ -from typing import Literal, Self, Annotated -from pydantic import model_validator, Field +from typing import Literal, Self +from pydantic import model_validator from datetime import datetime @@ -11,14 +11,9 @@ from fiber_package.refs import SignupRefList from fiber_package.signup.signup import SignupModel from fiber_package.signup.util import validate_answer -from fiber_package.signup.element.form_base_text import FormBaseText from fiber_package.signup.element.form_base_question import FormBaseQuestion -# Special type which uses enum category to decide type! -FieldUnionType = Annotated[ - FormBaseText | FormBaseQuestion, - Field(discriminator="category") -] +from fiber_package.signup.element.types import FormElementUnion, FormTextUnion class ActivityModel(CommunicationModel): category: Literal[CommunicationCategory.activity] @@ -31,7 +26,7 @@ class ActivityModel(CommunicationModel): payment_info: ActivityPaymentInfo | None = None - form: list[FieldUnionType] + form: list[FormElementUnion] signups: SignupRefList = SignupRefList([], "signup") @@ -51,7 +46,7 @@ class ActivityModel(CommunicationModel): question_dict: dict[str, FormBaseQuestion] = {} for element in self.form: - if isinstance(element, FormBaseText): + if isinstance(element, FormTextUnion): continue # so we know it is istance of FormBaseQuestion answerable.add(element.name) diff --git a/src/fiber_package/signup/answer/types.py b/src/fiber_package/signup/answer/types.py new file mode 100644 index 0000000..8f9effd --- /dev/null +++ b/src/fiber_package/signup/answer/types.py @@ -0,0 +1,10 @@ +from typing import Annotated + +from pydantic import Field + +from .answer_open_questions import AnswerOpenQuestions + +AnswerUnion = Annotated[ + AnswerOpenQuestions, + Field(discriminator="category") +] diff --git a/src/fiber_package/signup/element/types.py b/src/fiber_package/signup/element/types.py new file mode 100644 index 0000000..77a6f4b --- /dev/null +++ b/src/fiber_package/signup/element/types.py @@ -0,0 +1,22 @@ +from typing import Annotated + +from pydantic import Field + +from .form_open_questions import FormOpenQuestions +from .form_text import FormText +from .form_title import FormTitle + +FormTextUnion = Annotated[ + FormText | FormTitle, + Field(discriminator="category") +] + +FormQuestionUnion = Annotated[ + FormOpenQuestions, + Field(discriminator="category") +] + +FormElementUnion = Annotated[ + FormTextUnion | FormQuestionUnion, + Field(discriminator="category") +] diff --git a/src/fiber_package/signup/signup.py b/src/fiber_package/signup/signup.py index 6b13f63..8690685 100644 --- a/src/fiber_package/signup/signup.py +++ b/src/fiber_package/signup/signup.py @@ -3,7 +3,7 @@ from typing import Literal from fiber_package.base import FiberBaseModel from fiber_package.refs import EntityRef, ActivityRef -from fiber_package.signup.answer.answer_base import AnswerBase +from fiber_package.signup.answer.types import AnswerUnion class SignupModel(FiberBaseModel): collection_name: Literal["signup"] = "signup" @@ -11,6 +11,6 @@ class SignupModel(FiberBaseModel): attendee: EntityRef activity: ActivityRef - answers: list[AnswerBase] + answers: list[AnswerUnion] # TODO: signed_up, is_reserve, payment, confirmed, .... From 36dadd7ac132aeb24d5418a86bd64ec6bd5d39ab Mon Sep 17 00:00:00 2001 From: Tiago Scholten Date: Sat, 17 Oct 2026 16:35:19 +0200 Subject: [PATCH 13/23] rename --- src/fiber_package/{communication => events}/activity.py | 0 src/fiber_package/{communication => events}/communication.py | 0 src/fiber_package/{communication => events}/enums.py | 0 src/fiber_package/{communication => events}/notes.txt | 0 src/fiber_package/{communication => events}/submodels.py | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename src/fiber_package/{communication => events}/activity.py (100%) rename src/fiber_package/{communication => events}/communication.py (100%) rename src/fiber_package/{communication => events}/enums.py (100%) rename src/fiber_package/{communication => events}/notes.txt (100%) rename src/fiber_package/{communication => events}/submodels.py (100%) diff --git a/src/fiber_package/communication/activity.py b/src/fiber_package/events/activity.py similarity index 100% rename from src/fiber_package/communication/activity.py rename to src/fiber_package/events/activity.py diff --git a/src/fiber_package/communication/communication.py b/src/fiber_package/events/communication.py similarity index 100% rename from src/fiber_package/communication/communication.py rename to src/fiber_package/events/communication.py diff --git a/src/fiber_package/communication/enums.py b/src/fiber_package/events/enums.py similarity index 100% rename from src/fiber_package/communication/enums.py rename to src/fiber_package/events/enums.py diff --git a/src/fiber_package/communication/notes.txt b/src/fiber_package/events/notes.txt similarity index 100% rename from src/fiber_package/communication/notes.txt rename to src/fiber_package/events/notes.txt diff --git a/src/fiber_package/communication/submodels.py b/src/fiber_package/events/submodels.py similarity index 100% rename from src/fiber_package/communication/submodels.py rename to src/fiber_package/events/submodels.py From 74a4c947a134189a5b00d0e1ef0f75e89ad3a1fe Mon Sep 17 00:00:00 2001 From: Tiago Scholten Date: Sat, 17 Oct 2026 16:50:38 +0200 Subject: [PATCH 14/23] new question type --- .../signup/answer/answer_checkmarks.py | 9 ++++++ .../signup/element/form_checkmarks.py | 28 +++++++++++++++++++ src/fiber_package/signup/element/types.py | 3 +- src/fiber_package/signup/enums.py | 4 ++- .../signup/howto-add-new-question.txt | 8 ++++++ src/fiber_package/signup/notes.txt | 5 ---- 6 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 src/fiber_package/signup/answer/answer_checkmarks.py create mode 100644 src/fiber_package/signup/element/form_checkmarks.py create mode 100644 src/fiber_package/signup/howto-add-new-question.txt diff --git a/src/fiber_package/signup/answer/answer_checkmarks.py b/src/fiber_package/signup/answer/answer_checkmarks.py new file mode 100644 index 0000000..8988750 --- /dev/null +++ b/src/fiber_package/signup/answer/answer_checkmarks.py @@ -0,0 +1,9 @@ +from typing import Literal + +from .answer_base import AnswerBase +from fiber_package.signup.enums import FormElementCategory + +class AnswerOpenQuestions(AnswerBase): + category: Literal[FormElementCategory.checkmarks] + + answer_list: list[bool] diff --git a/src/fiber_package/signup/element/form_checkmarks.py b/src/fiber_package/signup/element/form_checkmarks.py new file mode 100644 index 0000000..f7694cb --- /dev/null +++ b/src/fiber_package/signup/element/form_checkmarks.py @@ -0,0 +1,28 @@ +from typing import Literal +from pydantic import BaseModel + +from .form_base_question import FormBaseQuestion +from fiber_package.signup.enums import FormElementCategory + +from fiber_package.signup.answer.answer_open_questions import AnswerCheckmarks + +class CheckmarkQuestion(BaseModel): + question_en: str + question_nl: str + +class FormCheckmarks(FormBaseQuestion): + category: Literal[FormElementCategory.checkmarks] + + questions: list[CheckmarkQuestion] + + def validate_answer(self, answer: AnswerCheckmarks) -> None: + if answer.question_name != self.name: + raise ValueError("Answer question name does not match.") + + answer_list = answer.answer_list + if len(answer_list) != len(self.questions): + raise ValueError("Length of answer question list does not match.") + + + + diff --git a/src/fiber_package/signup/element/types.py b/src/fiber_package/signup/element/types.py index 77a6f4b..76c8a36 100644 --- a/src/fiber_package/signup/element/types.py +++ b/src/fiber_package/signup/element/types.py @@ -3,6 +3,7 @@ from typing import Annotated from pydantic import Field from .form_open_questions import FormOpenQuestions +from .form_checkmarks import FormCheckmarks from .form_text import FormText from .form_title import FormTitle @@ -12,7 +13,7 @@ FormTextUnion = Annotated[ ] FormQuestionUnion = Annotated[ - FormOpenQuestions, + FormOpenQuestions | FormCheckmarks, Field(discriminator="category") ] diff --git a/src/fiber_package/signup/enums.py b/src/fiber_package/signup/enums.py index d62f853..5cb289d 100644 --- a/src/fiber_package/signup/enums.py +++ b/src/fiber_package/signup/enums.py @@ -8,9 +8,11 @@ class FormElementCategory(StrEnum): text_piece = "text_piece" title_text = "title_text" open_questions = "open_questions" + checkmarks = "checkmarks" FormQuestionCategory = Literal[ - FormElementCategory.open_questions + FormElementCategory.open_questions, + FormElementCategory.checkmarks ] FormTextCategory = Literal[ diff --git a/src/fiber_package/signup/howto-add-new-question.txt b/src/fiber_package/signup/howto-add-new-question.txt new file mode 100644 index 0000000..cd1f921 --- /dev/null +++ b/src/fiber_package/signup/howto-add-new-question.txt @@ -0,0 +1,8 @@ +In order to add a new question type you need to: + +1) Make a new tag in enums.py +2) add it to the list of question tags +3) Create the FormXXX in element +4) Create the AnswerXXX in answer +5) Add it to the question union type in answer.types +6) Add it to fiber-django \ No newline at end of file diff --git a/src/fiber_package/signup/notes.txt b/src/fiber_package/signup/notes.txt index d9a6f03..7df7049 100644 --- a/src/fiber_package/signup/notes.txt +++ b/src/fiber_package/signup/notes.txt @@ -34,11 +34,6 @@ List of question types: * feedback --> feedabck (str) * team --> teamname (str) -Maybe a bug? -If nnvbijdrage is set but nnv is not part of activity, -then everybody pays the LOW price as if NNV pays ??!! -Not a bug! You cannot set NNV if NNV is not part of sjabloon! -... its handled by custom js.... omg it is TERRIBLE. In Silk every sjabloon has its OWN template ?! From 71853ac32d0923e6215799459a267fdda52e73a1 Mon Sep 17 00:00:00 2001 From: Tiago Scholten Date: Sat, 17 Oct 2026 16:51:41 +0200 Subject: [PATCH 15/23] New type + questions --- src/fiber_package/signup/answer/answer_checkmarks.py | 2 +- src/fiber_package/signup/element/form_checkmarks.py | 2 +- src/fiber_package/signup/howto-add-new-question.txt | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/fiber_package/signup/answer/answer_checkmarks.py b/src/fiber_package/signup/answer/answer_checkmarks.py index 8988750..95c3842 100644 --- a/src/fiber_package/signup/answer/answer_checkmarks.py +++ b/src/fiber_package/signup/answer/answer_checkmarks.py @@ -3,7 +3,7 @@ from typing import Literal from .answer_base import AnswerBase from fiber_package.signup.enums import FormElementCategory -class AnswerOpenQuestions(AnswerBase): +class AnswerCheckmarks(AnswerBase): category: Literal[FormElementCategory.checkmarks] answer_list: list[bool] diff --git a/src/fiber_package/signup/element/form_checkmarks.py b/src/fiber_package/signup/element/form_checkmarks.py index f7694cb..36887f5 100644 --- a/src/fiber_package/signup/element/form_checkmarks.py +++ b/src/fiber_package/signup/element/form_checkmarks.py @@ -4,7 +4,7 @@ from pydantic import BaseModel from .form_base_question import FormBaseQuestion from fiber_package.signup.enums import FormElementCategory -from fiber_package.signup.answer.answer_open_questions import AnswerCheckmarks +from fiber_package.signup.answer.answer_checkmarks import AnswerCheckmarks class CheckmarkQuestion(BaseModel): question_en: str diff --git a/src/fiber_package/signup/howto-add-new-question.txt b/src/fiber_package/signup/howto-add-new-question.txt index cd1f921..b6ed00d 100644 --- a/src/fiber_package/signup/howto-add-new-question.txt +++ b/src/fiber_package/signup/howto-add-new-question.txt @@ -5,4 +5,5 @@ In order to add a new question type you need to: 3) Create the FormXXX in element 4) Create the AnswerXXX in answer 5) Add it to the question union type in answer.types +Tip: run ./pre-commit to run the typechecker to see if you got your imports right! 6) Add it to fiber-django \ No newline at end of file From 9f513271ac8fcba3c971905c2e2e49a70defc317 Mon Sep 17 00:00:00 2001 From: Tiago Scholten Date: Sat, 17 Oct 2026 17:07:20 +0200 Subject: [PATCH 16/23] rename to singular --- src/fiber_package/{events => event}/activity.py | 0 src/fiber_package/{events => event}/communication.py | 0 src/fiber_package/{events => event}/enums.py | 0 src/fiber_package/{events => event}/notes.txt | 0 src/fiber_package/{events => event}/submodels.py | 0 src/fiber_package/signup/howto-add-new-question.txt | 5 ++++- 6 files changed, 4 insertions(+), 1 deletion(-) rename src/fiber_package/{events => event}/activity.py (100%) rename src/fiber_package/{events => event}/communication.py (100%) rename src/fiber_package/{events => event}/enums.py (100%) rename src/fiber_package/{events => event}/notes.txt (100%) rename src/fiber_package/{events => event}/submodels.py (100%) diff --git a/src/fiber_package/events/activity.py b/src/fiber_package/event/activity.py similarity index 100% rename from src/fiber_package/events/activity.py rename to src/fiber_package/event/activity.py diff --git a/src/fiber_package/events/communication.py b/src/fiber_package/event/communication.py similarity index 100% rename from src/fiber_package/events/communication.py rename to src/fiber_package/event/communication.py diff --git a/src/fiber_package/events/enums.py b/src/fiber_package/event/enums.py similarity index 100% rename from src/fiber_package/events/enums.py rename to src/fiber_package/event/enums.py diff --git a/src/fiber_package/events/notes.txt b/src/fiber_package/event/notes.txt similarity index 100% rename from src/fiber_package/events/notes.txt rename to src/fiber_package/event/notes.txt diff --git a/src/fiber_package/events/submodels.py b/src/fiber_package/event/submodels.py similarity index 100% rename from src/fiber_package/events/submodels.py rename to src/fiber_package/event/submodels.py diff --git a/src/fiber_package/signup/howto-add-new-question.txt b/src/fiber_package/signup/howto-add-new-question.txt index b6ed00d..e948dbf 100644 --- a/src/fiber_package/signup/howto-add-new-question.txt +++ b/src/fiber_package/signup/howto-add-new-question.txt @@ -6,4 +6,7 @@ In order to add a new question type you need to: 4) Create the AnswerXXX in answer 5) Add it to the question union type in answer.types Tip: run ./pre-commit to run the typechecker to see if you got your imports right! -6) Add it to fiber-django \ No newline at end of file +6) Add it to fiber-django + 6a) Add it to the process_question function event/util.py + 6b) Add it to core/templates/form + 6c) Add it to the form page (currently dlfsite/templates/testing/form.html) \ No newline at end of file From 22859b679ffd0edce5f1299a03fb2195c54676bc Mon Sep 17 00:00:00 2001 From: Tiago Scholten Date: Sat, 17 Oct 2026 17:09:12 +0200 Subject: [PATCH 17/23] renamed collection to event to match folder name --- src/fiber_package/refs.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/fiber_package/refs.py b/src/fiber_package/refs.py index b6ddd0a..e74312d 100644 --- a/src/fiber_package/refs.py +++ b/src/fiber_package/refs.py @@ -13,7 +13,7 @@ CollectionName = Literal[ "committee_edition", "guild", "signup", - "communication" + "event" ] C = TypeVar("C", bound=str) @@ -53,8 +53,8 @@ GuildRefList = RefList[Literal["guild"]] SignupRef = Ref[Literal["signup"]] SignupRefList = RefList[Literal["signup"]] -CommunicationRef = Ref[Literal["communication"]] -CommunicationRefList = Ref[Literal["communication"]] +CommunicationRef = Ref[Literal["event"]] +CommunicationRefList = Ref[Literal["event"]] # Activities are stored in the collection of communications ActivityRef = CommunicationRef From 5e4787665e62865a54ec7af247f632db705c443f Mon Sep 17 00:00:00 2001 From: Tiago Scholten Date: Sat, 17 Oct 2026 17:23:45 +0200 Subject: [PATCH 18/23] added extra step --- src/fiber_package/signup/answer/types.py | 3 ++- src/fiber_package/signup/howto-add-new-question.txt | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/fiber_package/signup/answer/types.py b/src/fiber_package/signup/answer/types.py index 8f9effd..92c17e8 100644 --- a/src/fiber_package/signup/answer/types.py +++ b/src/fiber_package/signup/answer/types.py @@ -3,8 +3,9 @@ from typing import Annotated from pydantic import Field from .answer_open_questions import AnswerOpenQuestions +from .answer_checkmarks import AnswerCheckmarks AnswerUnion = Annotated[ - AnswerOpenQuestions, + AnswerOpenQuestions, AnswerCheckmarks Field(discriminator="category") ] diff --git a/src/fiber_package/signup/howto-add-new-question.txt b/src/fiber_package/signup/howto-add-new-question.txt index e948dbf..7c931ae 100644 --- a/src/fiber_package/signup/howto-add-new-question.txt +++ b/src/fiber_package/signup/howto-add-new-question.txt @@ -4,9 +4,10 @@ In order to add a new question type you need to: 2) add it to the list of question tags 3) Create the FormXXX in element 4) Create the AnswerXXX in answer -5) Add it to the question union type in answer.types +5) Add it to the answer union type in answer.types +6) Add it to the question union type in element.types Tip: run ./pre-commit to run the typechecker to see if you got your imports right! -6) Add it to fiber-django +7) Add it to fiber-django 6a) Add it to the process_question function event/util.py 6b) Add it to core/templates/form 6c) Add it to the form page (currently dlfsite/templates/testing/form.html) \ No newline at end of file From 0cc1bf48618fe1940f97d2b125dc38ef12588fbe Mon Sep 17 00:00:00 2001 From: Tiago Scholten Date: Sat, 17 Oct 2026 17:23:59 +0200 Subject: [PATCH 19/23] typo --- src/fiber_package/signup/answer/types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fiber_package/signup/answer/types.py b/src/fiber_package/signup/answer/types.py index 92c17e8..51749a6 100644 --- a/src/fiber_package/signup/answer/types.py +++ b/src/fiber_package/signup/answer/types.py @@ -6,6 +6,6 @@ from .answer_open_questions import AnswerOpenQuestions from .answer_checkmarks import AnswerCheckmarks AnswerUnion = Annotated[ - AnswerOpenQuestions, AnswerCheckmarks + AnswerOpenQuestions, AnswerCheckmarks, Field(discriminator="category") ] From d94e1bda81d6cc76b083896e01b86fea137e6b10 Mon Sep 17 00:00:00 2001 From: Tiago Scholten Date: Sat, 17 Oct 2026 17:25:38 +0200 Subject: [PATCH 20/23] another typo --- src/fiber_package/signup/answer/types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fiber_package/signup/answer/types.py b/src/fiber_package/signup/answer/types.py index 51749a6..41131bf 100644 --- a/src/fiber_package/signup/answer/types.py +++ b/src/fiber_package/signup/answer/types.py @@ -6,6 +6,6 @@ from .answer_open_questions import AnswerOpenQuestions from .answer_checkmarks import AnswerCheckmarks AnswerUnion = Annotated[ - AnswerOpenQuestions, AnswerCheckmarks, + AnswerOpenQuestion | AnswerCheckmarks, Field(discriminator="category") ] From 5c4aac62cb63c779a63a7976a1fb45fee65ca30e Mon Sep 17 00:00:00 2001 From: Tiago Scholten Date: Sat, 17 Oct 2026 17:26:22 +0200 Subject: [PATCH 21/23] third typo hihi --- src/fiber_package/signup/answer/types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fiber_package/signup/answer/types.py b/src/fiber_package/signup/answer/types.py index 41131bf..8d31d00 100644 --- a/src/fiber_package/signup/answer/types.py +++ b/src/fiber_package/signup/answer/types.py @@ -6,6 +6,6 @@ from .answer_open_questions import AnswerOpenQuestions from .answer_checkmarks import AnswerCheckmarks AnswerUnion = Annotated[ - AnswerOpenQuestion | AnswerCheckmarks, + AnswerOpenQuestions | AnswerCheckmarks, Field(discriminator="category") ] From 249e6851b4505ac767bea101a80b206e8fb03178 Mon Sep 17 00:00:00 2001 From: Tiago Scholten Date: Sat, 17 Oct 2026 17:37:37 +0200 Subject: [PATCH 22/23] fixed bug (python is weak, no my fault i swear) --- src/fiber_package/event/activity.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fiber_package/event/activity.py b/src/fiber_package/event/activity.py index 60fb0b8..c0aeae7 100644 --- a/src/fiber_package/event/activity.py +++ b/src/fiber_package/event/activity.py @@ -10,6 +10,7 @@ from .enums import CommunicationCategory from fiber_package.refs import SignupRefList from fiber_package.signup.signup import SignupModel from fiber_package.signup.util import validate_answer +from fiber_package.signup.enums import is_question_category from fiber_package.signup.element.form_base_question import FormBaseQuestion @@ -46,7 +47,7 @@ class ActivityModel(CommunicationModel): question_dict: dict[str, FormBaseQuestion] = {} for element in self.form: - if isinstance(element, FormTextUnion): + if not is_question_category(element.category): continue # so we know it is istance of FormBaseQuestion answerable.add(element.name) From f308f96616ef0ea41ed1ec88b838e39f88091894 Mon Sep 17 00:00:00 2001 From: Tiago Scholten Date: Sat, 17 Oct 2026 17:39:40 +0200 Subject: [PATCH 23/23] added default value for checkboxes --- src/fiber_package/signup/element/form_checkmarks.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fiber_package/signup/element/form_checkmarks.py b/src/fiber_package/signup/element/form_checkmarks.py index 36887f5..d0af93c 100644 --- a/src/fiber_package/signup/element/form_checkmarks.py +++ b/src/fiber_package/signup/element/form_checkmarks.py @@ -9,6 +9,7 @@ from fiber_package.signup.answer.answer_checkmarks import AnswerCheckmarks class CheckmarkQuestion(BaseModel): question_en: str question_nl: str + default: bool = False class FormCheckmarks(FormBaseQuestion): category: Literal[FormElementCategory.checkmarks]