Skip to content

Commit d5fd637

Browse files
committed
Org delete to delete children first
1 parent a7e9392 commit d5fd637

4 files changed

Lines changed: 62 additions & 14 deletions

File tree

core/common/models.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,11 @@ def batch_index(queryset, document):
176176
offset = limit
177177
limit += batch_size
178178

179+
@staticmethod
180+
def batch_delete(queryset):
181+
for batch in queryset.iterator(chunk_size=200):
182+
batch.delete()
183+
179184

180185
class CommonLogoModel(models.Model):
181186
logo_path = models.TextField(null=True, blank=True)

core/common/tasks.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,18 @@ def delete_organization(org_id):
2222
from core.orgs.models import Organization
2323
logger.info('Finding org...')
2424

25-
queryset = Organization.objects.filter(id=org_id)
25+
org = Organization.objects.filter(id=org_id).first()
2626

27-
if not queryset.exists():
27+
if not org:
2828
logger.info('Not found org %s', org_id)
2929
return
3030

31-
org = queryset.first()
32-
3331
try:
3432
logger.info('Found org %s. Beginning purge...', org.mnemonic)
35-
queryset.delete() # not using org.delete() to use django's bulk delete
36-
from core.pins.models import Pin
37-
Pin.objects.filter(resource_type__model='organization', resource_id=org.id).delete()
38-
from core.client_configs.models import ClientConfig
39-
ClientConfig.objects.filter(resource_type__model='organization', resource_id=org.id).delete()
33+
org.delete()
4034
logger.info('Purge complete!')
4135
except Exception as ex:
36+
print("****", ex)
4237
logger.info('Org delete failed for %s with exception %s', org.mnemonic, ex.args)
4338

4439

@@ -415,8 +410,9 @@ def delete_dormant_locales(): # pragma: no cover
415410
def delete_concept(concept_id): # pragma: no cover
416411
from core.concepts.models import Concept
417412

418-
concept = Concept.objects.filter(id=concept_id).first()
419-
concept.delete()
413+
queryset = Concept.objects.filter(id=concept_id)
414+
if queryset.exists():
415+
queryset.delete()
420416

421417
return 1
422418

core/orgs/models.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from django.contrib import admin
22
from django.contrib.contenttypes.fields import GenericRelation
33
from django.core.validators import RegexValidator
4-
from django.db import models
4+
from django.db import models, transaction
55

66
from core.client_configs.models import ClientConfig
77
from core.common.constants import NAMESPACE_REGEX, ACCESS_TYPE_VIEW, ACCESS_TYPE_EDIT
@@ -15,7 +15,6 @@ class Meta:
1515
db_table = 'organizations'
1616
indexes = [] + BaseResourceModel.Meta.indexes
1717

18-
1918
OBJECT_TYPE = ORG_OBJECT_TYPE
2019
es_fields = {
2120
'name': {'sortable': True, 'filterable': True, 'exact': True},
@@ -71,5 +70,29 @@ def save(self, force_insert=False, force_update=False, using=None, update_fields
7170
if self.updated_by_id:
7271
self.members.add(self.updated_by)
7372

73+
def delete(self, using=None, keep_parents=False):
74+
with transaction.atomic():
75+
for source in self.source_set.all():
76+
self.batch_delete(source.concepts_set)
77+
self.batch_delete(source.mappings_set)
78+
source.delete()
79+
for collection in self.collection_set.all():
80+
self.batch_delete(collection.references)
81+
collection.delete()
82+
self.delete_pins()
83+
self.delete_client_configs()
84+
85+
return super().delete(using=using, keep_parents=keep_parents)
86+
87+
def delete_client_configs(self):
88+
ClientConfig.objects.filter(resource_type__model='organization', resource_id=self.id).delete()
89+
90+
def delete_pins(self):
91+
from core.pins.models import Pin
92+
# deletes pins where org is pinned
93+
Pin.objects.filter(resource_type__model='organization', resource_id=self.id).delete()
94+
# deletes pins for this org
95+
self.pins.all().delete()
96+
7497

7598
admin.site.register(Organization)

core/orgs/tests/tests.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
from django.core.exceptions import ValidationError
22
from mock import patch, Mock
33

4+
from core.collections.models import Collection, CollectionReference
45
from core.common.constants import ACCESS_TYPE_NONE, HEAD
56
from core.common.tasks import delete_organization
67
from core.common.tests import OCLTestCase
8+
from core.concepts.models import Concept
9+
from core.concepts.tests.factories import ConceptFactory
10+
from core.mappings.models import Mapping
11+
from core.mappings.tests.factories import MappingFactory
712
from core.orgs.constants import ORG_OBJECT_TYPE
813
from core.orgs.models import Organization
914
from core.orgs.tests.factories import OrganizationFactory
15+
from core.sources.models import Source
1016
from core.sources.tests.factories import OrganizationSourceFactory
1117
from core.collections.tests.factories import OrganizationCollectionFactory
1218
from core.users.tests.factories import UserProfileFactory
@@ -124,7 +130,20 @@ def test_org_active_inactive_should_affect_children(self):
124130
self.assertTrue(collection.is_active)
125131

126132
def test_delete_organization_task(self):
127-
org = OrganizationFactory()
133+
org = OrganizationFactory(mnemonic='to-be-deleted-org')
134+
source = OrganizationSourceFactory(mnemonic='to-be-deleted-source', organization=org)
135+
collection = OrganizationCollectionFactory(mnemonic='to-be-deleted-coll', organization=org)
136+
concept = ConceptFactory(mnemonic='to-be-deleted-concept', parent=source)
137+
mapping = MappingFactory(mnemonic='to-be-deleted-mapping', parent=source)
138+
collection.add_references([concept.uri, mapping.uri])
139+
140+
self.assertEqual(org.source_set.count(), 1)
141+
self.assertEqual(org.collection_set.count(), 1)
142+
self.assertEqual(source.concepts_set.count(), 2)
143+
self.assertEqual(source.mappings_set.count(), 2)
144+
self.assertEqual(collection.references.count(), 2)
145+
self.assertEqual(collection.concepts.count(), 1)
146+
self.assertEqual(collection.mappings.count(), 1)
128147

129148
delete_organization(0)
130149

@@ -133,6 +152,11 @@ def test_delete_organization_task(self):
133152
delete_organization(org.id)
134153

135154
self.assertFalse(Organization.objects.filter(id=org.id).exists())
155+
self.assertFalse(Source.objects.filter(mnemonic='to-be-deleted-source').exists())
156+
self.assertFalse(Collection.objects.filter(mnemonic='to-be-deleted-coll').exists())
157+
self.assertFalse(Concept.objects.filter(mnemonic='to-be-deleted-concept').exists())
158+
self.assertFalse(Mapping.objects.filter(mnemonic='to-be-deleted-mapping').exists())
159+
self.assertEqual(CollectionReference.objects.count(), 0)
136160

137161
def test_logo_url(self):
138162
self.assertIsNone(Organization(logo_path=None).logo_url)

0 commit comments

Comments
 (0)