Issue#2943: Regenerate refs for tasks, issues and user stories on project change

remotes/origin/enhancement/email-actions
Jesús Espino 2015-06-23 17:24:17 +02:00
parent 8167439828
commit aaf89ebb04
14 changed files with 575 additions and 47 deletions

View File

@ -31,7 +31,8 @@ from taiga.projects.notifications.mixins import WatchedResourceMixin
from taiga.projects.occ import OCCResourceMixin from taiga.projects.occ import OCCResourceMixin
from taiga.projects.history.mixins import HistoryResourceMixin from taiga.projects.history.mixins import HistoryResourceMixin
from taiga.projects.models import Project from taiga.projects.models import Project, IssueStatus, Severity, Priority, IssueType
from taiga.projects.milestones.models import Milestone
from taiga.projects.votes.utils import attach_votescount_to_queryset from taiga.projects.votes.utils import attach_votescount_to_queryset
from taiga.projects.votes import services as votes_service from taiga.projects.votes import services as votes_service
from taiga.projects.votes import serializers as votes_serializers from taiga.projects.votes import serializers as votes_serializers
@ -121,6 +122,60 @@ class IssueViewSet(OCCResourceMixin, HistoryResourceMixin, WatchedResourceMixin,
"assigned_to", "assigned_to",
"subject") "subject")
def update(self, request, *args, **kwargs):
self.object = self.get_object_or_none()
project_id = request.DATA.get('project', None)
if project_id and self.object and self.object.project.id != project_id:
try:
new_project = Project.objects.get(pk=project_id)
self.check_permissions(request, "destroy", self.object)
self.check_permissions(request, "create", new_project)
sprint_id = request.DATA.get('milestone', None)
if sprint_id is not None and new_project.milestones.filter(pk=sprint_id).count() == 0:
request.DATA['milestone'] = None
status_id = request.DATA.get('status', None)
if status_id is not None:
try:
old_status = self.object.project.issue_statuses.get(pk=status_id)
new_status = new_project.issue_statuses.get(slug=old_status.slug)
request.DATA['status'] = new_status.id
except IssueStatus.DoesNotExist:
request.DATA['status'] = new_project.default_issue_status.id
priority_id = request.DATA.get('priority', None)
if priority_id is not None:
try:
old_priority = self.object.project.priorities.get(pk=priority_id)
new_priority = new_project.priorities.get(name=old_priority.name)
request.DATA['priority'] = new_priority.id
except Priority.DoesNotExist:
request.DATA['priority'] = new_project.default_priority.id
severity_id = request.DATA.get('severity', None)
if severity_id is not None:
try:
old_severity = self.object.project.severities.get(pk=severity_id)
new_severity = new_project.severities.get(name=old_severity.name)
request.DATA['severity'] = new_severity.id
except Severity.DoesNotExist:
request.DATA['severity'] = new_project.default_severity.id
type_id = request.DATA.get('type', None)
if type_id is not None:
try:
old_type = self.object.project.issue_types.get(pk=type_id)
new_type = new_project.issue_types.get(name=old_type.name)
request.DATA['type'] = new_type.id
except IssueType.DoesNotExist:
request.DATA['type'] = new_project.default_issue_type.id
except Project.DoesNotExist:
return response.BadRequest(_("The project doesn't exist"))
return super().update(request, *args, **kwargs)
def get_queryset(self): def get_queryset(self):
qs = models.Issue.objects.all() qs = models.Issue.objects.all()
qs = qs.prefetch_related("attachments") qs = qs.prefetch_related("attachments")
@ -130,6 +185,7 @@ class IssueViewSet(OCCResourceMixin, HistoryResourceMixin, WatchedResourceMixin,
def pre_save(self, obj): def pre_save(self, obj):
if not obj.id: if not obj.id:
obj.owner = self.request.user obj.owner = self.request.user
super().pre_save(obj) super().pre_save(obj)
def pre_conditions_on_save(self, obj): def pre_conditions_on_save(self, obj):

View File

@ -80,8 +80,17 @@ def delete_sequence(sender, instance, **kwargs):
seq.delete(seqname) seq.delete(seqname)
def store_previous_project(sender, instance, **kwargs):
try:
prev_instance = sender.objects.get(pk=instance.pk)
instance.prev_project = prev_instance.project
except sender.DoesNotExist:
instance.prev_project = None
def attach_sequence(sender, instance, created, **kwargs): def attach_sequence(sender, instance, created, **kwargs):
if created and not instance._importing: if not instance._importing:
if created or instance.prev_project != instance.project:
# Create a reference object. This operation should be # Create a reference object. This operation should be
# used in transaction context, otherwise it can # used in transaction context, otherwise it can
# create a lot of phantom reference objects. # create a lot of phantom reference objects.
@ -93,6 +102,9 @@ def attach_sequence(sender, instance, created, **kwargs):
models.signals.post_save.connect(create_sequence, sender=Project, dispatch_uid="refproj") models.signals.post_save.connect(create_sequence, sender=Project, dispatch_uid="refproj")
models.signals.pre_save.connect(store_previous_project, sender=UserStory, dispatch_uid="refus")
models.signals.pre_save.connect(store_previous_project, sender=Issue, dispatch_uid="refissue")
models.signals.pre_save.connect(store_previous_project, sender=Task, dispatch_uid="reftask")
models.signals.post_save.connect(attach_sequence, sender=UserStory, dispatch_uid="refus") models.signals.post_save.connect(attach_sequence, sender=UserStory, dispatch_uid="refus")
models.signals.post_save.connect(attach_sequence, sender=Issue, dispatch_uid="refissue") models.signals.post_save.connect(attach_sequence, sender=Issue, dispatch_uid="refissue")
models.signals.post_save.connect(attach_sequence, sender=Task, dispatch_uid="reftask") models.signals.post_save.connect(attach_sequence, sender=Task, dispatch_uid="reftask")

View File

@ -21,7 +21,7 @@ from taiga.base import filters, response
from taiga.base import exceptions as exc from taiga.base import exceptions as exc
from taiga.base.decorators import list_route from taiga.base.decorators import list_route
from taiga.base.api import ModelCrudViewSet from taiga.base.api import ModelCrudViewSet
from taiga.projects.models import Project from taiga.projects.models import Project, TaskStatus
from django.http import HttpResponse from django.http import HttpResponse
from taiga.projects.notifications.mixins import WatchedResourceMixin from taiga.projects.notifications.mixins import WatchedResourceMixin
@ -44,6 +44,38 @@ class TaskViewSet(OCCResourceMixin, HistoryResourceMixin, WatchedResourceMixin,
filter_fields = ["user_story", "milestone", "project", "assigned_to", filter_fields = ["user_story", "milestone", "project", "assigned_to",
"status__is_closed", "watchers"] "status__is_closed", "watchers"]
def update(self, request, *args, **kwargs):
self.object = self.get_object_or_none()
project_id = request.DATA.get('project', None)
if project_id and self.object and self.object.project.id != project_id:
try:
new_project = Project.objects.get(pk=project_id)
self.check_permissions(request, "destroy", self.object)
self.check_permissions(request, "create", new_project)
sprint_id = request.DATA.get('milestone', None)
if sprint_id is not None and new_project.milestones.filter(pk=sprint_id).count() == 0:
request.DATA['milestone'] = None
us_id = request.DATA.get('user_story', None)
if us_id is not None and new_project.user_stories.filter(pk=us_id).count() == 0:
request.DATA['user_story'] = None
status_id = request.DATA.get('status', None)
if status_id is not None:
try:
old_status = self.object.project.task_statuses.get(pk=status_id)
new_status = new_project.task_statuses.get(slug=old_status.slug)
request.DATA['status'] = new_status.id
except TaskStatus.DoesNotExist:
request.DATA['status'] = new_project.default_task_status.id
except Project.DoesNotExist:
return response.BadRequest(_("The project doesn't exist"))
return super().update(request, *args, **kwargs)
def pre_save(self, obj): def pre_save(self, obj):
if obj.user_story: if obj.user_story:
obj.milestone = obj.user_story.milestone obj.milestone = obj.user_story.milestone
@ -55,16 +87,16 @@ class TaskViewSet(OCCResourceMixin, HistoryResourceMixin, WatchedResourceMixin,
super().pre_conditions_on_save(obj) super().pre_conditions_on_save(obj)
if obj.milestone and obj.milestone.project != obj.project: if obj.milestone and obj.milestone.project != obj.project:
raise exc.WrongArguments(_("You don't have permissions for add/modify this task.")) raise exc.WrongArguments(_("You don't have permissions to set this sprint to this task."))
if obj.user_story and obj.user_story.project != obj.project: if obj.user_story and obj.user_story.project != obj.project:
raise exc.WrongArguments(_("You don't have permissions for add/modify this task.")) raise exc.WrongArguments(_("You don't have permissions to set this user story to this task."))
if obj.status and obj.status.project != obj.project: if obj.status and obj.status.project != obj.project:
raise exc.WrongArguments(_("You don't have permissions for add/modify this task.")) raise exc.WrongArguments(_("You don't have permissions to set this status to this task."))
if obj.milestone and obj.user_story and obj.milestone != obj.user_story.milestone: if obj.milestone and obj.user_story and obj.milestone != obj.user_story.milestone:
raise exc.WrongArguments(_("You don't have permissions for add/modify this task.")) raise exc.WrongArguments(_("You don't have permissions to set this sprint to this task."))
@list_route(methods=["GET"]) @list_route(methods=["GET"])
def by_ref(self, request): def by_ref(self, request):

View File

@ -62,6 +62,33 @@ class UserStoryViewSet(OCCResourceMixin, HistoryResourceMixin, WatchedResourceMi
# Specific filter used for filtering neighbor user stories # Specific filter used for filtering neighbor user stories
_neighbor_tags_filter = filters.TagsFilter('neighbor_tags') _neighbor_tags_filter = filters.TagsFilter('neighbor_tags')
def update(self, request, *args, **kwargs):
self.object = self.get_object_or_none()
project_id = request.DATA.get('project', None)
if project_id and self.object and self.object.project.id != project_id:
try:
new_project = Project.objects.get(pk=project_id)
self.check_permissions(request, "destroy", self.object)
self.check_permissions(request, "create", new_project)
sprint_id = request.DATA.get('milestone', None)
if sprint_id is not None and new_project.milestones.filter(pk=sprint_id).count() == 0:
request.DATA['milestone'] = None
status_id = request.DATA.get('status', None)
if status_id is not None:
try:
old_status = self.object.project.us_statuses.get(pk=status_id)
new_status = new_project.us_statuses.get(slug=old_status.slug)
request.DATA['status'] = new_status.id
except UserStoryStatus.DoesNotExist:
request.DATA['status'] = new_project.default_us_status.id
except Project.DoesNotExist:
return response.BadRequest(_("The project doesn't exist"))
return super().update(request, *args, **kwargs)
def get_queryset(self): def get_queryset(self):
qs = self.model.objects.all() qs = self.model.objects.all()
qs = qs.prefetch_related("role_points", qs = qs.prefetch_related("role_points",
@ -100,6 +127,17 @@ class UserStoryViewSet(OCCResourceMixin, HistoryResourceMixin, WatchedResourceMi
super().post_save(obj, created) super().post_save(obj, created)
def pre_conditions_on_save(self, obj):
super().pre_conditions_on_save(obj)
if obj.milestone and obj.milestone.project != obj.project:
raise exc.PermissionDenied(_("You don't have permissions to set this sprint "
"to this user story."))
if obj.status and obj.status.project != obj.project:
raise exc.PermissionDenied(_("You don't have permissions to set this status "
"to this user story."))
@list_route(methods=["GET"]) @list_route(methods=["GET"])
def by_ref(self, request): def by_ref(self, request):
ref = request.QUERY_PARAMS.get("ref", None) ref = request.QUERY_PARAMS.get("ref", None)

View File

@ -231,6 +231,7 @@ class UserStoryFactory(Factory):
subject = factory.Sequence(lambda n: "User Story {}".format(n)) subject = factory.Sequence(lambda n: "User Story {}".format(n))
description = factory.Sequence(lambda n: "User Story {} description".format(n)) description = factory.Sequence(lambda n: "User Story {} description".format(n))
status = factory.SubFactory("tests.factories.UserStoryStatusFactory") status = factory.SubFactory("tests.factories.UserStoryStatusFactory")
milestone = factory.SubFactory("tests.factories.MilestoneFactory")
class UserStoryStatusFactory(Factory): class UserStoryStatusFactory(Factory):

View File

@ -160,6 +160,119 @@ def test_issue_update(client, data):
assert results == [401, 403, 403, 200, 200] assert results == [401, 403, 403, 200, 200]
def test_issue_update_with_project_change(client):
user1 = f.UserFactory.create()
user2 = f.UserFactory.create()
user3 = f.UserFactory.create()
user4 = f.UserFactory.create()
project1 = f.ProjectFactory()
project2 = f.ProjectFactory()
issue_status1 = f.IssueStatusFactory.create(project=project1)
issue_status2 = f.IssueStatusFactory.create(project=project2)
priority1 = f.PriorityFactory.create(project=project1)
priority2 = f.PriorityFactory.create(project=project2)
severity1 = f.SeverityFactory.create(project=project1)
severity2 = f.SeverityFactory.create(project=project2)
issue_type1 = f.IssueTypeFactory.create(project=project1)
issue_type2 = f.IssueTypeFactory.create(project=project2)
project1.default_issue_status = issue_status1
project2.default_issue_status = issue_status2
project1.default_priority = priority1
project2.default_priority = priority2
project1.default_severity = severity1
project2.default_severity = severity2
project1.default_issue_type = issue_type1
project2.default_issue_type = issue_type2
project1.save()
project2.save()
membership1 = f.MembershipFactory(project=project1,
user=user1,
role__project=project1,
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
membership2 = f.MembershipFactory(project=project2,
user=user1,
role__project=project2,
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
membership3 = f.MembershipFactory(project=project1,
user=user2,
role__project=project1,
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
membership4 = f.MembershipFactory(project=project2,
user=user3,
role__project=project2,
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
issue = f.IssueFactory.create(project=project1)
url = reverse('issues-detail', kwargs={"pk": issue.pk})
# Test user with permissions in both projects
client.login(user1)
issue_data = IssueSerializer(issue).data
issue_data["project"] = project2.id
issue_data = json.dumps(issue_data)
response = client.put(url, data=issue_data, content_type="application/json")
assert response.status_code == 200
issue.project = project1
issue.save()
# Test user with permissions in only origin project
client.login(user2)
issue_data = IssueSerializer(issue).data
issue_data["project"] = project2.id
issue_data = json.dumps(issue_data)
response = client.put(url, data=issue_data, content_type="application/json")
assert response.status_code == 403
issue.project = project1
issue.save()
# Test user with permissions in only destionation project
client.login(user3)
issue_data = IssueSerializer(issue).data
issue_data["project"] = project2.id
issue_data = json.dumps(issue_data)
response = client.put(url, data=issue_data, content_type="application/json")
assert response.status_code == 403
issue.project = project1
issue.save()
# Test user without permissions in the projects
client.login(user4)
issue_data = IssueSerializer(issue).data
issue_data["project"] = project2.id
issue_data = json.dumps(issue_data)
response = client.put(url, data=issue_data, content_type="application/json")
assert response.status_code == 403
issue.project = project1
issue.save()
def test_issue_delete(client, data): def test_issue_delete(client, data):
public_url = reverse('issues-detail', kwargs={"pk": data.public_issue.pk}) public_url = reverse('issues-detail', kwargs={"pk": data.public_issue.pk})
private_url1 = reverse('issues-detail', kwargs={"pk": data.private_issue1.pk}) private_url1 = reverse('issues-detail', kwargs={"pk": data.private_issue1.pk})

View File

@ -83,18 +83,25 @@ def data():
user=m.project_owner, user=m.project_owner,
is_owner=True) is_owner=True)
milestone_public_task = f.MilestoneFactory(project=m.public_project)
milestone_private_task1 = f.MilestoneFactory(project=m.private_project1)
milestone_private_task2 = f.MilestoneFactory(project=m.private_project2)
m.public_task = f.TaskFactory(project=m.public_project, m.public_task = f.TaskFactory(project=m.public_project,
status__project=m.public_project, status__project=m.public_project,
milestone__project=m.public_project, milestone=milestone_public_task,
user_story__project=m.public_project) user_story__project=m.public_project,
user_story__milestone=milestone_public_task)
m.private_task1 = f.TaskFactory(project=m.private_project1, m.private_task1 = f.TaskFactory(project=m.private_project1,
status__project=m.private_project1, status__project=m.private_project1,
milestone__project=m.private_project1, milestone=milestone_private_task1,
user_story__project=m.private_project1) user_story__project=m.private_project1,
user_story__milestone=milestone_private_task1)
m.private_task2 = f.TaskFactory(project=m.private_project2, m.private_task2 = f.TaskFactory(project=m.private_project2,
status__project=m.private_project2, status__project=m.private_project2,
milestone__project=m.private_project2, milestone=milestone_private_task2,
user_story__project=m.private_project2) user_story__project=m.private_project2,
user_story__milestone=milestone_private_task2)
m.public_project.default_task_status = m.public_task.status m.public_project.default_task_status = m.public_task.status
m.public_project.save() m.public_project.save()
@ -160,6 +167,101 @@ def test_task_update(client, data):
assert results == [401, 403, 403, 200, 200] assert results == [401, 403, 403, 200, 200]
def test_task_update_with_project_change(client):
user1 = f.UserFactory.create()
user2 = f.UserFactory.create()
user3 = f.UserFactory.create()
user4 = f.UserFactory.create()
project1 = f.ProjectFactory()
project2 = f.ProjectFactory()
task_status1 = f.TaskStatusFactory.create(project=project1)
task_status2 = f.TaskStatusFactory.create(project=project2)
project1.default_task_status = task_status1
project2.default_task_status = task_status2
project1.save()
project2.save()
membership1 = f.MembershipFactory(project=project1,
user=user1,
role__project=project1,
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
membership2 = f.MembershipFactory(project=project2,
user=user1,
role__project=project2,
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
membership3 = f.MembershipFactory(project=project1,
user=user2,
role__project=project1,
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
membership4 = f.MembershipFactory(project=project2,
user=user3,
role__project=project2,
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
task = f.TaskFactory.create(project=project1)
url = reverse('tasks-detail', kwargs={"pk": task.pk})
# Test user with permissions in both projects
client.login(user1)
task_data = TaskSerializer(task).data
task_data["project"] = project2.id
task_data = json.dumps(task_data)
response = client.put(url, data=task_data, content_type="application/json")
assert response.status_code == 200
task.project = project1
task.save()
# Test user with permissions in only origin project
client.login(user2)
task_data = TaskSerializer(task).data
task_data["project"] = project2.id
task_data = json.dumps(task_data)
response = client.put(url, data=task_data, content_type="application/json")
assert response.status_code == 403
task.project = project1
task.save()
# Test user with permissions in only destionation project
client.login(user3)
task_data = TaskSerializer(task).data
task_data["project"] = project2.id
task_data = json.dumps(task_data)
response = client.put(url, data=task_data, content_type="application/json")
assert response.status_code == 403
task.project = project1
task.save()
# Test user without permissions in the projects
client.login(user4)
task_data = TaskSerializer(task).data
task_data["project"] = project2.id
task_data = json.dumps(task_data)
response = client.put(url, data=task_data, content_type="application/json")
assert response.status_code == 403
task.project = project1
task.save()
def test_task_delete(client, data): def test_task_delete(client, data):
public_url = reverse('tasks-detail', kwargs={"pk": data.public_task.pk}) public_url = reverse('tasks-detail', kwargs={"pk": data.public_task.pk})
private_url1 = reverse('tasks-detail', kwargs={"pk": data.private_task1.pk}) private_url1 = reverse('tasks-detail', kwargs={"pk": data.private_task1.pk})

View File

@ -89,13 +89,19 @@ def data():
m.public_role_points = f.RolePointsFactory(role=m.public_project.roles.all()[0], m.public_role_points = f.RolePointsFactory(role=m.public_project.roles.all()[0],
points=m.public_points, points=m.public_points,
user_story__project=m.public_project) user_story__project=m.public_project,
user_story__milestone__project=m.public_project,
user_story__status__project=m.public_project)
m.private_role_points1 = f.RolePointsFactory(role=m.private_project1.roles.all()[0], m.private_role_points1 = f.RolePointsFactory(role=m.private_project1.roles.all()[0],
points=m.private_points1, points=m.private_points1,
user_story__project=m.private_project1) user_story__project=m.private_project1,
user_story__milestone__project=m.private_project1,
user_story__status__project=m.private_project1)
m.private_role_points2 = f.RolePointsFactory(role=m.private_project2.roles.all()[0], m.private_role_points2 = f.RolePointsFactory(role=m.private_project2.roles.all()[0],
points=m.private_points2, points=m.private_points2,
user_story__project=m.private_project2) user_story__project=m.private_project2,
user_story__milestone__project=m.private_project2,
user_story__status__project=m.private_project2)
m.public_user_story = m.public_role_points.user_story m.public_user_story = m.public_role_points.user_story
m.private_user_story1 = m.private_role_points1.user_story m.private_user_story1 = m.private_role_points1.user_story
@ -158,6 +164,101 @@ def test_user_story_update(client, data):
assert results == [401, 403, 403, 200, 200] assert results == [401, 403, 403, 200, 200]
def test_user_story_update_with_project_change(client):
user1 = f.UserFactory.create()
user2 = f.UserFactory.create()
user3 = f.UserFactory.create()
user4 = f.UserFactory.create()
project1 = f.ProjectFactory()
project2 = f.ProjectFactory()
us_status1 = f.UserStoryStatusFactory.create(project=project1)
us_status2 = f.UserStoryStatusFactory.create(project=project2)
project1.default_us_status = us_status1
project2.default_us_status = us_status2
project1.save()
project2.save()
membership1 = f.MembershipFactory(project=project1,
user=user1,
role__project=project1,
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
membership2 = f.MembershipFactory(project=project2,
user=user1,
role__project=project2,
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
membership3 = f.MembershipFactory(project=project1,
user=user2,
role__project=project1,
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
membership4 = f.MembershipFactory(project=project2,
user=user3,
role__project=project2,
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
us = f.UserStoryFactory.create(project=project1)
url = reverse('userstories-detail', kwargs={"pk": us.pk})
# Test user with permissions in both projects
client.login(user1)
us_data = UserStorySerializer(us).data
us_data["project"] = project2.id
us_data = json.dumps(us_data)
response = client.put(url, data=us_data, content_type="application/json")
assert response.status_code == 200
us.project = project1
us.save()
# Test user with permissions in only origin project
client.login(user2)
us_data = UserStorySerializer(us).data
us_data["project"] = project2.id
us_data = json.dumps(us_data)
response = client.put(url, data=us_data, content_type="application/json")
assert response.status_code == 403
us.project = project1
us.save()
# Test user with permissions in only destionation project
client.login(user3)
us_data = UserStorySerializer(us).data
us_data["project"] = project2.id
us_data = json.dumps(us_data)
response = client.put(url, data=us_data, content_type="application/json")
assert response.status_code == 403
us.project = project1
us.save()
# Test user without permissions in the projects
client.login(user4)
us_data = UserStorySerializer(us).data
us_data["project"] = project2.id
us_data = json.dumps(us_data)
response = client.put(url, data=us_data, content_type="application/json")
assert response.status_code == 403
us.project = project1
us.save()
def test_user_story_delete(client, data): def test_user_story_delete(client, data):
public_url = reverse('userstories-detail', kwargs={"pk": data.public_user_story.pk}) public_url = reverse('userstories-detail', kwargs={"pk": data.public_user_story.pk})
private_url1 = reverse('userstories-detail', kwargs={"pk": data.private_user_story1.pk}) private_url1 = reverse('userstories-detail', kwargs={"pk": data.private_user_story1.pk})

View File

@ -199,7 +199,7 @@ def test_take_hidden_snapshot():
def test_history_with_only_comment_shouldnot_be_hidden(client): def test_history_with_only_comment_shouldnot_be_hidden(client):
project = f.create_project() project = f.create_project()
us = f.create_userstory(project=project) us = f.create_userstory(project=project, status__project=project)
f.MembershipFactory.create(project=project, user=project.owner, is_owner=True) f.MembershipFactory.create(project=project, user=project.owner, is_owner=True)
qs_all = HistoryEntry.objects.all() qs_all = HistoryEntry.objects.all()
@ -213,7 +213,7 @@ def test_history_with_only_comment_shouldnot_be_hidden(client):
client.login(project.owner) client.login(project.owner)
response = client.patch(url, data, content_type="application/json") response = client.patch(url, data, content_type="application/json")
assert response.status_code == 200, response.content assert response.status_code == 200, str(response.content)
assert qs_all.count() == 1 assert qs_all.count() == 1
assert qs_hidden.count() == 0 assert qs_hidden.count() == 0

View File

@ -32,6 +32,7 @@ from taiga.projects.history.services import take_snapshot
from taiga.projects.issues.serializers import IssueSerializer from taiga.projects.issues.serializers import IssueSerializer
from taiga.projects.userstories.serializers import UserStorySerializer from taiga.projects.userstories.serializers import UserStorySerializer
from taiga.projects.tasks.serializers import TaskSerializer from taiga.projects.tasks.serializers import TaskSerializer
from taiga.permissions.permissions import MEMBERS_PERMISSIONS
pytestmark = pytest.mark.django_db pytestmark = pytest.mark.django_db
@ -317,7 +318,7 @@ def test_watchers_assignation_for_issue(client):
url = reverse("issues-detail", args=[issue.pk]) url = reverse("issues-detail", args=[issue.pk])
response = client.json.patch(url, json.dumps(data)) response = client.json.patch(url, json.dumps(data))
assert response.status_code == 200, response.content assert response.status_code == 200, str(response.content)
issue = f.create_issue(project=project1, owner=user1) issue = f.create_issue(project=project1, owner=user1)
data = {"version": issue.version, data = {"version": issue.version,
@ -356,22 +357,22 @@ def test_watchers_assignation_for_task(client):
user2 = f.UserFactory.create() user2 = f.UserFactory.create()
project1 = f.ProjectFactory.create(owner=user1) project1 = f.ProjectFactory.create(owner=user1)
project2 = f.ProjectFactory.create(owner=user2) project2 = f.ProjectFactory.create(owner=user2)
role1 = f.RoleFactory.create(project=project1) role1 = f.RoleFactory.create(project=project1, permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
role2 = f.RoleFactory.create(project=project2) role2 = f.RoleFactory.create(project=project2)
f.MembershipFactory.create(project=project1, user=user1, role=role1, is_owner=True) f.MembershipFactory.create(project=project1, user=user1, role=role1, is_owner=True)
f.MembershipFactory.create(project=project2, user=user2, role=role2) f.MembershipFactory.create(project=project2, user=user2, role=role2)
client.login(user1) client.login(user1)
task = f.create_task(project=project1, owner=user1) task = f.create_task(project=project1, owner=user1, status__project=project1, milestone__project=project1, user_story=None)
data = {"version": task.version, data = {"version": task.version,
"watchers": [user1.pk]} "watchers": [user1.pk]}
url = reverse("tasks-detail", args=[task.pk]) url = reverse("tasks-detail", args=[task.pk])
response = client.json.patch(url, json.dumps(data)) response = client.json.patch(url, json.dumps(data))
assert response.status_code == 200, response.content assert response.status_code == 200, str(response.content)
task = f.create_task(project=project1, owner=user1) task = f.create_task(project=project1, owner=user1, status__project=project1, milestone__project=project1)
data = {"version": task.version, data = {"version": task.version,
"watchers": [user1.pk, user2.pk]} "watchers": [user1.pk, user2.pk]}
@ -379,7 +380,7 @@ def test_watchers_assignation_for_task(client):
response = client.json.patch(url, json.dumps(data)) response = client.json.patch(url, json.dumps(data))
assert response.status_code == 400 assert response.status_code == 400
task = f.create_task(project=project1, owner=user1) task = f.create_task(project=project1, owner=user1, status__project=project1, milestone__project=project1)
data = dict(TaskSerializer(task).data) data = dict(TaskSerializer(task).data)
data["id"] = None data["id"] = None
data["version"] = None data["version"] = None
@ -391,7 +392,7 @@ def test_watchers_assignation_for_task(client):
# Test the impossible case when project is not # Test the impossible case when project is not
# exists in create request, and validator works as expected # exists in create request, and validator works as expected
task = f.create_task(project=project1, owner=user1) task = f.create_task(project=project1, owner=user1, status__project=project1, milestone__project=project1)
data = dict(TaskSerializer(task).data) data = dict(TaskSerializer(task).data)
data["id"] = None data["id"] = None
@ -415,15 +416,15 @@ def test_watchers_assignation_for_us(client):
client.login(user1) client.login(user1)
us = f.create_userstory(project=project1, owner=user1) us = f.create_userstory(project=project1, owner=user1, status__project=project1)
data = {"version": us.version, data = {"version": us.version,
"watchers": [user1.pk]} "watchers": [user1.pk]}
url = reverse("userstories-detail", args=[us.pk]) url = reverse("userstories-detail", args=[us.pk])
response = client.json.patch(url, json.dumps(data)) response = client.json.patch(url, json.dumps(data))
assert response.status_code == 200 assert response.status_code == 200, str(response.content)
us = f.create_userstory(project=project1, owner=user1) us = f.create_userstory(project=project1, owner=user1, status__project=project1)
data = {"version": us.version, data = {"version": us.version,
"watchers": [user1.pk, user2.pk]} "watchers": [user1.pk, user2.pk]}
@ -431,7 +432,7 @@ def test_watchers_assignation_for_us(client):
response = client.json.patch(url, json.dumps(data)) response = client.json.patch(url, json.dumps(data))
assert response.status_code == 400 assert response.status_code == 400
us = f.create_userstory(project=project1, owner=user1) us = f.create_userstory(project=project1, owner=user1, status__project=project1)
data = dict(UserStorySerializer(us).data) data = dict(UserStorySerializer(us).data)
data["id"] = None data["id"] = None
data["version"] = None data["version"] = None
@ -443,7 +444,7 @@ def test_watchers_assignation_for_us(client):
# Test the impossible case when project is not # Test the impossible case when project is not
# exists in create request, and validator works as expected # exists in create request, and validator works as expected
us = f.create_userstory(project=project1, owner=user1) us = f.create_userstory(project=project1, owner=user1, status__project=project1)
data = dict(UserStorySerializer(us).data) data = dict(UserStorySerializer(us).data)
data["id"] = None data["id"] = None
@ -463,4 +464,4 @@ def test_retrieve_notify_policies_by_anonymous_user(client):
url = reverse("notifications-detail", args=[policy.pk]) url = reverse("notifications-detail", args=[policy.pk])
response = client.get(url, content_type="application/json") response = client.get(url, content_type="application/json")
assert response.status_code == 404, response.status_code assert response.status_code == 404, response.status_code
assert response.data["_error_message"] == "No NotifyPolicy matches the given query.", response.content assert response.data["_error_message"] == "No NotifyPolicy matches the given query.", str(response.content)

View File

@ -74,3 +74,70 @@ def test_unique_reference_per_project(seq, refmodels):
project.delete() project.delete()
assert not seq.exists(seqname) assert not seq.exists(seqname)
@pytest.mark.django_db
def test_regenerate_us_reference_on_project_change(seq, refmodels):
project1 = factories.ProjectFactory.create()
seqname1 = refmodels.make_sequence_name(project1)
project2 = factories.ProjectFactory.create()
seqname2 = refmodels.make_sequence_name(project2)
seq.alter(seqname1, 100)
seq.alter(seqname2, 200)
user_story = factories.UserStoryFactory.create(project=project1)
assert user_story.ref == 101
user_story.subject = "other"
user_story.save()
assert user_story.ref == 101
user_story.project = project2
user_story.save()
assert user_story.ref == 201
@pytest.mark.django_db
def test_regenerate_task_reference_on_project_change(seq, refmodels):
project1 = factories.ProjectFactory.create()
seqname1 = refmodels.make_sequence_name(project1)
project2 = factories.ProjectFactory.create()
seqname2 = refmodels.make_sequence_name(project2)
seq.alter(seqname1, 100)
seq.alter(seqname2, 200)
task = factories.TaskFactory.create(project=project1)
assert task.ref == 101
task.subject = "other"
task.save()
assert task.ref == 101
task.project = project2
task.save()
assert task.ref == 201
@pytest.mark.django_db
def test_regenerate_issue_reference_on_project_change(seq, refmodels):
project1 = factories.ProjectFactory.create()
seqname1 = refmodels.make_sequence_name(project1)
project2 = factories.ProjectFactory.create()
seqname2 = refmodels.make_sequence_name(project2)
seq.alter(seqname1, 100)
seq.alter(seqname2, 200)
issue = factories.IssueFactory.create(project=project1)
assert issue.ref == 101
issue.subject = "other"
issue.save()
assert issue.ref == 101
issue.project = project2
issue.save()
assert issue.ref == 201

View File

@ -37,19 +37,23 @@ def data():
m.role_points1 = f.RolePointsFactory(role=m.role1, m.role_points1 = f.RolePointsFactory(role=m.role1,
points=m.points1, points=m.points1,
user_story__project=m.project, user_story__project=m.project,
user_story__status=m.open_status) user_story__status=m.open_status,
user_story__milestone=None)
m.role_points2 = f.RolePointsFactory(role=m.role1, m.role_points2 = f.RolePointsFactory(role=m.role1,
points=m.points2, points=m.points2,
user_story__project=m.project, user_story__project=m.project,
user_story__status=m.open_status) user_story__status=m.open_status,
user_story__milestone=None)
m.role_points3 = f.RolePointsFactory(role=m.role1, m.role_points3 = f.RolePointsFactory(role=m.role1,
points=m.points3, points=m.points3,
user_story__project=m.project, user_story__project=m.project,
user_story__status=m.open_status) user_story__status=m.open_status,
user_story__milestone=None)
m.role_points4 = f.RolePointsFactory(role=m.project.roles.all()[0], m.role_points4 = f.RolePointsFactory(role=m.project.roles.all()[0],
points=m.points4, points=m.points4,
user_story__project=m.project, user_story__project=m.project,
user_story__status=m.open_status) user_story__status=m.open_status,
user_story__milestone=None)
m.user_story1 = m.role_points1.user_story m.user_story1 = m.role_points1.user_story
m.user_story2 = m.role_points2.user_story m.user_story2 = m.role_points2.user_story

View File

@ -54,8 +54,9 @@ def test_create_task_without_status(client):
def test_api_update_task_tags(client): def test_api_update_task_tags(client):
task = f.create_task() project = f.ProjectFactory.create()
f.MembershipFactory.create(project=task.project, user=task.owner, is_owner=True) task = f.create_task(project=project, status__project=project, milestone=None, user_story=None)
f.MembershipFactory.create(project=project, user=task.owner, is_owner=True)
url = reverse("tasks-detail", kwargs={"pk": task.pk}) url = reverse("tasks-detail", kwargs={"pk": task.pk})
data = {"tags": ["back", "front"], "version": task.version} data = {"tags": ["back", "front"], "version": task.version}

View File

@ -152,7 +152,7 @@ def test_update_userstory_points(client):
f.PointsFactory.create(project=project, value=1) f.PointsFactory.create(project=project, value=1)
points3 = f.PointsFactory.create(project=project, value=2) points3 = f.PointsFactory.create(project=project, value=2)
us = f.UserStoryFactory.create(project=project, owner=user1) us = f.UserStoryFactory.create(project=project, owner=user1, status__project=project, milestone__project=project)
usdata = UserStorySerializer(us).data usdata = UserStorySerializer(us).data
url = reverse("userstories-detail", args=[us.pk]) url = reverse("userstories-detail", args=[us.pk])
@ -166,7 +166,7 @@ def test_update_userstory_points(client):
data["points"].update({'2000': points3.pk}) data["points"].update({'2000': points3.pk})
response = client.json.patch(url, json.dumps(data)) response = client.json.patch(url, json.dumps(data))
assert response.status_code == 200 assert response.status_code == 200, str(response.content)
assert response.data["points"] == usdata['points'] assert response.data["points"] == usdata['points']
# Api should save successful # Api should save successful