Skip to content

Commit

Permalink
api tests, anonymize datasets on user deletion
Browse files Browse the repository at this point in the history
  • Loading branch information
biodiv committed Nov 8, 2022
1 parent a38ee67 commit c7ab952
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 19 deletions.
101 changes: 95 additions & 6 deletions localcosmos_server/api/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,6 @@ def get_jw_token(self, username, password):
return response.data


class TestManageAccount(GetJWTokenMixin, WithUser, WithApp, TestCase):

def get_authenticated_client(self, username, password):

token_pair = self.get_jw_token(username, password)
Expand All @@ -206,6 +204,7 @@ def get_authenticated_client(self, username, password):
return authed_client


class TestManageAccount(GetJWTokenMixin, WithUser, WithApp, TestCase):

@test_settings
def test_get(self):
Expand Down Expand Up @@ -291,13 +290,103 @@ def test_put_400(self):
self.assertIn('errors', authed_response.data)


class TestDeleteAccount(GetJWTokenMixin, WithDataset, WithUser, WithApp, TestCase):

@test_settings
def test_delete(self):

superuser = self.create_superuser()
user = self.create_user()

user_exists = User.objects.filter(pk=user.id).exists()
self.assertTrue(user_exists)

authed_client = self.get_authenticated_client(user.username, self.test_password)
authed_response = authed_client.delete('/api/user/delete/')

self.assertEqual(authed_response.status_code, 200)

self.assertTrue(authed_response.data['success'])

user_exists = User.objects.filter(pk=user.id).exists()
self.assertFalse(user_exists)

class TestPasswordResetRequest(TestCase):

@test_settings
def test_get(self):
pass
def test_delete_anonymize_dataset(self):

superuser = self.create_superuser()
user = self.create_user()

dataset = self.create_dataset()

self.assertEqual(dataset.user, None)

dataset.user = user
dataset.save()
dataset = Dataset.objects.get(pk=dataset.id)

self.assertEqual(dataset.user, user)

authed_client = self.get_authenticated_client(user.username, self.test_password)
authed_response = authed_client.delete('/api/user/delete/')

user_exists = User.objects.filter(pk=user.id).exists()
self.assertFalse(user_exists)

dataset.refresh_from_db()
self.assertEqual(dataset.user, None)


class TestPasswordResetRequest(GetJWTokenMixin, WithUser, WithApp, TestCase):

@test_settings
def test_post(self):
pass

superuser = self.create_superuser()
user = self.create_user()

post_data = {
'email' : user.email
}

authed_client = self.get_authenticated_client(user.username, self.test_password)
authed_response = authed_client.post('/api/password/reset/', post_data, format='json')

self.assertEqual(authed_response.status_code, 200)

self.assertTrue(authed_response.data['success'])


@test_settings
def test_post_invalid(self):

superuser = self.create_superuser()
user = self.create_user()

post_data = {}

authed_client = self.get_authenticated_client(user.username, self.test_password)
authed_response = authed_client.post('/api/password/reset/', post_data, format='json')

self.assertEqual(authed_response.status_code, 400)

self.assertFalse(authed_response.data['success'])


@test_settings
def test_post_no_user(self):

superuser = self.create_superuser()
user = self.create_user()

post_data = {
'email' : 'nonexistant@example.com'
}

authed_client = self.get_authenticated_client(user.username, self.test_password)
authed_response = authed_client.post('/api/password/reset/', post_data, format='json')

self.assertEqual(authed_response.status_code, 400)

self.assertFalse(authed_response.data['success'])
1 change: 1 addition & 0 deletions localcosmos_server/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ class DeleteAccount(APIView):
serializer_class = AccountSerializer

def delete(self, request, *args, **kwargs):

request.user.delete()
logout(request)

Expand Down
10 changes: 6 additions & 4 deletions localcosmos_server/datasets/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ class Dataset(ModelWithTaxon):
# - iterate over all remaining steps as defined in DatasetValidationRoutine
# - if no steps are defined, mark the dataset as valid, and set validation_step to 'completed'
###############################################################################################################


@property
def validation_routine(self):
Expand Down Expand Up @@ -235,9 +236,9 @@ def update_redundant_columns(self):

if taxon_field_uuid in reported_values and type(reported_values[taxon_field_uuid]) == dict:
taxon_json = reported_values[taxon_field_uuid]

lazy_taxon = self.LazyTaxonClass(**taxon_json)
self.set_taxon(lazy_taxon)
self.set_taxon(lazy_taxon)

# update coordinates or geographic_reference
# {"type": "Feature", "geometry": {"crs": {"type": "name", "properties": {"name": "EPSG:4326"}},
Expand Down Expand Up @@ -339,11 +340,12 @@ def save(self, *args, **kwargs):
if created == True:
self.validate()


'''
def __str__(self):
if self.taxon_latname:
return '%s' % (self.taxon_latname)
return '{}'.format(self.taxon_latname)
return str(_('Unidentified'))
'''


class Meta:
Expand Down
15 changes: 15 additions & 0 deletions localcosmos_server/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,22 @@ class LocalcosmosUser(AbstractUser):

objects = LocalcosmosUserManager()


# there is a bug in django for Dataset.user.on_delete=models.SET_NULL (django 3.1)
# anonymize the datasets here instead of letting django call SET_NULL
def anonymize_datasets(self):
from localcosmos_server.datasets.models import Dataset
datasets = Dataset.objects.filter(user=self)
for dataset in datasets:
dataset.user = None

Dataset.objects.bulk_update(datasets, ['user'])

# do not alter the delete method
def delete(self, using=None, keep_parents=False):

