Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
thalia
concrexit
Commits
5b179b40
Commit
5b179b40
authored
Mar 06, 2019
by
Luko van der Maas
Browse files
Merge branch 'feature/manual-data-minimisation' into 'master'
Add manual data minimisation functionality See merge request
!1189
parents
ef676998
4a5d8b29
Changes
3
Hide whitespace changes
Inline
Side-by-side
website/members/admin.py
View file @
5b179b40
...
...
@@ -3,7 +3,7 @@ This module registers admin pages for the models
"""
import
csv
import
datetime
from
django.contrib
import
admin
from
django.contrib
import
admin
,
messages
from
django.contrib.auth.admin
import
UserAdmin
as
BaseUserAdmin
from
django.contrib.auth.models
import
User
from
django.db.models
import
Q
...
...
@@ -11,7 +11,8 @@ from django.http import HttpResponse
from
django.utils
import
timezone
from
django.utils.translation
import
ugettext_lazy
as
_
from
members.models
import
EmailChange
from
members
import
services
from
members.models
import
EmailChange
,
Member
from
.
import
forms
,
models
...
...
@@ -93,7 +94,7 @@ class UserAdmin(BaseUserAdmin):
add_form
=
forms
.
UserCreationForm
actions
=
[
'address_csv_export'
,
'student_number_csv_export'
,
'email_csv_export'
]
'email_csv_export'
,
'minimise_data'
]
inlines
=
(
ProfileInline
,
MembershipInline
,)
list_filter
=
(
MembershipTypeListFilter
,
...
...
@@ -161,6 +162,25 @@ class UserAdmin(BaseUserAdmin):
student_number_csv_export
.
short_description
=
_
(
'Download student number '
'label for selected users'
)
def
minimise_data
(
self
,
request
,
queryset
):
processed
=
len
(
services
.
execute_data_minimisation
(
members
=
Member
.
objects
.
filter
(
pk__in
=
queryset
)))
if
processed
==
0
:
self
.
message_user
(
request
,
_
(
'Data minimisation could not be executed '
'for the selected user(s).'
),
messages
.
ERROR
)
else
:
self
.
message_user
(
request
,
_
(
'Data minimisation was executed '
'for {} user(s).'
).
format
(
processed
),
messages
.
SUCCESS
)
minimise_data
.
short_description
=
_
(
'Minimise data for the selected users'
)
@
admin
.
register
(
models
.
Member
)
class
MemberAdmin
(
UserAdmin
):
...
...
website/members/services.py
View file @
5b179b40
from
datetime
import
date
from
django.db.models
import
Q
from
django.db.models
import
Q
,
Count
from
django.utils
import
timezone
from
django.utils.translation
import
gettext
...
...
@@ -164,17 +164,21 @@ def process_email_change(change_request):
emails
.
send_email_change_completion_message
(
change_request
)
def
execute_data_minimisation
(
dry_run
=
False
):
def
execute_data_minimisation
(
dry_run
=
False
,
members
=
None
):
"""
Clean the profiles of members/users of whom the last membership ended
at least 31 days ago
:param dry_run: does not really remove data if True
:param members: queryset of members to process, optional
:return: list of processed members
"""
members
=
(
Member
.
objects
.
exclude
(
Q
(
membership__until__isnull
=
True
)
|
Q
(
membership__until__gt
=
timezone
.
now
().
date
()))
if
not
members
:
members
=
Member
.
objects
members
=
(
members
.
annotate
(
membership_count
=
Count
(
'membership'
))
.
exclude
((
Q
(
membership__until__isnull
=
True
)
|
Q
(
membership__until__gt
=
timezone
.
now
().
date
()))
&
Q
(
membership_count__gt
=
0
))
.
distinct
()
.
prefetch_related
(
'membership_set'
,
'profile'
))
deletion_period
=
timezone
.
now
().
date
()
-
timezone
.
timedelta
(
days
=
31
)
...
...
website/members/tests/test_services.py
View file @
5b179b40
...
...
@@ -224,77 +224,107 @@ class DataMinimisationTest(TestCase):
@
classmethod
def
setUpTestData
(
cls
):
cls
.
m
ember
=
Member
.
objects
.
create
(
cls
.
m
1
=
Member
.
objects
.
create
(
username
=
'test1'
,
first_name
=
'Test1'
,
last_name
=
'Example'
,
email
=
'test1@example.org'
)
Profile
.
objects
.
create
(
user
=
cls
.
m
ember
,
user
=
cls
.
m
1
,
language
=
'nl'
,
student_number
=
's1234567'
)
cls
.
membership
=
Membership
.
objects
.
create
(
user
=
cls
.
member
,
cls
.
s1
=
Membership
.
objects
.
create
(
user
=
cls
.
m1
,
type
=
Membership
.
MEMBER
,
since
=
timezone
.
now
().
replace
(
year
=
2017
,
month
=
9
,
day
=
1
),
until
=
timezone
.
now
().
replace
(
year
=
2018
,
month
=
9
,
day
=
1
)
)
cls
.
m2
=
Member
.
objects
.
create
(
username
=
'test2'
,
first_name
=
'Test2'
,
last_name
=
'Example'
,
email
=
'test2@example.org'
)
Profile
.
objects
.
create
(
user
=
cls
.
m2
,
language
=
'nl'
,
student_number
=
's7654321'
)
cls
.
s2
=
Membership
.
objects
.
create
(
user
=
cls
.
m2
,
type
=
Membership
.
MEMBER
,
since
=
timezone
.
now
().
replace
(
year
=
2017
,
month
=
9
,
day
=
1
),
until
=
timezone
.
now
().
replace
(
year
=
2018
,
month
=
9
,
day
=
1
)
)
def
test_removes_after_31_days
(
self
):
processed
=
services
.
execute_data_minimisation
(
True
)
self
.
assertEqual
(
len
(
processed
),
1
)
self
.
assertEqual
(
processed
[
0
],
self
.
member
)
def
test_removes_after_31_days_or_no_membership
(
self
):
with
self
.
subTest
(
'Deletes after 31 days'
):
processed
=
services
.
execute_data_minimisation
(
True
)
self
.
assertEqual
(
len
(
processed
),
2
)
self
.
assertEqual
(
processed
[
0
],
self
.
m1
)
self
.
membership
.
until
=
timezone
.
now
().
replace
(
year
=
2018
,
month
=
11
,
day
=
1
)
self
.
membership
.
save
()
processed
=
services
.
execute_data_minimisation
(
True
)
self
.
assertEqual
(
len
(
processed
),
0
)
with
self
.
subTest
(
'Deletes after 31 days'
):
self
.
s1
.
until
=
timezone
.
now
().
replace
(
year
=
2018
,
month
=
11
,
day
=
1
)
self
.
s1
.
save
()
processed
=
services
.
execute_data_minimisation
(
True
)
self
.
assertEqual
(
len
(
processed
),
1
)
with
self
.
subTest
(
'Deletes when no memberships'
):
self
.
s1
.
delete
()
processed
=
services
.
execute_data_minimisation
(
True
)
self
.
assertEqual
(
len
(
processed
),
2
)
def
test_dry_run
(
self
):
with
self
.
subTest
(
'With dry_run=True'
):
services
.
execute_data_minimisation
(
True
)
self
.
m
ember
.
refresh_from_db
()
self
.
assertEqual
(
self
.
m
ember
.
profile
.
student_number
,
's1234567'
)
self
.
m
1
.
refresh_from_db
()
self
.
assertEqual
(
self
.
m
1
.
profile
.
student_number
,
's1234567'
)
with
self
.
subTest
(
'With dry_run=False'
):
services
.
execute_data_minimisation
(
False
)
self
.
member
.
refresh_from_db
()
self
.
assertIsNone
(
self
.
member
.
profile
.
student_number
)
self
.
m1
.
refresh_from_db
()
self
.
assertIsNone
(
self
.
m1
.
profile
.
student_number
)
def
test_provided_queryset
(
self
):
processed
=
services
.
execute_data_minimisation
(
True
,
members
=
Member
.
objects
)
self
.
assertEqual
(
len
(
processed
),
2
)
self
.
assertEqual
(
processed
[
0
],
self
.
m1
)
def
test_does_not_affect_current_members
(
self
):
with
self
.
subTest
(
'Membership ends in future'
):
self
.
membership
.
until
=
timezone
.
now
().
replace
(
self
.
s1
.
until
=
timezone
.
now
().
replace
(
year
=
2019
,
month
=
9
,
day
=
1
)
self
.
membership
.
save
()
self
.
s1
.
save
()
processed
=
services
.
execute_data_minimisation
(
True
)
self
.
assertEqual
(
len
(
processed
),
0
)
self
.
assertEqual
(
len
(
processed
),
1
)
with
self
.
subTest
(
'Never ending membership'
):
self
.
membership
.
until
=
None
self
.
membership
.
save
()
self
.
s1
.
until
=
None
self
.
s1
.
save
()
processed
=
services
.
execute_data_minimisation
(
True
)
self
.
assertEqual
(
len
(
processed
),
0
)
self
.
membership
.
until
=
timezone
.
now
().
replace
(
self
.
assertEqual
(
len
(
processed
),
1
)
self
.
s1
.
until
=
timezone
.
now
().
replace
(
year
=
2018
,
month
=
9
,
day
=
1
)
self
.
membership
.
save
()
self
.
s1
.
save
()
with
self
.
subTest
(
'Newer year membership after expired one'
):
m
=
Membership
.
objects
.
create
(
user
=
self
.
m
ember
,
user
=
self
.
m
1
,
type
=
Membership
.
MEMBER
,
since
=
timezone
.
now
().
replace
(
year
=
2018
,
month
=
9
,
day
=
10
),
until
=
timezone
.
now
().
replace
(
year
=
2019
,
month
=
8
,
day
=
31
),
)
processed
=
services
.
execute_data_minimisation
(
True
)
self
.
assertEqual
(
len
(
processed
),
0
)
self
.
assertEqual
(
len
(
processed
),
1
)
m
.
delete
()
with
self
.
subTest
(
'Newer study membership after expired one'
):
m
=
Membership
.
objects
.
create
(
user
=
self
.
m
ember
,
user
=
self
.
m
1
,
type
=
Membership
.
MEMBER
,
since
=
timezone
.
now
().
replace
(
year
=
2018
,
month
=
9
,
day
=
10
),
until
=
None
)
processed
=
services
.
execute_data_minimisation
(
True
)
self
.
assertEqual
(
len
(
processed
),
0
)
self
.
assertEqual
(
len
(
processed
),
1
)
m
.
delete
()
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment