Skip to content

Commit 0a92941

Browse files
authored
[ENG-9002] allow gdpr delete for sole contribs (#11334)
1 parent 3f8b884 commit 0a92941

File tree

2 files changed

+60
-28
lines changed

2 files changed

+60
-28
lines changed

osf/models/user.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1988,13 +1988,34 @@ def gdpr_delete(self):
19881988
def _validate_no_public_entities(self):
19891989
"""
19901990
Ensure that the user doesn't have any public facing resources like Registrations or Preprints
1991+
that would be left with other contributors after this deletion.
1992+
1993+
Allow GDPR deletion if the user is the sole contributor on a public Registration or Preprint.
19911994
"""
1992-
from osf.models import Preprint
1995+
from osf.models import Preprint, AbstractNode
1996+
1997+
registrations_with_others = AbstractNode.objects.annotate(
1998+
contrib_count=Count('_contributors', distinct=True),
1999+
).filter(
2000+
_contributors=self,
2001+
deleted__isnull=True,
2002+
type='osf.registration',
2003+
contrib_count__gt=1
2004+
).exists()
19932005

1994-
if self.nodes.filter(deleted__isnull=True, type='osf.registration').exists():
2006+
if registrations_with_others:
19952007
raise UserStateError('You cannot delete this user because they have one or more registrations.')
19962008

1997-
if Preprint.objects.filter(_contributors=self, ever_public=True, deleted__isnull=True).exists():
2009+
preprints_with_others = Preprint.objects.annotate(
2010+
contrib_count=Count('_contributors', distinct=True),
2011+
).filter(
2012+
_contributors=self,
2013+
ever_public=True,
2014+
deleted__isnull=True,
2015+
contrib_count__gt=1
2016+
).exists()
2017+
2018+
if preprints_with_others:
19982019
raise UserStateError('You cannot delete this user because they have one or more preprints.')
19992020

20002021
def _validate_and_remove_resource_for_gdpr_delete(self, resources, hard_delete):

osf_tests/test_user.py

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@
3030
NotableDomain,
3131
PreprintContributor,
3232
DraftRegistrationContributor,
33-
DraftRegistration,
34-
DraftNode,
3533
UserSessionMap,
3634
)
3735
from osf.models.institution_affiliation import get_user_by_institution_identity
@@ -2116,26 +2114,6 @@ def test_can_gdpr_delete_personal_nodes(self, user):
21162114
user.gdpr_delete()
21172115
assert user.nodes.exclude(is_deleted=True).count() == 0
21182116

2119-
def test_can_gdpr_delete_personal_registrations(self, user, registration_with_draft_node):
2120-
assert DraftRegistration.objects.all().count() == 1
2121-
assert DraftNode.objects.all().count() == 1
2122-
2123-
with pytest.raises(UserStateError) as exc_info:
2124-
user.gdpr_delete()
2125-
2126-
assert exc_info.value.args[0] == 'You cannot delete this user because they have one or more registrations.'
2127-
assert DraftRegistration.objects.all().count() == 1
2128-
assert DraftNode.objects.all().count() == 1
2129-
2130-
registration_with_draft_node.remove_node(Auth(user))
2131-
assert DraftRegistration.objects.all().count() == 1
2132-
assert DraftNode.objects.all().count() == 1
2133-
user.gdpr_delete()
2134-
2135-
# DraftNodes soft-deleted, DraftRegistions hard-deleted
2136-
assert user.nodes.exclude(is_deleted=True).count() == 0
2137-
assert DraftRegistration.objects.all().count() == 0
2138-
21392117
def test_can_gdpr_delete_shared_nodes_with_multiple_admins(self, user, project_with_two_admins):
21402118

21412119
user.gdpr_delete()
@@ -2144,28 +2122,61 @@ def test_can_gdpr_delete_shared_nodes_with_multiple_admins(self, user, project_w
21442122
def test_can_gdpr_delete_shared_draft_registration_with_multiple_admins(self, user, registration):
21452123
other_admin = AuthUserFactory()
21462124
draft_registrations = user.draft_registrations.get()
2147-
draft_registrations.add_contributor(other_admin, permissions='admin')
2125+
draft_registrations.add_contributor(other_admin, auth=Auth(user), permissions='admin')
21482126
assert draft_registrations.contributors.all().count() == 2
21492127
registration.delete_registration_tree(save=True)
21502128

21512129
user.gdpr_delete()
21522130
assert draft_registrations.contributors.get() == other_admin
21532131
assert user.nodes.filter(deleted__isnull=True).count() == 0
21542132

2155-
def test_cant_gdpr_delete_registrations(self, user, registration):
2133+
def test_cant_gdpr_delete_multiple_contributors_registrations(self, user, registration):
2134+
registration.is_public = True
2135+
other_user = AuthUserFactory()
2136+
registration.add_contributor(other_user, auth=Auth(user), permissions='admin')
2137+
registration.save()
2138+
2139+
assert registration.contributors.count() == 2
21562140

21572141
with pytest.raises(UserStateError) as exc_info:
21582142
user.gdpr_delete()
21592143

21602144
assert exc_info.value.args[0] == 'You cannot delete this user because they have one or more registrations.'
21612145

2162-
def test_cant_gdpr_delete_preprints(self, user, preprint):
2146+
def test_cant_gdpr_delete_multiple_contributors_preprints(self, user, preprint):
2147+
other_user = AuthUserFactory()
2148+
preprint.add_contributor(other_user, auth=Auth(user), permissions='admin')
2149+
preprint.save()
21632150

21642151
with pytest.raises(UserStateError) as exc_info:
21652152
user.gdpr_delete()
21662153

21672154
assert exc_info.value.args[0] == 'You cannot delete this user because they have one or more preprints.'
21682155

2156+
def test_can_gdpr_delete_sole_contributor_registration(self, user):
2157+
registration = RegistrationFactory(creator=user)
2158+
registration.save()
2159+
2160+
assert registration.contributors.count() == 1
2161+
assert registration.contributors.first() == user
2162+
2163+
user.gdpr_delete()
2164+
2165+
assert user.fullname == 'Deleted user'
2166+
assert user.deleted is not None
2167+
2168+
def test_can_gdpr_delete_sole_contributor_preprint(self, user):
2169+
preprint = PreprintFactory(creator=user)
2170+
preprint.save()
2171+
2172+
assert preprint.contributors.count() == 1
2173+
assert preprint.contributors.first() == user
2174+
2175+
user.gdpr_delete()
2176+
2177+
assert user.fullname == 'Deleted user'
2178+
assert user.deleted is not None
2179+
21692180
def test_cant_gdpr_delete_shared_node_if_only_admin(self, user, project_user_is_only_admin):
21702181

21712182
with pytest.raises(UserStateError) as exc_info:

0 commit comments

Comments
 (0)