Newer
Older
Benjamin Hättasch
committed
from django.db.models.signals import post_save, m2m_changed
from django.dispatch import receiver
from AKModel.availability.models import Availability
from AKModel.models import AK, AKSlot, Room, Event, AKOwner, ConstraintViolation
@receiver(post_save, sender=AK)
def ak_changed_handler(sender, instance: AK, **kwargs):
# Changes might affect: Owner(s), Requirements, Conflicts, Prerequisites, Category, Interest
Benjamin Hättasch
committed
pass
@receiver(m2m_changed, sender=AK.owners.through)
def ak_changed_handler(sender, instance: AK, action: str, **kwargs):
"""
Owners of AK changed
"""
# Only signal after change (post_add, post_delete, post_clear) are relevant
if not action.startswith("post"):
return
# print(f"{instance} changed")
Benjamin Hättasch
committed
# Owner(s) changed: Might affect multiple AKs by the same owner(s) at the same time
violation_type = ConstraintViolation.ViolationType.OWNER_TWO_SLOTS
new_violations = []
slots_of_this_ak: [AKSlot] = instance.akslot_set.filter(start__isnull=False)
# For all owners (after recent change)...
for owner in instance.owners.all():
Benjamin Hättasch
committed
# ...find other slots that might be overlapping...
for ak in owner.ak_set.all():
# ...find overlapping slots...
Benjamin Hättasch
committed
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
for slot in slots_of_this_ak:
for other_slot in ak.akslot_set.filter(start__isnull=False):
if slot.overlaps(other_slot):
# ...and create a temporary violation if necessary...
c = ConstraintViolation(
type=violation_type,
level=ConstraintViolation.ViolationLevel.VIOLATION,
event=event,
ak_owner=owner
)
c.aks_tmp.add(instance)
c.aks_tmp.add(other_slot.ak)
c.ak_slots_tmp.add(slot)
c.ak_slots_tmp.add(other_slot)
new_violations.append(c)
# print(f"{owner} has the following conflicts: {new_violations}")
# ... and compare to/update list of existing violations of this type
# belonging to the AK that was recently changed (important!)
existing_violations_to_check = list(instance.constraintviolation_set.filter(type=violation_type))
# print(existing_violations_to_check)
for new_violation in new_violations:
found_match = False
for existing_violation in existing_violations_to_check:
if existing_violation.matches(new_violation):
# Remove from existing violations set since it should stay in db
existing_violations_to_check.remove(existing_violation)
found_match = True
break
# Only save new violation if no match was found
if not found_match:
new_violation.save()
# Cleanup obsolete violations (ones without matches computed under current conditions)
for outdated_violation in existing_violations_to_check:
outdated_violation.delete()
@receiver(post_save, sender=AKSlot)
def akslot_changed_handler(sender, instance, **kwargs):
Benjamin Hättasch
committed
# Changes might affect: Duplicate parallel, Two in room, Resodeadline
print(f"{sender} changed")
# TODO Replace with real handling
@receiver(post_save, sender=Room)
def room_changed_handler(sender, **kwargs):
# Changes might affect: Room size, Requirement
print(f"{sender} changed")
# TODO Replace with real handling
@receiver(post_save, sender=Availability)
def availability_changed_handler(sender, **kwargs):
# Changes might affect: category availability, AK availability, Room availability
print(f"{sender} changed")
# TODO Replace with real handling
@receiver(post_save, sender=Event)
def room_changed_handler(sender, **kwargs):
# Changes might affect: Reso-Deadline
print(f"{sender} changed")
# TODO Replace with real handling