Skip to content

Commit 77df279

Browse files
authored
Merge pull request #7441 from readthedocs/move-signals
Organizations: move signals
2 parents ce4adfe + 08fffe7 commit 77df279

File tree

3 files changed

+80
-0
lines changed

3 files changed

+80
-0
lines changed

readthedocs/organizations/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
default_app_config = 'readthedocs.organizations.apps.OrganizationsConfig' # noqa

readthedocs/organizations/apps.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@
66
class OrganizationsConfig(AppConfig):
77

88
name = 'readthedocs.organizations'
9+
10+
def ready(self):
11+
import readthedocs.organizations.signals # noqa

readthedocs/organizations/signals.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
"""Organization signals."""
2+
3+
import logging
4+
5+
from allauth.account.signals import user_signed_up
6+
from django.db.models import Count
7+
from django.db.models.signals import pre_delete
8+
from django.dispatch import receiver
9+
10+
from readthedocs.builds.models import Version
11+
from readthedocs.organizations.models import (
12+
Organization,
13+
Team,
14+
TeamInvite,
15+
TeamMember,
16+
)
17+
from readthedocs.projects.models import Project
18+
19+
log = logging.getLogger(__name__)
20+
21+
22+
# pylint: disable=unused-argument
23+
@receiver(user_signed_up)
24+
def attach_org(sender, request, user, **kwargs):
25+
"""Attach invited user to organization."""
26+
team_slug = request.session.get('team')
27+
if team_slug:
28+
team = Team.objects.get(slug=team_slug)
29+
TeamMember.objects.create(team=team, member=user)
30+
31+
32+
# pylint: disable=unused-argument
33+
@receiver(pre_delete, sender=Organization)
34+
def remove_organization_completely(sender, instance, using, **kwargs):
35+
"""
36+
Remove Organization leaf-overs.
37+
38+
This includes:
39+
40+
- Projects
41+
- Versions
42+
- Builds (deleted on cascade)
43+
- Teams
44+
- Team Invitations
45+
- Team Memberships
46+
- Artifacts (HTML, PDF, etc)
47+
"""
48+
organization = instance
49+
log.info('Removing Organization %s completely', organization.slug)
50+
51+
# ``Project`` has a ManyToMany relationship with ``Organization``. We need
52+
# to be sure that the projects we are deleting here belongs only to the
53+
# organization deleted
54+
projects = Project.objects.annotate(
55+
Count('organizations'),
56+
).filter(
57+
organizations__in=[organization],
58+
organizations__count=1,
59+
)
60+
61+
versions = Version.objects.filter(project__in=projects)
62+
teams = Team.objects.filter(organization=organization)
63+
team_invites = TeamInvite.objects.filter(organization=organization)
64+
team_memberships = TeamMember.objects.filter(team__in=teams)
65+
66+
# Bulk delete
67+
team_memberships.delete()
68+
team_invites.delete()
69+
teams.delete()
70+
71+
# Granular delete that trigger other complex tasks
72+
for version in versions:
73+
# Triggers a task to remove artifacts from storage
74+
version.delete()
75+
76+
projects.delete()

0 commit comments

Comments
 (0)