diff --git a/ephios/core/models/events.py b/ephios/core/models/events.py index 844937ef7..9d4595265 100644 --- a/ephios/core/models/events.py +++ b/ephios/core/models/events.py @@ -263,7 +263,9 @@ class Shift(DatetimeDisplayMixin, Model): structure_slug = SlugField(_("structure")) structure_configuration = JSONField( - default=dict, encoder=CustomJSONEncoder, decoder=CustomJSONDecoder + default=dict, + encoder=CustomJSONEncoder, + decoder=CustomJSONDecoder, ) class Meta: @@ -272,7 +274,7 @@ class Meta: ordering = ("meeting_time", "start_time", "id") db_table = "shift" - @property + @cached_property def signup_flow(self) -> "AbstractSignupFlow": from ephios.core.signup.flow import signup_flow_from_slug @@ -304,6 +306,28 @@ def structure(self) -> "AbstractShiftStructure": return FallbackShiftStructure(self, event=event) + def _clear_cached_signup_objects(self): + """ + when changing data on the shift, cached info in the signup flow or structure might become outdated, + so we clear the cached versions. (most relevant to tests, as we use new instances every request) + """ + try: + del self.structure + except AttributeError: + pass + try: + del self.signup_flow + except AttributeError: + pass + + def save(self, *args, **kwargs): + self._clear_cached_signup_objects() + return super().save(*args, **kwargs) + + def refresh_from_db(self, using=None, fields=None): + self._clear_cached_signup_objects() + return super().refresh_from_db(using, fields) + def get_participants(self, with_state_in=frozenset({AbstractParticipation.States.CONFIRMED})): for participation in self.participations.filter(state__in=with_state_in): yield participation.participant diff --git a/ephios/core/services/matching.py b/ephios/core/services/matching.py index aa70b8c16..51f55c091 100644 --- a/ephios/core/services/matching.py +++ b/ephios/core/services/matching.py @@ -18,7 +18,7 @@ class Position: designated_for: Collection[AbstractParticipant] # designated by disposition preferred_by: Collection[AbstractParticipant] # preferred by participant (less important) label: Optional[str] = None - aux_score: float = 0.0 # additional score control + aux_score: float = 0.0 # additional score control in range [0,1] def __post_init__(self): self.required_qualifications = frozenset(self.required_qualifications) diff --git a/ephios/core/signup/flow/participant_validation.py b/ephios/core/signup/flow/participant_validation.py index bd18fdc08..930d2b2d4 100644 --- a/ephios/core/signup/flow/participant_validation.py +++ b/ephios/core/signup/flow/participant_validation.py @@ -11,6 +11,9 @@ class BaseSignupError(Exception): """Superclass of errors used in the signup mechanism.""" + def __init__(self, message): + self.message = message + class SignupDisallowedError(BaseSignupError): """ diff --git a/ephios/plugins/complexsignup/structure.py b/ephios/plugins/complexsignup/structure.py index eb5e06aaa..70a61c288 100644 --- a/ephios/plugins/complexsignup/structure.py +++ b/ephios/plugins/complexsignup/structure.py @@ -359,6 +359,7 @@ def _search_block( preferred_by=preferred_by, required=required, label=label, + aux_score=1, ) participation = matching.participation_for_position(match_id) if matching else None signup_stats += SignupStats.ZERO.replace( diff --git a/ephios/settings.py b/ephios/settings.py index 2ff9c5381..da6e4436c 100644 --- a/ephios/settings.py +++ b/ephios/settings.py @@ -466,3 +466,8 @@ def GET_SITE_URL(): if env.bool("TRUST_X_FORWARDED_PROTO", default=False): SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") + +# Transitional/deprecated settings +FORMS_URLFIELD_ASSUME_HTTPS = ( + True # https://docs.djangoproject.com/en/5.1/ref/settings/#forms-urlfield-assume-https +) diff --git a/tests/core/services/test_matching.py b/tests/core/services/test_matching.py index 24cbfdadc..74f736347 100644 --- a/tests/core/services/test_matching.py +++ b/tests/core/services/test_matching.py @@ -7,8 +7,8 @@ def test_match_participants_to_positions(qualifications): # create 3 participants ann = PlaceholderParticipant("Ann", {qualifications.nfs}, None, None) ben = PlaceholderParticipant("Ben", {qualifications.rs, qualifications.ce}, None, None) - leader = Position("Führer", True, {qualifications.nfs}, []) - driver = Position("Fahrer", True, {qualifications.rs, qualifications.c}, []) + leader = Position("Führer", True, {qualifications.nfs}, [], []) + driver = Position("Fahrer", True, {qualifications.rs, qualifications.c}, [], []) assert match_participants_to_positions([], []).pairings == set() assert match_participants_to_positions([ben], []).pairings == set() @@ -51,10 +51,10 @@ def test_maximise_number_of_matches_in_adverse_case(): z = PlaceholderParticipant("Z", {q_d}, None, None) positions = [ - Position("A", False, {q_a}, []), - Position("B", False, {q_b}, [w]), - Position("C", False, {q_c}, [x]), - Position("D", False, {q_d}, [y]), + Position("A", False, {q_a}, [], []), + Position("B", False, {q_b}, [], [w]), + Position("C", False, {q_c}, [], [x]), + Position("D", False, {q_d}, [], [y]), ] participants = [w, x, y, z]