Merge pull request #736 from taigaio/Improving-project-deletion
Improving-project-deletionremotes/origin/issue/4795/notification_even_they_are_disabled
commit
a1f52e9a72
|
@ -20,6 +20,7 @@ from easy_thumbnails.source_generators import pil_image
|
|||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
from django.db.models import signals, Prefetch
|
||||
from django.db.models import Value as V
|
||||
from django.db.models.functions import Coalesce
|
||||
|
@ -442,9 +443,13 @@ class ProjectViewSet(LikedResourceMixin, HistoryResourceMixin,
|
|||
|
||||
self.pre_delete(obj)
|
||||
self.pre_conditions_on_delete(obj)
|
||||
obj.delete_related_content()
|
||||
obj.delete()
|
||||
self.post_delete(obj)
|
||||
|
||||
services.orphan_project(obj)
|
||||
if settings.CELERY_ENABLED:
|
||||
services.delete_project.delay(obj.id)
|
||||
else:
|
||||
services.delete_project(obj.id)
|
||||
|
||||
return response.NoContent()
|
||||
|
||||
|
||||
|
|
|
@ -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'),
|
||||
),
|
||||
]
|
|
@ -157,7 +157,7 @@ class Project(ProjectDefaults, TaggedMixin, models.Model):
|
|||
default=timezone.now)
|
||||
modified_date = models.DateTimeField(null=False, blank=False,
|
||||
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"))
|
||||
members = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="projects",
|
||||
through="Membership", verbose_name=_("members"),
|
||||
|
|
|
@ -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_transfered
|
||||
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
|
||||
|
|
|
@ -15,8 +15,9 @@
|
|||
# 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/>.
|
||||
|
||||
from django.apps import apps
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from taiga.celery import app
|
||||
|
||||
ERROR_MAX_PUBLIC_PROJECTS_MEMBERSHIPS = 'max_public_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 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()
|
||||
|
|
|
@ -19,6 +19,8 @@ from easy_thumbnails.files import generate_all_aliases, get_thumbnailer
|
|||
import os.path
|
||||
import pytest
|
||||
|
||||
from unittest import mock
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue