Skip to content

Commit

Permalink
UI og funktionalitet til at anonymisere personer og familier
Browse files Browse the repository at this point in the history
  • Loading branch information
rasmusselsmark committed Jan 12, 2025
1 parent ff95955 commit e46fa9e
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 2 deletions.
41 changes: 40 additions & 1 deletion members/admin/person_admin.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import codecs
from django import forms
from django.contrib import admin
from django.db.models import Q
from django.http import HttpResponse
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render
from django.urls import path
from django.utils.html import format_html

from members.models import (
Expand Down Expand Up @@ -60,6 +63,7 @@ class PersonAdmin(admin.ModelAdmin):
AdminActions.invite_many_to_activity_action,
"export_emaillist",
"export_csv",
"anonymize_persons",
]
raw_id_fields = ("family", "user")

Expand Down Expand Up @@ -223,6 +227,41 @@ def export_csv(self, request, queryset):

export_csv.short_description = "CSV Export"

def anonymize_persons(self, request, queryset):
class MassConfirmForm(forms.Form):
confirmation = forms.BooleanField(
label="Jeg godkender at ovenstående personer anonymiseres",
required=True,
widget=forms.CheckboxInput(attrs={'style': 'color: blue; width: unset;'})
)

persons = queryset

context = admin.site.each_context(request)
context["persons"] = persons
context["queryset"] = queryset

if request.method == "POST" and "confirmation" in request.POST:
form = MassConfirmForm(request.POST)

if form.is_valid():
context["mass_confirmation_form"] = form
for person in queryset:
person.anonymize()

self.message_user(request, "Valgte personer er blevet anonymiseret.")
return HttpResponseRedirect(request.get_full_path())

context["mass_confirmation_form"] = MassConfirmForm()

return render(
request,
"admin/anonymize_persons.html",
context,
)

anonymize_persons.short_description = "Anonymisér valgte personer"

# Only view persons related to users department (all family, via participant, waitinglist & invites)
def get_queryset(self, request):
qs = super(PersonAdmin, self).get_queryset(request)
Expand Down
23 changes: 23 additions & 0 deletions members/migrations/0064_family_anonymized_person_anonymized.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 4.2.17 on 2025-01-12 13:52

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("members", "0063_merge_20241229_1529"),
]

operations = [
migrations.AddField(
model_name="family",
name="anonymized",
field=models.BooleanField(default=False, verbose_name="Anonymiseret"),
),
migrations.AddField(
model_name="person",
name="anonymized",
field=models.BooleanField(default=False, verbose_name="Anonymiseret"),
),
]
12 changes: 12 additions & 0 deletions members/models/family.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class Meta:
confirmed_at = models.DateTimeField("Bekræftet", null=True, blank=True)
last_visit_dtm = models.DateTimeField("Sidst besøgt", null=True, blank=True)
deleted_dtm = models.DateTimeField("Slettet", null=True, blank=True)
anonymized = models.BooleanField("Anonymiseret", default=False)

def get_abosolute_url(self):
return reverse("family_form")
Expand Down Expand Up @@ -57,3 +58,14 @@ def get_persons(self):
def save(self, *args, **kwargs):
self.email = self.email.lower()
return super(Family, self).save(*args, **kwargs)

def anonymize(self):
self.email = f"anonym-{self.id}@codingpirates.dk"
self.dont_send_mails = True
self.anonymized = True
self.save()

