-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
[Fix #3182] Better user deletion #3214
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,14 +5,19 @@ | |
import logging | ||
|
||
from corsheaders import signals | ||
from django.contrib.auth import get_user_model | ||
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.oauth.tasks import bulk_delete_oauth_remote_organizations | ||
from readthedocs.projects.models import Project, Domain | ||
|
||
from readthedocs.projects.tasks import bulk_delete_projects | ||
|
||
log = logging.getLogger(__name__) | ||
User = get_user_model() | ||
|
||
WHITELIST_URLS = ['/api/v2/footer_html', '/api/v2/search', '/api/v2/docsearch'] | ||
|
||
|
@@ -62,4 +67,23 @@ def decide_if_cors(sender, request, **kwargs): # pylint: disable=unused-argumen | |
|
||
return False | ||
|
||
|
||
@receiver(pre_delete, sender=User) | ||
def delete_projects_and_organizations(instance, *args, **kwargs): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The function arguments are wrong here. The first argument is @receiver(pre_delete, sender=User)
def delete_projects_and_organizations(sender, *args, **kwargs):
instance = kwargs.pop('instance') https://docs.djangoproject.com/en/1.9/ref/signals/#pre-delete There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh! Sorry, I missed the sender part. I will add it in next commit |
||
# 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_id = (instance.projects.all().annotate(num_users=Count('users')) | ||
.exclude(num_users__gt=1) | ||
.values_list('id', flat=True)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll have to think more on this logic, but at first glance this will cause problems with our hosting at readthedocs.com, as users don't own projects, a more top-level object, |
||
|
||
# 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_id = (instance.oauth_organizations.annotate(num_users=Count('users')) | ||
.exclude(num_users__gt=1) | ||
.values_list('id', flat=True)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OAuth organizations aren't currently shared, so There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I dont know whats the case actually. maybe it was m2m to give a organization user same permission? to docs |
||
|
||
bulk_delete_projects.delay(projects_id) | ||
bulk_delete_oauth_remote_organizations.delay(oauth_organizations_id) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If there is no strong reason that either of these need to be executed via a task, we can just remove them directly here. |
||
|
||
|
||
signals.check_request_enabled.connect(decide_if_cors) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,14 @@ | ||
"""Tasks for OAuth services""" | ||
|
||
from __future__ import absolute_import | ||
from celery import task | ||
from django.contrib.auth.models import User | ||
from djcelery import celery as celery_app | ||
|
||
from readthedocs.core.utils.tasks import PublicTask | ||
from readthedocs.core.utils.tasks import permission_check | ||
from readthedocs.core.utils.tasks import user_id_matches | ||
from readthedocs.oauth.models import RemoteOrganization | ||
from .services import registry | ||
|
||
|
||
|
@@ -21,5 +23,9 @@ def run_public(self, user_id): | |
for service in service_cls.for_user(user): | ||
service.sync() | ||
|
||
@task() | ||
def bulk_delete_oauth_remote_organizations(organizations_id): | ||
RemoteOrganization.objects.filter(id__in=organizations_id).delete() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems like something that should cascade on the database |
||
|
||
|
||
sync_remote_repositories = celery_app.tasks[SyncRemoteRepositories.name] |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -984,3 +984,8 @@ def clear_html_artifacts(version): | |
if isinstance(version, int): | ||
version = Version.objects.get(pk=version) | ||
remove_dir(version.project.rtd_build_path(version=version.slug)) | ||
|
||
|
||
@task() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Without specifying the queue on this task, it will execute on the build instances, which have no access to the database. Specify |
||
def bulk_delete_projects(projects_id): | ||
Project.objects.filter(id__in=projects_id).delete() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any reason this needs to be executed via a task? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was hoping to delete the project directory with the project removal. So was thinking to do it with task. I think we can exclude it from the task |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,8 @@ | |
<form method="POST" action="."> | ||
{% csrf_token %} | ||
{{ form }} | ||
<br> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Styling should be handled with css, avoid |
||
<strong>Be careful! This can not be undone!</strong> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Untranslated string here. |
||
<input type="submit" name="submit" value="{% trans "Delete Account" %}" id="submit"/> | ||
</form> | ||
{% endblock %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the reason for using get_user_model() here? The pattern we've used throughout the codebase is to import
from django.contrib.auth.models import User
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have gone through the documentation and it seems that using
settings.AUTH_USER_MODEL
is conventional way