Browse Source

feat(deletions): Rename projects pending deletion. (#12044)

* Added pending delete rename to project.

* Added extra lookup to get deleted project.

* refactored both project and repo so that the model gets saved once and uses transaction atomic.

* Revert previous changes.

* removed space.

* Removed linting error.
Lauryn Brown 6 years ago
parent
commit
80b1caeb5a

+ 2 - 0
src/sentry/api/endpoints/project_details.py

@@ -625,4 +625,6 @@ class ProjectDetailsEndpoint(ProjectEndpoint):
                 }
             )
 
+            project.rename_on_pending_deletion()
+
         return Response(status=204)

+ 8 - 1
src/sentry/models/project.py

@@ -17,6 +17,7 @@ from datetime import datetime
 from bitfield import BitField
 from django.conf import settings
 from django.db import IntegrityError, models, transaction
+from django.db.models.signals import pre_delete
 from django.utils import timezone
 from django.utils.translation import ugettext_lazy as _
 from django.utils.http import urlencode
@@ -24,6 +25,7 @@ from uuid import uuid1
 
 from sentry.app import locks
 from sentry.constants import ObjectStatus, RESERVED_PROJECT_SLUGS
+from sentry.db.mixin import PendingDeletionMixin, delete_pending_deletion_option
 from sentry.db.models import (
     BaseManager, BoundedPositiveIntegerField, FlexibleForeignKey, Model, sane_repr
 )
@@ -81,7 +83,7 @@ class ProjectManager(BaseManager):
         return sorted(project_list, key=lambda x: x.name.lower())
 
 
-class Project(Model):
+class Project(Model, PendingDeletionMixin):
     """
     Projects are permission based namespaces which generally
     are the top level entry point for all data.
@@ -126,6 +128,8 @@ class Project(Model):
 
     __repr__ = sane_repr('team_id', 'name', 'slug')
 
+    _rename_fields_on_pending_delete = frozenset(['slug'])
+
     def __unicode__(self):
         return u'%s (%s)' % (self.name, self.slug)
 
@@ -458,3 +462,6 @@ class Project(Model):
             )
             return False
         return True
+
+
+pre_delete.connect(delete_pending_deletion_option, sender=Project, weak=False)

+ 12 - 4
tests/sentry/api/endpoints/test_project_details.py

@@ -6,7 +6,7 @@ import six
 from django.core.urlresolvers import reverse
 
 from sentry.constants import RESERVED_PROJECT_SLUGS
-from sentry.models import OrganizationMember, Project, EnvironmentProject, ProjectOwnership, ProjectBookmark, ProjectStatus, ProjectTeam, Rule, UserOption, DeletedProject, ProjectRedirect, AuditLogEntry, AuditLogEntryEvent
+from sentry.models import OrganizationMember, OrganizationOption, Project, EnvironmentProject, ProjectOwnership, ProjectBookmark, ProjectStatus, ProjectTeam, Rule, UserOption, DeletedProject, ProjectRedirect, AuditLogEntry, AuditLogEntryEvent
 from sentry.testutils import APITestCase
 
 
@@ -839,13 +839,15 @@ class CopyProjectSettingsTest(APITestCase):
 
 
 class ProjectDeleteTest(APITestCase):
+    @mock.patch('sentry.db.mixin.uuid4')
     @mock.patch('sentry.api.endpoints.project_details.uuid4')
     @mock.patch('sentry.api.endpoints.project_details.delete_project')
-    def test_simple(self, mock_delete_project, mock_uuid4):
+    def test_simple(self, mock_delete_project, mock_uuid4_project, mock_uuid4_mixin):
         class uuid(object):
             hex = 'abc123'
 
-        mock_uuid4.return_value = uuid
+        mock_uuid4_mixin.return_value = uuid
+        mock_uuid4_project.return_value = uuid
         project = self.create_project()
 
         self.login_as(user=self.user)
@@ -871,7 +873,13 @@ class ProjectDeleteTest(APITestCase):
             countdown=3600,
         )
 
-        assert Project.objects.get(id=project.id).status == ProjectStatus.PENDING_DELETION
+        deleted_project = Project.objects.get(id=project.id)
+        assert deleted_project.status == ProjectStatus.PENDING_DELETION
+        assert deleted_project.slug == 'abc123'
+        assert OrganizationOption.objects.filter(
+            organization_id=deleted_project.organization_id,
+            key=deleted_project.build_pending_deletion_key(),
+        ).exists()
         deleted_project = DeletedProject.objects.get(slug=project.slug)
         self.assert_valid_deleted_log(deleted_project, project)