Skip to content
Snippets Groups Projects
Commit 22476850 authored by Felix Blanke's avatar Felix Blanke Committed by Felix Blanke
Browse files

Address findings

parent 5d7e5b91
No related branches found
No related tags found
2 merge requests!22Feature: Preference polling form,!18Prepare tool for preference polling
Pipeline #279864 passed
...@@ -574,6 +574,9 @@ class DefaultSlotAdmin(EventTimezoneFormMixin, admin.ModelAdmin): ...@@ -574,6 +574,9 @@ class DefaultSlotAdmin(EventTimezoneFormMixin, admin.ModelAdmin):
@admin.register(EventParticipant) @admin.register(EventParticipant)
class EventParticipantAdmin(PrepopulateWithNextActiveEventMixin, admin.ModelAdmin): class EventParticipantAdmin(PrepopulateWithNextActiveEventMixin, admin.ModelAdmin):
"""
Admin interface for EventParticipant
"""
model = EventParticipant model = EventParticipant
list_display = ['name', 'institution', 'event'] list_display = ['name', 'institution', 'event']
list_filter = ['event', 'institution'] list_filter = ['event', 'institution']
...@@ -583,7 +586,7 @@ class EventParticipantAdmin(PrepopulateWithNextActiveEventMixin, admin.ModelAdmi ...@@ -583,7 +586,7 @@ class EventParticipantAdmin(PrepopulateWithNextActiveEventMixin, admin.ModelAdmi
class AKPreferenceAdminForm(forms.ModelForm): class AKPreferenceAdminForm(forms.ModelForm):
""" """
Adapted admin form for constraint violations for usage in :class:`ConstraintViolationAdmin`) Adapted admin form for AK preferences for usage in :class:`AKPreferenceAdmin`)
""" """
class Meta: class Meta:
widgets = { widgets = {
...@@ -601,6 +604,10 @@ class AKPreferenceAdminForm(forms.ModelForm): ...@@ -601,6 +604,10 @@ class AKPreferenceAdminForm(forms.ModelForm):
@admin.register(AKPreference) @admin.register(AKPreference)
class AKPreferenceAdmin(PrepopulateWithNextActiveEventMixin, admin.ModelAdmin): class AKPreferenceAdmin(PrepopulateWithNextActiveEventMixin, admin.ModelAdmin):
"""
Admin interface for AK preferences.
Uses an adapted form (see :class:`AKPreferenceAdminForm`)
"""
model = AKPreference model = AKPreference
form = AKPreferenceAdminForm form = AKPreferenceAdminForm
list_display = ['preference', 'participant', 'slot', 'event'] list_display = ['preference', 'participant', 'slot', 'event']
......
...@@ -99,11 +99,29 @@ class Availability(models.Model): ...@@ -99,11 +99,29 @@ class Availability(models.Model):
event = getattr(getattr(self, 'event', None), 'name', None) event = getattr(getattr(self, 'event', None), 'name', None)
ak = getattr(self.ak, 'name', None) ak = getattr(self.ak, 'name', None)
ak_category = getattr(self.ak_category, 'name', None) ak_category = getattr(self.ak_category, 'name', None)
return f'Availability(event={event}, person={person}, room={room}, ak={ak}, ak category={ak_category}, participant={participant})' arg_list = [
f"event={event}",
f"person={person}",
f"room={room}",
f"ak={ak}",
f"ak category={ak_category}",
f"participant={participant}",
]
return f'Availability({", ".join(arg_list)})'
def __hash__(self): def __hash__(self):
return hash( return hash(
(getattr(self, 'event', None), self.person, self.room, self.ak, self.ak_category, self.participant, self.start, self.end)) (
getattr(self, 'event', None),
self.person,
self.room,
self.ak,
self.ak_category,
self.participant,
self.start,
self.end,
)
)
def __eq__(self, other: 'Availability') -> bool: def __eq__(self, other: 'Availability') -> bool:
"""Comparisons like ``availability1 == availability2``. """Comparisons like ``availability1 == availability2``.
......
...@@ -560,7 +560,7 @@ class Event(models.Model): ...@@ -560,7 +560,7 @@ class Event(models.Model):
rooms = Room.objects.filter(event=self).order_by() rooms = Room.objects.filter(event=self).order_by()
slots = AKSlot.objects.filter(event=self).order_by() slots = AKSlot.objects.filter(event=self).order_by()
participants = EventParticipant.objects.filter(event=self).order_by() participants = EventParticipant.objects.filter(event=self).order_by()
owners = AKOwner.objects.filter(event=self.event).order_by().all() owners = AKOwner.objects.filter(event=self).order_by().all()
ak_availabilities = { ak_availabilities = {
ak.pk: Availability.union(ak.availabilities.all()) ak.pk: Availability.union(ak.availabilities.all())
...@@ -576,7 +576,7 @@ class Event(models.Model): ...@@ -576,7 +576,7 @@ class Event(models.Model):
} }
participant_availabilities = { participant_availabilities = {
participant.pk: Availability.union(participant.availabilities.all()) participant.pk: Availability.union(participant.availabilities.all())
for participant in EventParticipant.objects.filter(event=self.event) for participant in EventParticipant.objects.filter(event=self)
} }
blocks = list(self.discretize_timeslots()) blocks = list(self.discretize_timeslots())
...@@ -627,7 +627,7 @@ class Event(models.Model): ...@@ -627,7 +627,7 @@ class Event(models.Model):
# add fulfilled time constraints for all participants that are not available for full event # add fulfilled time constraints for all participants that are not available for full event
time_constraints.extend( time_constraints.extend(
self._generate_time_constraints("participant", participant_availabilities, timeslot.avail) _generate_time_constraints("participant", participant_availabilities, timeslot.avail)
) )
# add fulfilled time constraints for all AKSlots fixed to happen during timeslot # add fulfilled time constraints for all AKSlots fixed to happen during timeslot
...@@ -639,6 +639,7 @@ class Event(models.Model): ...@@ -639,6 +639,7 @@ class Event(models.Model):
time_constraints.extend(timeslot.constraints) time_constraints.extend(timeslot.constraints)
time_constraints.extend(block_timeconstraints) time_constraints.extend(block_timeconstraints)
time_constraints.sort()
current_block.append({ current_block.append({
"id": timeslot.idx, "id": timeslot.idx,
...@@ -646,7 +647,7 @@ class Event(models.Model): ...@@ -646,7 +647,7 @@ class Event(models.Model):
"start": timeslot.avail.start.astimezone(self.timezone).strftime("%Y-%m-%d %H:%M"), "start": timeslot.avail.start.astimezone(self.timezone).strftime("%Y-%m-%d %H:%M"),
"end": timeslot.avail.end.astimezone(self.timezone).strftime("%Y-%m-%d %H:%M"), "end": timeslot.avail.end.astimezone(self.timezone).strftime("%Y-%m-%d %H:%M"),
}, },
"fulfilled_time_constraints": sorted(time_constraints), "fulfilled_time_constraints": time_constraints,
}) })
timeslots["blocks"].append(current_block) timeslots["blocks"].append(current_block)
...@@ -670,18 +671,14 @@ class Event(models.Model): ...@@ -670,18 +671,14 @@ class Event(models.Model):
"aks": [ak.as_json_dict() for ak in slots], "aks": [ak.as_json_dict() for ak in slots],
} }
event_ak_slots = AKSlot.objects.filter(event=self.event)
if EventParticipant.objects.exists(): if EventParticipant.objects.exists():
next_participant_pk = EventParticipant.objects.latest("pk").pk + 1 next_participant_pk = EventParticipant.objects.latest("pk").pk + 1
else: else:
next_participant_pk = 1 next_participant_pk = 1
# add one dummy participant per owner # add one dummy participant per owner
# this ensures that the hard constraints from each owner are considered # this ensures that the hard constraints from each owner are considered
for new_pk, owner in enumerate( for new_pk, owner in enumerate(owners, next_participant_pk):
owners, owned_slots = slots.filter(ak__owners=owner).order_by().all()
next_participant_pk,
):
owned_slots = event_ak_slots.filter(ak__owners=owner).all()
if not owned_slots: if not owned_slots:
continue continue
new_participant_data = { new_participant_data = {
...@@ -695,6 +692,7 @@ class Event(models.Model): ...@@ -695,6 +692,7 @@ class Event(models.Model):
] ]
} }
data["participants"].append(new_participant_data) data["participants"].append(new_participant_data)
return data
class AKOwner(models.Model): class AKOwner(models.Model):
...@@ -1128,8 +1126,7 @@ class Room(models.Model): ...@@ -1128,8 +1126,7 @@ class Room(models.Model):
"name": self.name, "name": self.name,
}, },
"capacity": self.capacity, "capacity": self.capacity,
"fulfilled_room_constraints": [constraint.name "fulfilled_room_constraints": list(self.properties.values_list("name", flat=True)),
for constraint in self.properties.all()],
"time_constraints": time_constraints "time_constraints": time_constraints
} }
...@@ -1275,20 +1272,14 @@ class AKSlot(models.Model): ...@@ -1275,20 +1272,14 @@ class AKSlot(models.Model):
"id": self.pk, "id": self.pk,
"duration": math.ceil(self.duration / self.event.export_slot - ceil_offet_eps), "duration": math.ceil(self.duration / self.event.export_slot - ceil_offet_eps),
"properties": { "properties": {
"conflicts": "conflicts": list((conflict_slots | other_ak_slots).values_list("pk", flat=True).order_by()),
sorted( "dependencies": list(dependency_slots.values_list("pk", flat=True).order_by()),
[conflict.pk for conflict in conflict_slots.all()]
+ [second_slot.pk for second_slot in other_ak_slots.all()]
),
"dependencies": sorted([dep.pk for dep in dependency_slots.all()]),
}, },
"room_constraints": [constraint.name "room_constraints": list(self.ak.requirements.values_list("name", flat=True).order_by()),
for constraint in self.ak.requirements.all()],
"time_constraints": ["resolution"] if self.ak.reso else [], "time_constraints": ["resolution"] if self.ak.reso else [],
"info": { "info": {
"name": self.ak.name, "name": self.ak.name,
"head": ", ".join([str(owner) "head": ", ".join([str(owner) for owner in self.ak.owners.order_by().all()]),
for owner in self.ak.owners.all()]),
"description": self.ak.description, "description": self.ak.description,
"reso": self.ak.reso, "reso": self.ak.reso,
"duration_in_hours": float(self.duration), "duration_in_hours": float(self.duration),
...@@ -1662,14 +1653,14 @@ class EventParticipant(models.Model): ...@@ -1662,14 +1653,14 @@ class EventParticipant(models.Model):
data = { data = {
"id": self.pk, "id": self.pk,
"info": {"name": str(self)}, "info": {"name": str(self)},
"room_constraints": [constraint.name for constraint in self.requirements.all()], "room_constraints": list(self.requirements.values_list("name", flat=True).order_by()),
"time_constraints": [], "time_constraints": [],
} }
data["preferences"] = [ data["preferences"] = [
pref.as_json_dict() pref.as_json_dict()
for pref in AKPreference.objects.filter( for pref in AKPreference.objects.filter(
participant=self, preference__gt=0 participant=self, preference__gt=0
).select_related("slot") ).select_related("slot").order_by()
] ]
avails = self.availabilities.all() avails = self.availabilities.all()
...@@ -1683,6 +1674,7 @@ class EventParticipant(models.Model): ...@@ -1683,6 +1674,7 @@ class EventParticipant(models.Model):
# partipant is actually required for AKs # partipant is actually required for AKs
data["time_constraints"].append(f"availability-participant-{self.pk}") data["time_constraints"].append(f"availability-participant-{self.pk}")
data["time_constraints"].sort()
return data return data
......
...@@ -62,7 +62,10 @@ class JSONExportTest(TestCase): ...@@ -62,7 +62,10 @@ class JSONExportTest(TestCase):
self.ak_slots: Iterable[AKSlot] = [] self.ak_slots: Iterable[AKSlot] = []
self.rooms: Iterable[Room] = [] self.rooms: Iterable[Room] = []
self.participants: Iterable[EventParticipant] = []
self.owners: Iterable[AKOwner] = []
self.slots_in_an_hour: float = 1.0 self.slots_in_an_hour: float = 1.0
self.max_participant_pk = 0
self.event: Event | None = None self.event: Event | None = None
def set_up_event(self, event: Event) -> None: def set_up_event(self, event: Event) -> None:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment