Skip to content

Commit 2d82e62

Browse files
committed
fix: update person retention period deletion logic
Update person retention period deletion logic to return persons who: 1. Don't have a user account 2. Don't have any valid enrolments 3. Don't have any valid event queue enrolments Add tests. Refs: PT-1946
1 parent c8fffac commit 2d82e62

2 files changed

Lines changed: 114 additions & 18 deletions

File tree

organisations/models.py

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from django.contrib.auth.models import UserManager
99
from django.contrib.postgres.fields import ArrayField
1010
from django.db import models, router, transaction
11-
from django.db.models import Max, Q
11+
from django.db.models import Q
1212
from django.db.models.deletion import Collector
1313
from django.utils import timezone
1414
from django.utils.translation import gettext_lazy as _
@@ -37,29 +37,51 @@ def user_can_view(self, user):
3737
return self.none()
3838

3939
def retention_period_exceeded(self):
40+
"""
41+
Return queryset of Person objects whose personal data
42+
retention period has exceeded.
43+
44+
This excludes:
45+
- Persons with a user account
46+
- Persons with any valid (recent) enrolments
47+
"""
4048
earliest_valid_timestamp = timezone.now() - relativedelta(
4149
months=settings.PERSONAL_DATA_RETENTION_PERIOD_MONTHS
4250
)
4351

44-
all_enrolments_too_old = Q(max_enrolment_end_time=None) | Q(
45-
max_enrolment_end_time__lt=earliest_valid_timestamp
46-
)
47-
all_study_groups_too_old = Q(max_studygroup_end_time=None) | Q(
48-
max_studygroup_end_time__lt=earliest_valid_timestamp
49-
)
50-
51-
return (
52-
# At least for now returns only unauthenticated Person's
53-
self.filter(user=None)
54-
.annotate(
55-
max_enrolment_end_time=Max("enrolment__occurrence__end_time"),
56-
max_studygroup_end_time=Max(
57-
"studygroup__enrolments__occurrence__end_time"
58-
),
52+
# Find persons with any valid enrolments or
53+
# event queue enrolments (as person or study group contact)
54+
valid_enrolment_persons = self.filter(
55+
Q(enrolment__occurrence__end_time__gt=earliest_valid_timestamp)
56+
| Q(
57+
studygroup__enrolments__occurrence__end_time__gt=earliest_valid_timestamp
58+
)
59+
| Q(
60+
eventqueueenrolment__p_event__occurrences__end_time__gt=earliest_valid_timestamp
61+
)
62+
).distinct()
63+
64+
# Return persons who:
65+
# 1. Don't have a user account
66+
# 2. Don't have any valid enrolments (either as person or study group contact)
67+
# 3. Don't have any valid event queue enrolments
68+
old_enrolment_filter = (
69+
Q(enrolment__occurrence__end_time__lte=earliest_valid_timestamp)
70+
| Q(enrolment__occurrence__end_time__isnull=True)
71+
| Q(
72+
studygroup__enrolments__occurrence__end_time__lte=earliest_valid_timestamp
5973
)
60-
.filter(all_enrolments_too_old & all_study_groups_too_old)
74+
| Q(studygroup__enrolments__occurrence__end_time__isnull=True)
75+
| Q(
76+
eventqueueenrolment__p_event__occurrences__end_time__lte=earliest_valid_timestamp
77+
)
78+
| Q(eventqueueenrolment__p_event__occurrences__end_time__isnull=True)
6179
)
6280

81+
persons = self.filter(user__isnull=True).filter(old_enrolment_filter)
82+
persons = persons.exclude(id__in=valid_enrolment_persons.values("id"))
83+
return persons.distinct()
84+
6385
@transaction.atomic
6486
def delete(self):
6587
for obj in self:

organisations/tests/test_models.py

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@
44
from django.db import IntegrityError
55
from django.utils import timezone
66

7-
from occurrences.factories import EnrolmentFactory, PalvelutarjotinEventFactory
7+
from occurrences.factories import (
8+
EnrolmentFactory,
9+
EventQueueEnrolmentFactory,
10+
OccurrenceFactory,
11+
PalvelutarjotinEventFactory,
12+
)
813
from organisations.factories import (
914
OrganisationFactory,
1015
OrganisationProposalFactory,
@@ -210,6 +215,75 @@ def test_too_old_personal_data(mock_get_event_data):
210215
assert all(person in results for person in expected_people)
211216

212217

218+
@pytest.mark.django_db
219+
def test_old_personal_data_deletion_with_valid_enrolments(mock_get_event_data):
220+
too_old = timezone.now() - relativedelta(months=24, days=1)
221+
still_valid = timezone.now() - relativedelta(days=1)
222+
223+
(
224+
enrolment_person,
225+
study_group_person,
226+
enrolment_and_study_group_person,
227+
no_enrolment_or_study_group_person,
228+
event_queue_enrolment_person,
229+
event_queue_study_group_person,
230+
) = PersonFactory.create_batch(6, user=None)
231+
232+
# person with a too old enrolment
233+
EnrolmentFactory(person=enrolment_person, occurrence__end_time=too_old)
234+
235+
# person with a too old study group
236+
EnrolmentFactory(
237+
study_group__person=study_group_person, occurrence__end_time=too_old
238+
)
239+
240+
# person with too old enrolment and study group
241+
EnrolmentFactory(
242+
person=enrolment_and_study_group_person,
243+
study_group__person=enrolment_and_study_group_person,
244+
occurrence__end_time=too_old,
245+
)
246+
247+
too_old_p_event = PalvelutarjotinEventFactory()
248+
OccurrenceFactory(end_time=too_old, p_event=too_old_p_event)
249+
250+
EventQueueEnrolmentFactory(
251+
person=event_queue_enrolment_person, p_event=too_old_p_event
252+
)
253+
EventQueueEnrolmentFactory(
254+
study_group__person=event_queue_study_group_person,
255+
p_event=too_old_p_event,
256+
)
257+
258+
valid_p_event = PalvelutarjotinEventFactory()
259+
OccurrenceFactory(end_time=still_valid, p_event=valid_p_event)
260+
# valid event queue enrolment for the event queue enrolment person
261+
EventQueueEnrolmentFactory(
262+
person=event_queue_enrolment_person, p_event=valid_p_event
263+
)
264+
265+
# valid enrolment for the enrolment person
266+
EnrolmentFactory(person=enrolment_person, occurrence__end_time=still_valid)
267+
# valid enrolment for the study group person
268+
EnrolmentFactory(
269+
study_group__person=study_group_person, occurrence__end_time=still_valid
270+
)
271+
# valid enrolment for the event queue enrolment person
272+
EventQueueEnrolmentFactory(
273+
person=event_queue_enrolment_person, p_event=too_old_p_event
274+
)
275+
# valid enrolment for the event queue study group person
276+
EventQueueEnrolmentFactory(
277+
study_group__person=event_queue_study_group_person, p_event=too_old_p_event
278+
)
279+
# person with a user
280+
PersonFactory(user=UserFactory())
281+
282+
# only the person without any enrolments should be in the results
283+
results = Person.objects.retention_period_exceeded()
284+
assert len(results) == 3
285+
286+
213287
@pytest.mark.django_db
214288
@pytest.mark.parametrize("delete_via_queryset", (False, True))
215289
def test_user_deletion_deletes_palvelutarjotin_event_contact_info(delete_via_queryset):

0 commit comments

Comments
 (0)