Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add data retention period to event information fields #2296

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion website/events/admin/inlines.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from pizzas.models import FoodEvent


class RegistrationInformationFieldInline(admin.TabularInline):
se-bastiaan marked this conversation as resolved.
Show resolved Hide resolved
class RegistrationInformationFieldInline(admin.StackedInline):
"""The inline for registration information fields in the Event admin."""

form = RegistrationInformationFieldForm
Expand Down
10 changes: 9 additions & 1 deletion website/events/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,15 @@ def __init__(self, *args, **kwargs):
self.fields[key] = forms.CharField(required=field["required"])

self.fields[key].label = field["label"]
self.fields[key].help_text = field["description"]
if not field["description"]:
self.fields[
key
].help_text = f"{_('This data will be deleted after')} {field['delete_after']:%d-%m-%Y}."
else:
self.fields[key].help_text = (
field["description"]
+ f". {_('This data will be deleted after')} {field['delete_after']:%d-%m-%Y}."
)
self.fields[key].initial = field["value"]

def field_values(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 4.0.3 on 2022-04-15 12:22

from django.db import migrations, models
import django.utils.timezone


class Migration(migrations.Migration):

dependencies = [
('events', '0055_alter_event_no_registration_message'),
]

operations = [
migrations.AddField(
model_name='registrationinformationfield',
name='delete_after',
field=models.DateField(default=django.utils.timezone.now, help_text='The data entered in this field will automatically be deleted after this date for privacy purposes. Please choose a value, e.g. 1 month after the event.', verbose_name='delete after'),
preserve_default=False,
),
]
9 changes: 9 additions & 0 deletions website/events/models/registration_information_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ class RegistrationInformationField(models.Model):
_("required"),
)

delete_after = models.DateField(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we delete this after a predetermined time? This way it could technically be saved forever if people enter a value that is years in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also possible. The reason I opened the issue myself is because we don't have an exact policy on this, and regarding data minimization I figure that some kinds of data might have different retention times than others and this forces organizers to think about it. We could add a validator of max 3 years or something. But I'm open for discussion on this

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would personally say that 1/2-ish months after the activity ended would also be fine. So many options. As long as it is not 'unlimited'.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a constant? Or as max value?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Constant

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, as you can see (we do anonymize it, we don't delete it)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then I think 2 months after the event is over we can delete the registration info

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should keep it this way. Force people to think about what to do with this data.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it a bit our job to have thought about this for them?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, because we don't know what kind of data this is, so we are not able to make a judgement on what the retention period should be.

_("delete after"),
null=False,
blank=False,
help_text=_(
"The data entered in this field will automatically be deleted after this date for privacy purposes. Please choose a value, e.g. 1 month after the event."
),
)

def get_value_for(self, registration):
if self.type == self.TEXT_FIELD:
value_set = self.textregistrationinformation_set
Expand Down
38 changes: 34 additions & 4 deletions website/events/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
EventRegistration,
RegistrationInformationField,
Event,
TextRegistrationInformation,
IntegerRegistrationInformation,
BooleanRegistrationInformation,
)
from payments.api.v1.fields import PaymentTypeField
from payments.services import create_payment, delete_payment
Expand Down Expand Up @@ -303,6 +306,7 @@ def registration_fields(request, member=None, event=None, registration=None, nam
"description": field.description,
"value": information_field["value"],
"required": field.required,
"delete_after": field.delete_after,
}

return fields
Expand Down Expand Up @@ -359,11 +363,37 @@ def generate_category_statistics() -> dict:
def execute_data_minimisation(dry_run=False):
"""Delete information about very old events."""
# Sometimes years are 366 days of course, but better delete 1 or 2 days early than late
deletion_period = timezone.now().date() - timezone.timedelta(days=(365 * 5))
event_registration_deletion_period = timezone.now().date() - timezone.timedelta(
days=(365 * 5)
)

queryset = EventRegistration.objects.filter(event__end__lte=deletion_period).filter(
event_registrations = EventRegistration.objects.filter(
event__end__lte=event_registration_deletion_period
).filter(
Q(payment__isnull=False) | Q(member__isnull=False) | ~Q(name__exact="<removed>")
)

event_information_boolean = BooleanRegistrationInformation.objects.filter(
field__delete_after__lt=timezone.now().date()
)

event_information_integer = IntegerRegistrationInformation.objects.filter(
field__delete_after__lt=timezone.now().date()
)

event_information_text = TextRegistrationInformation.objects.filter(
field__delete_after__lt=timezone.now().date()
)

if not dry_run:
queryset.update(payment=None, member=None, name="<removed>")
return queryset.all()
event_registrations.update(payment=None, member=None, name="<removed>")
event_information_boolean.delete()
event_information_integer.delete()
event_information_text.delete()

return (
event_registrations.all(),
event_information_boolean.all(),
event_information_integer.all(),
event_information_text.all(),
)