def anonymize_if_all_persons_anonymized(self):
non_anonymized_persons_in_family = self.person_set.filter(anonymized=False)
if non_anonymized_persons_in_family.count() == 0:
self.anonymize()
37 changes: 36 additions & 1 deletion members/models/person.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import random
from django.db import models
from django.utils import timezone
from django.conf import settings
Expand Down Expand Up @@ -60,7 +61,7 @@ class Meta:
floor = models.CharField("Etage", max_length=10, blank=True)
door = models.CharField("Dør", max_length=5, blank=True)
dawa_id = models.CharField("DAWA id", max_length=200, blank=True)
municipality = municipality = models.ForeignKey(
municipality = models.ForeignKey(
Municipality,
on_delete=models.RESTRICT,
blank=True,
Expand Down Expand Up @@ -94,6 +95,7 @@ class Meta:
default=None,
)
address_invalid = models.BooleanField("Ugyldig adresse", default=False)
anonymized = models.BooleanField("Anonymiseret", default=False)

def __str__(self):
return self.name
Expand Down Expand Up @@ -189,5 +191,38 @@ def update_dawa_data(self):

# TODO: Move to dawa_data in utils

def anonymize(self):
logger.info(f"Anonymizing person {self.name}")

self.name = "Anonymiseret"
self.zipcode = ""
self.city = ""
self.streetname = ""
self.housenumber = ""
self.floor = ""
self.door = ""
self.dawa_id = ""
self.municipality = None
self.longitude = None
self.latitude = None
self.placename = ""
self.email = ""
self.phone = ""

if self.birthday:
original_birthday = self.birthday

# Make sure we don't end up with the same birthday
while self.birthday == original_birthday:
self.birthday = self.birthday.replace(day=random.randint(1, 28))

self.notes = ""
self.address_invalid = True # don't try to update address for anonymized persons
self.anonymized = True
self.save()

self.family.anonymize_if_all_persons_anonymized()


firstname.admin_order_field = "name"
firstname.short_description = "Fornavn"
82 changes: 82 additions & 0 deletions members/templates/admin/anonymize_persons.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
{% extends "admin/base_site.html" %}
{% load i18n admin_urls static admin_modify %}

{% block extrahead %}{{ block.super }}
<script type="text/javascript" src="{% url 'admin:jsi18n' %}"></script>
<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}" />
{{mass_confirmation_form.media}}
{{ media }}
{% endblock %}

{% block extrastyle %}{{ block.super }}
<script type="text/javascript" src="{% static "admin/js/core.js" %}"></script>
<script type="text/javascript" src="{% static "admin/js/vendor/jquery/jquery.min.js" %}"></script>
<script type="text/javascript" src="{% static "admin/js/jquery.init.js" %}"></script>
{% endblock %}

{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
&rsaquo; <a href="{% url 'admin:app_list' 'members' %}">Members</a>
&rsaquo; <a href="">Personer</a>
</div>
{% endblock %}

{% block content_title %}<h1>Anonymisér person(er)</h1>{% endblock %}

{% block content %}
<div id="content-main">
<form action="" method="post">
<div>
<fieldset class="module aligned">
<h2>VIGTIGT!</h2>
<div class="description">
<p><b>Du er ved at anonymisere én eller flere personer.</b></p>
<p>Dette betyder at de fleste informationer om personen slettes, primært bevares information
om vedkommendes kommune, således at der stadig vil kunne trækkes statistik ud senere.</p>
</div>

{% csrf_token %}
<input type="hidden" name="action" value="anonymize_persons">
<input type="hidden" name="select_across" value="0">
<input type="hidden" name="index" value="0">
{% for obj in queryset %}
<input type="hidden" name="_selected_action" value="{{ obj.pk }}" />
{% endfor %}

<h2>Bekræft person(er)</h2>
<div class="description">
<p>Følgende ({{persons.count}}) personer vil blive anonymiseret:</p>
<p>
<ul>
{% for person in persons %}
<li>{{person.name}}</li>
{% endfor %}
</ul>
</p>
<p style="color: red; font-weight: bold; font-size: large;">Dette kan ikke fortrydes!</p>
</div>

<div class="submit-row">
<input type="checkbox" id="id_confirmation" name="confirmation" value="1" required>
<label name="confirmation" for="id_confirmation" style="width: unset">Jeg godkender at ovenstående personer anonymiseres</label>
</input>
</div>

<div class="submit-row">
<p class="deletelink-box"><a href="#" id="abort" class="deletelink">Fortryd</a></p>
<p><input class="default" style="background-color: rgb(199, 183, 0); color: black; float: right;" type="submit" value="Anonymisér"></p>
</div>
</fieldset>
</div>
</form>

</div>

<script type="text/javascript">
document.getElementById("abort").addEventListener("click", () => {
history.back();
});
</script>

{% endblock %}

0 comments on commit e46fa9e

Please sign in to comment.