Skip to content

Commit c042f7b

Browse files
author
Tinde von Wachenfeldt
committed
Restrict pool updates to active pools
1 parent 7801052 commit c042f7b

File tree

5 files changed

+98
-18
lines changed

5 files changed

+98
-18
lines changed

lego/apps/events/models.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,9 @@ def decrement(self) -> Pool:
849849
self.save(update_fields=["counter"])
850850
return self
851851

852+
def permission_group_ids(self) -> set[int]:
853+
return set(self.permission_groups.values_list("id", flat=True))
854+
852855
@abakus_cached_property
853856
def all_permission_groups(self):
854857
groups = self.permission_groups.all()

lego/apps/events/serializers/events.py

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -454,24 +454,43 @@ def update(self, instance, validated_data):
454454
pools[0]["capacity"] = 0
455455
with transaction.atomic():
456456
if pools is not None:
457-
existing_pools = list(instance.pools.all().values_list("id", flat=True))
457+
existing_ids = set(instance.pools.values_list("id", flat=True))
458458
for pool in pools:
459459
pool_id = pool.get("id", None)
460-
if pool_id in existing_pools:
461-
existing_pools.remove(pool_id)
462460
permission_groups = pool.pop("permission_groups")
463-
created_pool = Pool.objects.update_or_create(
464-
event=instance,
465-
id=pool_id,
466-
defaults={
467-
"name": pool.get("name"),
468-
"capacity": pool.get("capacity", 0),
469-
"activation_date": pool.get("activation_date"),
470-
},
471-
)[0]
472-
created_pool.permission_groups.set(permission_groups)
473-
for pool_id in existing_pools:
474-
Pool.objects.get(id=pool_id).delete()
461+
perm_ids = [getattr(g, "id", g) for g in permission_groups]
462+
pool_instance = None
463+
if pool_id:
464+
pool_instance = (
465+
Pool.objects.filter(id=pool_id, event=instance)
466+
.select_for_update()
467+
.first()
468+
)
469+
existing_ids.discard(pool_id)
470+
pool_data = {
471+
"name": pool.get("name", getattr(pool_instance, "name", None)),
472+
"capacity": pool.get(
473+
"capacity", getattr(pool_instance, "capacity", 0)
474+
),
475+
"activation_date": pool.get(
476+
"activation_date",
477+
getattr(pool_instance, "activation_date", None),
478+
),
479+
"permission_groups": perm_ids,
480+
}
481+
ser = PoolCreateAndUpdateSerializer(
482+
instance=pool_instance,
483+
data=pool_data,
484+
context={**self.context, "event": instance},
485+
partial=True,
486+
)
487+
ser.is_valid(raise_exception=True)
488+
ser.save()
489+
if existing_ids:
490+
for p in Pool.objects.filter(
491+
event=instance, id__in=existing_ids
492+
).iterator():
493+
p.delete()
475494
return super().update(instance, validated_data)
476495

477496

lego/apps/events/serializers/pools.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,29 @@ class Meta:
9090
"registrations": {"read_only": True},
9191
}
9292

93+
def validate(self, attrs):
94+
instance = getattr(self, "instance", None)
95+
if not instance:
96+
return attrs
97+
if "permission_groups" in attrs and instance.is_activated:
98+
new_ids = {getattr(g, "id", g) for g in attrs["permission_groups"]}
99+
old_ids = instance.permission_group_ids()
100+
if new_ids != old_ids:
101+
raise serializers.ValidationError(
102+
{
103+
"permission_groups": "Permission control is disabled for active pools."
104+
}
105+
)
106+
if "activation_date" in attrs and instance.is_activated:
107+
if attrs["activation_date"] != instance.activation_date:
108+
raise serializers.ValidationError(
109+
{"activation_date": "Time travel is disabled for active pools."}
110+
)
111+
return attrs
112+
93113
def create(self, validated_data):
94-
event = Event.objects.get(pk=self.context["view"].kwargs["event_pk"])
114+
event = validated_data.pop("event", None) or self.context.get("event")
95115
permission_groups = validated_data.pop("permission_groups")
96116
pool = Pool.objects.create(event=event, **validated_data)
97117
pool.permission_groups.set(permission_groups)
98-
99118
return pool

lego/apps/events/tests/test_events_api.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,6 +1000,33 @@ def test_delete_pool_without_registrations_as_abakus(self):
10001000
pool_response = self.client.delete(_get_pools_detail_url(1, pool.id))
10011001
self.assertEqual(pool_response.status_code, status.HTTP_403_FORBIDDEN)
10021002

1003+
def test_patch_permission_groups_after_activation(self):
1004+
"""Test that change of permission group is not possible in active pool"""
1005+
AbakusGroup.objects.get(name="Bedkom").add_user(self.abakus_user)
1006+
self.client.force_authenticate(self.abakus_user)
1007+
pool = Event.objects.get(pk=1).pools.first()
1008+
new_group = AbakusGroup.objects.get(name="Webkom")
1009+
pool_response = self.client.patch(
1010+
_get_pools_detail_url(1, pool.id),
1011+
{"permissionGroups": [new_group.id]},
1012+
format="json",
1013+
)
1014+
self.assertEqual(pool_response.status_code, status.HTTP_400_BAD_REQUEST)
1015+
self.assertIn("permissionGroups", pool_response.json())
1016+
1017+
def test_patch_activation_date_after_activation(self):
1018+
"""Test that change of activation date is not possible in active pool"""
1019+
AbakusGroup.objects.get(name="Bedkom").add_user(self.abakus_user)
1020+
self.client.force_authenticate(self.abakus_user)
1021+
pool = Event.objects.get(pk=1).pools.first()
1022+
pool_response = self.client.patch(
1023+
_get_pools_detail_url(1, pool.id),
1024+
{"activationDate": timezone.now().isoformat()},
1025+
format="json",
1026+
)
1027+
self.assertEqual(pool_response.status_code, status.HTTP_400_BAD_REQUEST)
1028+
self.assertIn("activationDate", pool_response.json())
1029+
10031030

10041031
@mock.patch("lego.apps.events.views.verify_captcha", return_value=True)
10051032
class RegistrationsTransactionTestCase(BaseAPITransactionTestCase):

lego/apps/events/views.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,11 +346,23 @@ class PoolViewSet(
346346
serializer_class = PoolCreateAndUpdateSerializer
347347

348348
def get_queryset(self):
349-
event_id = self.kwargs.get("event_pk", None)
349+
event_id = self.kwargs.get("event_pk")
350350
return Pool.objects.filter(event=event_id).prefetch_related(
351351
"permission_groups", "registrations"
352352
)
353353

354+
def get_serializer_context(self):
355+
context = super().get_serializer_context()
356+
event_id = self.kwargs.get("event_pk")
357+
if event_id:
358+
context["event"] = get_object_or_404(Event, pk=event_id)
359+
return context
360+
361+
def perform_create(self, serializer):
362+
event_id = self.kwargs.get("event_pk")
363+
event = get_object_or_404(Event, pk=event_id)
364+
serializer.save(event=event)
365+
354366
def destroy(self, request, *args, **kwargs):
355367
try:
356368
return super().destroy(request, *args, **kwargs)

0 commit comments

Comments
 (0)