if settings.LOCALCOSMOS_PRIVATE == True:
self.anonymize_datasets()
super().delete(using=using, keep_parents=keep_parents)
else:
# localcosmos.org uses django-tenants
Expand All @@ -82,6 +95,8 @@ def delete(self, using=None, keep_parents=False):
# delete user and all of its data across tenants
for tenant in Tenant.objects.all().exclude(schema_name='public'):
with schema_context(tenant.schema_name):

self.anonymize_datasets()

super().delete(using=using, keep_parents=keep_parents)
# reassign the ID because delete() sets it to None
Expand Down
29 changes: 22 additions & 7 deletions localcosmos_server/taxonomy/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ def __init__(self, *args, **kwargs):
self.set_taxon(lazy_taxon)

elif self.pk:
if self.taxon_latname:

if self.taxon_latname and self.taxon_author and self.taxon_source and self.taxon_nuid and self.name_uuid:
lazy_taxon = self.LazyTaxonClass(instance=self)
self.set_taxon(lazy_taxon)

Expand Down Expand Up @@ -58,23 +59,28 @@ def get_taxon(self):
'taxon_source' : self.taxon_source,
'taxon_include_descendants' : self.taxon_include_descendants,
}
lazy_taxon = LazyTaxon(**lazy_taxon_kwargs)
lazy_taxon = LazyAppTaxon(**lazy_taxon_kwargs)
self.set_taxon(lazy_taxon)

return self.taxon


def set_taxon(self, lazy_taxon):
def set_taxon_parameters(self, lazy_taxon):

# allow setting with LazyTaxon or LazyAppTaxon

self.name_uuid = str(lazy_taxon.name_uuid)
self.taxon_nuid = lazy_taxon.taxon_nuid
self.taxon_latname = lazy_taxon.taxon_latname
self.taxon_author = lazy_taxon.taxon_author
self.taxon_source = lazy_taxon.taxon_source
self.taxon_include_descendants = lazy_taxon.taxon_include_descendants


def set_taxon(self, lazy_taxon):

# allow setting with LazyTaxon or LazyAppTaxon

self.set_taxon_parameters(lazy_taxon)

# the lazy taxon, make sure it is the right LazyTaxonClass
lazy_taxon_kwargs = {
'taxon_latname' : lazy_taxon.taxon_latname,
Expand All @@ -88,6 +94,15 @@ def set_taxon(self, lazy_taxon):
self.taxon = self.LazyTaxonClass(**lazy_taxon_kwargs)


def remove_taxon(self):
self.name_uuid = None
self.taxon_nuid = None
self.taxon_latname = None
self.taxon_author = None
self.taxon_source = None
self.taxon_include_descendants = None


def vernacular(self, language=None):
if not self.taxon:
self.get_taxon()
Expand Down Expand Up @@ -155,7 +170,7 @@ def update_taxon(self):

if str(tree_instance.name_uuid) != str(self.name_uuid) or tree_instance.taxon_nuid != self.taxon_nuid:

new_lazy_taxon = LazyTaxon(instance=tree_instance)
new_lazy_taxon = LazyAppTaxon(instance=tree_instance)
new_lazy_taxon.taxon_include_descendants = self.taxon_include_descendants

self.set_taxon(new_lazy_taxon)
Expand All @@ -166,7 +181,7 @@ def update_taxon(self):
synonym_instance = lazy_taxon.synonym_instance()
tree_instance = synonym_instance.taxon

new_lazy_taxon = LazyTaxon(instance=tree_instance)
new_lazy_taxon = LazyAppTaxon(instance=tree_instance)
new_lazy_taxon.taxon_include_descendants = self.taxon_include_descendants

self.set_taxon(new_lazy_taxon)
Expand Down
11 changes: 9 additions & 2 deletions localcosmos_server/tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
DATASET_VALIDATION_CLASSES = (
'localcosmos_server.datasets.validation.ExpertReviewValidator',
'localcosmos_server.datasets.validation.ReferenceFieldsValidator',
)
),
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend',
)

test_settings_commercial = override_settings(
Expand All @@ -43,7 +44,13 @@
"client_id": TEST_CLIENT_ID,
"client_platform": "browser",
"0f444e85-e31d-443d-afd3-2fa35df08ce3": {"cron": {"type": "timestamp", "format": "unixtime", "timestamp": TEST_UTC_TIMESTAMP, "timezone_offset": TEST_TIMESTAMP_OFFSET}, "type": "Temporal"},
"7e5c9390-61cf-4cb5-8b0f-9086b2f387ce": {"taxon_nuid": "006002009001005007001", "name_uuid": "1541aa08-7c23-4de0-9898-80d87e9227b3", "taxon_source": "taxonomy.sources.col", "taxon_latname": "Picea abies", "taxon_author":"Linnaeus"},
"7e5c9390-61cf-4cb5-8b0f-9086b2f387ce": {
"taxon_nuid": "006002009001005007001",
"name_uuid": "1541aa08-7c23-4de0-9898-80d87e9227b3",
"taxon_source": "taxonomy.sources.col",
"taxon_latname": "Picea abies",
"taxon_author":"Linnaeus"
},
"96e8ff3b-ffcc-4ccd-b81c-542f37ce53d0": None,
"a4d53718-715f-4436-9b4c-09fce7978153": {"type": "Feature", "geometry": {"crs": {"type": "name", "properties": {"name": "EPSG:4326"}}, "type": "Point", "coordinates": [TEST_LONGITUDE, TEST_LATITUDE]}, "properties": {"accuracy": 1}}
},
Expand Down

0 comments on commit c7ab952

Please sign in to comment.