From 762d342b9a55f9efee3fe6c7ef56c2743430f25a Mon Sep 17 00:00:00 2001 From: Safwan Rahman Date: Wed, 6 Dec 2017 06:10:50 +0600 Subject: [PATCH] [Fix #3182] Better user deletion (#3214) * [Fix #3182] Better user deletion * fixup according to comments * Delete user after user ask to get deleted * fixing lint --- readthedocs/core/signals.py | 22 +++++++++++++++++-- readthedocs/profiles/views.py | 8 +++---- .../profiles/private/delete_account.html | 3 +++ 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/readthedocs/core/signals.py b/readthedocs/core/signals.py index bbef98952e4..876f0d785ff 100644 --- a/readthedocs/core/signals.py +++ b/readthedocs/core/signals.py @@ -5,13 +5,15 @@ import logging from corsheaders import signals +from django.conf import settings +from django.db.models.signals import pre_delete from django.dispatch import Signal -from django.db.models import Q +from django.db.models import Q, Count +from django.dispatch import receiver from future.backports.urllib.parse import urlparse from readthedocs.projects.models import Project, Domain - log = logging.getLogger(__name__) WHITELIST_URLS = ['/api/v2/footer_html', '/api/v2/search', '/api/v2/docsearch'] @@ -62,4 +64,20 @@ def decide_if_cors(sender, request, **kwargs): # pylint: disable=unused-argumen return False + +@receiver(pre_delete, sender=settings.AUTH_USER_MODEL) +def delete_projects_and_organizations(sender, instance, *args, **kwargs): + # Here we count the owner list from the projects that the user own + # Then exclude the projects where there are more than one owner + projects = instance.projects.all().annotate(num_users=Count('users')).exclude(num_users__gt=1) + + # Here we count the users list from the organization that the user belong + # Then exclude the organizations where there are more than one user + oauth_organizations = (instance.oauth_organizations.annotate(num_users=Count('users')) + .exclude(num_users__gt=1)) + + projects.delete() + oauth_organizations.delete() + + signals.check_request_enabled.connect(decide_if_cors) diff --git a/readthedocs/profiles/views.py b/readthedocs/profiles/views.py index b8cecfa7b7b..7f9e9429c50 100644 --- a/readthedocs/profiles/views.py +++ b/readthedocs/profiles/views.py @@ -196,11 +196,9 @@ def delete_account(request): if request.method == 'POST': form = UserDeleteForm(instance=request.user, data=request.POST) if form.is_valid(): - - # Do not delete the account permanently because it may create disaster - # Inactive the user instead. - request.user.is_active = False - request.user.save() + # Delete the user permanently + # It will also delete some projects where he is the only owner + request.user.delete() logout(request) messages.info(request, 'You have successfully deleted your account') diff --git a/readthedocs/templates/profiles/private/delete_account.html b/readthedocs/templates/profiles/private/delete_account.html index 6a76f5c7576..567eff17cfb 100644 --- a/readthedocs/templates/profiles/private/delete_account.html +++ b/readthedocs/templates/profiles/private/delete_account.html @@ -12,6 +12,9 @@
{% csrf_token %} {{ form }} +
+ {% trans "Be careful! This can not be undone!" %} +
{% endblock %}