Merge pull request #736 from taigaio/Improving-project-deletion

Improving-project-deletion
remotes/origin/issue/4795/notification_even_they_are_disabled
David Barragán Merino 2016-05-30 17:57:57 +02:00
commit a1f52e9a72
6 changed files with 88 additions and 5 deletions

View File

@ -20,6 +20,7 @@ from easy_thumbnails.source_generators import pil_image
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from django.apps import apps from django.apps import apps
from django.conf import settings
from django.db.models import signals, Prefetch from django.db.models import signals, Prefetch
from django.db.models import Value as V from django.db.models import Value as V
from django.db.models.functions import Coalesce from django.db.models.functions import Coalesce
@ -442,9 +443,13 @@ class ProjectViewSet(LikedResourceMixin, HistoryResourceMixin,
self.pre_delete(obj) self.pre_delete(obj)
self.pre_conditions_on_delete(obj) self.pre_conditions_on_delete(obj)
obj.delete_related_content()
obj.delete() services.orphan_project(obj)
self.post_delete(obj) if settings.CELERY_ENABLED:
services.delete_project.delay(obj.id)
else:
services.delete_project(obj.id)
return response.NoContent() return response.NoContent()

View File

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.2 on 2016-05-30 10:04
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('projects', '0042_auto_20160525_0911'),
]
operations = [
migrations.AlterField(
model_name='project',
name='owner',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='owned_projects', to=settings.AUTH_USER_MODEL, verbose_name='owner'),
),
]

View File

@ -157,7 +157,7 @@ class Project(ProjectDefaults, TaggedMixin, models.Model):
default=timezone.now) default=timezone.now)
modified_date = models.DateTimeField(null=False, blank=False, modified_date = models.DateTimeField(null=False, blank=False,
verbose_name=_("modified date")) verbose_name=_("modified date"))
owner = models.ForeignKey(settings.AUTH_USER_MODEL, null=False, blank=False, owner = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True,
related_name="owned_projects", verbose_name=_("owner")) related_name="owned_projects", verbose_name=_("owner"))
members = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="projects", members = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="projects",
through="Membership", verbose_name=_("members"), through="Membership", verbose_name=_("members"),

View File

@ -47,6 +47,8 @@ from .projects import check_if_project_privacity_can_be_changed
from .projects import check_if_project_can_be_created_or_updated from .projects import check_if_project_can_be_created_or_updated
from .projects import check_if_project_can_be_transfered from .projects import check_if_project_can_be_transfered
from .projects import check_if_project_is_out_of_owner_limits from .projects import check_if_project_is_out_of_owner_limits
from .projects import orphan_project
from .projects import delete_project
from .stats import get_stats_for_project_issues from .stats import get_stats_for_project_issues
from .stats import get_stats_for_project from .stats import get_stats_for_project

View File

@ -15,8 +15,9 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from django.apps import apps
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from taiga.celery import app
ERROR_MAX_PUBLIC_PROJECTS_MEMBERSHIPS = 'max_public_projects_memberships' ERROR_MAX_PUBLIC_PROJECTS_MEMBERSHIPS = 'max_public_projects_memberships'
ERROR_MAX_PRIVATE_PROJECTS_MEMBERSHIPS = 'max_private_projects_memberships' ERROR_MAX_PRIVATE_PROJECTS_MEMBERSHIPS = 'max_private_projects_memberships'
@ -151,3 +152,21 @@ def check_if_project_is_out_of_owner_limits(project):
return True return True
return False return False
def orphan_project(project):
project.memberships.filter(user=project.owner).delete()
project.owner = None
project.save()
@app.task
def delete_project(project_id):
Project = apps.get_model("projects", "Project")
try:
project = Project.objects.get(id=project_id)
except Project.DoesNotExist:
return
project.delete_related_content()
project.delete()

View File

@ -19,6 +19,8 @@ from easy_thumbnails.files import generate_all_aliases, get_thumbnailer
import os.path import os.path
import pytest import pytest
from unittest import mock
pytestmark = pytest.mark.django_db pytestmark = pytest.mark.django_db
class ExpiredSigner(signing.TimestampSigner): class ExpiredSigner(signing.TimestampSigner):
@ -1814,3 +1816,36 @@ def test_public_project_when_project_has_unlimited_members(client):
project.owner.max_memberships_public_projects = None project.owner.max_memberships_public_projects = None
assert check_if_project_is_out_of_owner_limits(project) == False assert check_if_project_is_out_of_owner_limits(project) == False
def test_delete_project_with_celery_enabled(client, settings):
settings.CELERY_ENABLED = True
user = f.UserFactory.create()
project = f.ProjectFactory.create(owner=user)
role = f.RoleFactory.create(project=project, permissions=["view_project"])
membership = f.MembershipFactory.create(project=project, user=user, role=role, is_admin=True)
url = reverse("projects-detail", args=(project.id,))
client.login(user)
#delete_project task should have been launched
with mock.patch('taiga.projects.services.delete_project') as delete_project_mock:
response = client.json.delete(url)
assert response.status_code == 204
project = Project.objects.get(id=project.id)
assert project.owner == None
assert project.memberships.count() == 0
delete_project_mock.delay.assert_called_once_with(project.id)
def test_delete_project_with_celery_disabled(client, settings):
settings.CELERY_ENABLED = False
user = f.UserFactory.create()
project = f.ProjectFactory.create(owner=user)
role = f.RoleFactory.create(project=project, permissions=["view_project"])
membership = f.MembershipFactory.create(project=project, user=user, role=role, is_admin=True)
url = reverse("projects-detail", args=(project.id,))
client.login(user)
response = client.json.delete(url)
assert response.status_code == 204
assert Project.objects.filter(id=project.id).count() == 0