From 99fe8bd23c8dbe4599fa5639d75c0789f74305ba Mon Sep 17 00:00:00 2001 From: Findeton Date: Wed, 14 Jan 2026 19:50:45 +0100 Subject: [PATCH 1/3] wip --- iam/api/views.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/iam/api/views.py b/iam/api/views.py index a075f00c..389fee91 100644 --- a/iam/api/views.py +++ b/iam/api/views.py @@ -2046,8 +2046,28 @@ def delete(request, pk): permission_required(request.user, 'AuthEvent', ['edit', 'delete'], pk) ae = AuthEvent.objects.get(pk=pk) + + # Collect all election IDs that will be deleted (parent + children via CASCADE) + election_ids_to_cleanup = [str(pk)] + + # If this is a virtual election with children, collect their IDs too + # (they will be CASCADE deleted by Django, but their ACLs won't be) + if ae.children_election_info: + children_ids = ae.children_election_info.get('natural_order', []) + election_ids_to_cleanup.extend([str(child_id) for child_id in children_ids]) + + # Delete the AuthEvent (and CASCADE delete children) ae.delete() + # Manually delete orphaned ACLs for all affected elections + deleted_acls = ACL.objects.filter( + object_type='AuthEvent', + object_id__in=election_ids_to_cleanup + ).delete() + + if deleted_acls[0] > 0: + print(f"Deleted {deleted_acls[0]} orphaned ACL records for elections {election_ids_to_cleanup}") + data = {'status': 'ok'} return json_response(data) authevent = AuthEventView.as_view() From 4749e508edbc232ffdd27617be7a3fea11955a0e Mon Sep 17 00:00:00 2001 From: Findeton Date: Thu, 15 Jan 2026 19:58:21 +0100 Subject: [PATCH 2/3] wip --- iam/api/views.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/iam/api/views.py b/iam/api/views.py index 389fee91..4d4786af 100644 --- a/iam/api/views.py +++ b/iam/api/views.py @@ -2050,11 +2050,17 @@ def delete(request, pk): # Collect all election IDs that will be deleted (parent + children via CASCADE) election_ids_to_cleanup = [str(pk)] - # If this is a virtual election with children, collect their IDs too - # (they will be CASCADE deleted by Django, but their ACLs won't be) + # Collect children IDs using Django's ForeignKey relationship + # (children have parent=ae and will be CASCADE deleted) + children_from_fk = list(ae.children.values_list('id', flat=True)) + election_ids_to_cleanup.extend([str(child_id) for child_id in children_from_fk]) + + # Also check children_election_info JSONField as fallback if ae.children_election_info: children_ids = ae.children_election_info.get('natural_order', []) - election_ids_to_cleanup.extend([str(child_id) for child_id in children_ids]) + for child_id in children_ids: + if str(child_id) not in election_ids_to_cleanup: + election_ids_to_cleanup.append(str(child_id)) # Delete the AuthEvent (and CASCADE delete children) ae.delete() From 57618668287d640da3a0843b875aee86526be6ce Mon Sep 17 00:00:00 2001 From: Findeton Date: Sat, 17 Jan 2026 09:43:38 +0100 Subject: [PATCH 3/3] wip --- iam/api/views.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/iam/api/views.py b/iam/api/views.py index 4d4786af..3fa4a6f2 100644 --- a/iam/api/views.py +++ b/iam/api/views.py @@ -3422,7 +3422,7 @@ def post(request, pk=None): return json_response( status=400, error_codename=ErrorCodes.BAD_REQUEST) - + for election_id in election_ids: try: permission_required(request.user, 'AuthEvent', ['edit', 'delete'], election_id) @@ -3430,6 +3430,10 @@ def post(request, pk=None): election_obj = AuthEvent.objects.get(pk=election_id) children_pks = [child.id for child in election_obj.children.all()] children_pks.append(election_obj.id) + + # Collect all election IDs for ACL cleanup (as strings) + election_ids_to_cleanup = [str(pk) for pk in children_pks] + # delete event and children in ballot box: for pk in children_pks: try: @@ -3460,7 +3464,7 @@ def post(request, pk=None): "ballot_box_request.text '%r'\n", pk, ballot_box_url, - ballot_box_request.status_code, + ballot_box_request.status_code, ballot_box_request.text ) if ballot_box_request.status_code != 200: @@ -3470,12 +3474,23 @@ def post(request, pk=None): ) except Exception as err: print(f"Exception deleting child {pk} for election {election_id}: {err}") - + election_obj.delete() + + # Manually delete orphaned ACLs for all affected elections + deleted_acls = ACL.objects.filter( + object_type='AuthEvent', + object_id__in=election_ids_to_cleanup + ).delete() + + if deleted_acls[0] > 0: + LOGGER.info( + f"Deleted {deleted_acls[0]} orphaned ACL records for elections {election_ids_to_cleanup}" + ) except Exception as err: print(f"Exception deleting election {election_id}: {err}") - - + + data = {'status': 'ok'} return json_response(data)