Merge pull request #364 from taigaio/issue/2943/on-project-change-regenerate-refs-for-task-issues-uss
Issue#2943: Regenerate refs for tasks, issues and user stories on project changeremotes/origin/enhancement/email-actions
commit
f73f30e6b9
|
@ -31,7 +31,8 @@ from taiga.projects.notifications.mixins import WatchedResourceMixin
|
|||
from taiga.projects.occ import OCCResourceMixin
|
||||
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 import services as votes_service
|
||||
from taiga.projects.votes import serializers as votes_serializers
|
||||
|
@ -121,6 +122,60 @@ class IssueViewSet(OCCResourceMixin, HistoryResourceMixin, WatchedResourceMixin,
|
|||
"assigned_to",
|
||||
"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):
|
||||
qs = models.Issue.objects.all()
|
||||
qs = qs.prefetch_related("attachments")
|
||||
|
@ -130,6 +185,7 @@ class IssueViewSet(OCCResourceMixin, HistoryResourceMixin, WatchedResourceMixin,
|
|||
def pre_save(self, obj):
|
||||
if not obj.id:
|
||||
obj.owner = self.request.user
|
||||
|
||||
super().pre_save(obj)
|
||||
|
||||
def pre_conditions_on_save(self, obj):
|
||||
|
|
|
@ -80,19 +80,31 @@ def delete_sequence(sender, instance, **kwargs):
|
|||
seq.delete(seqname)
|
||||
|
||||
|
||||
def attach_sequence(sender, instance, created, **kwargs):
|
||||
if created and not instance._importing:
|
||||
# Create a reference object. This operation should be
|
||||
# used in transaction context, otherwise it can
|
||||
# create a lot of phantom reference objects.
|
||||
refval, _ = make_reference(instance, instance.project)
|
||||
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
|
||||
|
||||
# Additionally, attach sequence number to instance as ref
|
||||
instance.ref = refval
|
||||
instance.save(update_fields=['ref'])
|
||||
|
||||
def attach_sequence(sender, instance, created, **kwargs):
|
||||
if not instance._importing:
|
||||
if created or instance.prev_project != instance.project:
|
||||
# Create a reference object. This operation should be
|
||||
# used in transaction context, otherwise it can
|
||||
# create a lot of phantom reference objects.
|
||||
refval, _ = make_reference(instance, instance.project)
|
||||
|
||||
# Additionally, attach sequence number to instance as ref
|
||||
instance.ref = refval
|
||||
instance.save(update_fields=['ref'])
|
||||
|
||||
|
||||
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=Issue, dispatch_uid="refissue")
|
||||
models.signals.post_save.connect(attach_sequence, sender=Task, dispatch_uid="reftask")
|
||||
|
|
|
@ -21,7 +21,7 @@ from taiga.base import filters, response
|
|||
from taiga.base import exceptions as exc
|
||||
from taiga.base.decorators import list_route
|
||||
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 taiga.projects.notifications.mixins import WatchedResourceMixin
|
||||
|
@ -44,6 +44,38 @@ class TaskViewSet(OCCResourceMixin, HistoryResourceMixin, WatchedResourceMixin,
|
|||
filter_fields = ["user_story", "milestone", "project", "assigned_to",
|
||||
"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):
|
||||
if obj.user_story:
|
||||
obj.milestone = obj.user_story.milestone
|
||||
|
@ -55,16 +87,16 @@ class TaskViewSet(OCCResourceMixin, HistoryResourceMixin, WatchedResourceMixin,
|
|||
super().pre_conditions_on_save(obj)
|
||||
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
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"])
|
||||
def by_ref(self, request):
|
||||
|
|
|
@ -62,6 +62,33 @@ class UserStoryViewSet(OCCResourceMixin, HistoryResourceMixin, WatchedResourceMi
|
|||
# Specific filter used for filtering neighbor user stories
|
||||
_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):
|
||||
qs = self.model.objects.all()
|
||||
qs = qs.prefetch_related("role_points",
|
||||
|
@ -100,6 +127,17 @@ class UserStoryViewSet(OCCResourceMixin, HistoryResourceMixin, WatchedResourceMi
|
|||
|
||||
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"])
|
||||
def by_ref(self, request):
|
||||
ref = request.QUERY_PARAMS.get("ref", None)
|
||||
|
|
|
@ -231,6 +231,7 @@ class UserStoryFactory(Factory):
|
|||
subject = factory.Sequence(lambda n: "User Story {}".format(n))
|
||||
description = factory.Sequence(lambda n: "User Story {} description".format(n))
|
||||
status = factory.SubFactory("tests.factories.UserStoryStatusFactory")
|
||||
milestone = factory.SubFactory("tests.factories.MilestoneFactory")
|
||||
|
||||
|
||||
class UserStoryStatusFactory(Factory):
|
||||
|
|
|
@ -160,6 +160,119 @@ def test_issue_update(client, data):
|
|||
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):
|
||||
public_url = reverse('issues-detail', kwargs={"pk": data.public_issue.pk})
|
||||
private_url1 = reverse('issues-detail', kwargs={"pk": data.private_issue1.pk})
|
||||
|
|
|
@ -83,18 +83,25 @@ def data():
|
|||
user=m.project_owner,
|
||||
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,
|
||||
status__project=m.public_project,
|
||||
milestone__project=m.public_project,
|
||||
user_story__project=m.public_project)
|
||||
milestone=milestone_public_task,
|
||||
user_story__project=m.public_project,
|
||||
user_story__milestone=milestone_public_task)
|
||||
m.private_task1 = f.TaskFactory(project=m.private_project1,
|
||||
status__project=m.private_project1,
|
||||
milestone__project=m.private_project1,
|
||||
user_story__project=m.private_project1)
|
||||
milestone=milestone_private_task1,
|
||||
user_story__project=m.private_project1,
|
||||
user_story__milestone=milestone_private_task1)
|
||||
m.private_task2 = f.TaskFactory(project=m.private_project2,
|
||||
status__project=m.private_project2,
|
||||
milestone__project=m.private_project2,
|
||||
user_story__project=m.private_project2)
|
||||
milestone=milestone_private_task2,
|
||||
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.save()
|
||||
|
@ -160,6 +167,101 @@ def test_task_update(client, data):
|
|||
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):
|
||||
public_url = reverse('tasks-detail', kwargs={"pk": data.public_task.pk})
|
||||
private_url1 = reverse('tasks-detail', kwargs={"pk": data.private_task1.pk})
|
||||
|
|
|
@ -89,13 +89,19 @@ def data():
|
|||
|
||||
m.public_role_points = f.RolePointsFactory(role=m.public_project.roles.all()[0],
|
||||
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],
|
||||
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],
|
||||
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.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]
|
||||
|
||||
|
||||
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):
|
||||
public_url = reverse('userstories-detail', kwargs={"pk": data.public_user_story.pk})
|
||||
private_url1 = reverse('userstories-detail', kwargs={"pk": data.private_user_story1.pk})
|
||||
|
|
|
@ -199,7 +199,7 @@ def test_take_hidden_snapshot():
|
|||
|
||||
def test_history_with_only_comment_shouldnot_be_hidden(client):
|
||||
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)
|
||||
|
||||
qs_all = HistoryEntry.objects.all()
|
||||
|
@ -213,7 +213,7 @@ def test_history_with_only_comment_shouldnot_be_hidden(client):
|
|||
client.login(project.owner)
|
||||
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_hidden.count() == 0
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ from taiga.projects.history.services import take_snapshot
|
|||
from taiga.projects.issues.serializers import IssueSerializer
|
||||
from taiga.projects.userstories.serializers import UserStorySerializer
|
||||
from taiga.projects.tasks.serializers import TaskSerializer
|
||||
from taiga.permissions.permissions import MEMBERS_PERMISSIONS
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
@ -317,7 +318,7 @@ def test_watchers_assignation_for_issue(client):
|
|||
|
||||
url = reverse("issues-detail", args=[issue.pk])
|
||||
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)
|
||||
data = {"version": issue.version,
|
||||
|
@ -356,22 +357,22 @@ def test_watchers_assignation_for_task(client):
|
|||
user2 = f.UserFactory.create()
|
||||
project1 = f.ProjectFactory.create(owner=user1)
|
||||
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)
|
||||
f.MembershipFactory.create(project=project1, user=user1, role=role1, is_owner=True)
|
||||
f.MembershipFactory.create(project=project2, user=user2, role=role2)
|
||||
|
||||
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,
|
||||
"watchers": [user1.pk]}
|
||||
|
||||
url = reverse("tasks-detail", args=[task.pk])
|
||||
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,
|
||||
"watchers": [user1.pk, user2.pk]}
|
||||
|
||||
|
@ -379,7 +380,7 @@ def test_watchers_assignation_for_task(client):
|
|||
response = client.json.patch(url, json.dumps(data))
|
||||
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["id"] = None
|
||||
data["version"] = None
|
||||
|
@ -391,7 +392,7 @@ def test_watchers_assignation_for_task(client):
|
|||
|
||||
# Test the impossible case when project is not
|
||||
# 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["id"] = None
|
||||
|
@ -415,15 +416,15 @@ def test_watchers_assignation_for_us(client):
|
|||
|
||||
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,
|
||||
"watchers": [user1.pk]}
|
||||
|
||||
url = reverse("userstories-detail", args=[us.pk])
|
||||
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,
|
||||
"watchers": [user1.pk, user2.pk]}
|
||||
|
||||
|
@ -431,7 +432,7 @@ def test_watchers_assignation_for_us(client):
|
|||
response = client.json.patch(url, json.dumps(data))
|
||||
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["id"] = None
|
||||
data["version"] = None
|
||||
|
@ -443,7 +444,7 @@ def test_watchers_assignation_for_us(client):
|
|||
|
||||
# Test the impossible case when project is not
|
||||
# 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["id"] = None
|
||||
|
@ -463,4 +464,4 @@ def test_retrieve_notify_policies_by_anonymous_user(client):
|
|||
url = reverse("notifications-detail", args=[policy.pk])
|
||||
response = client.get(url, content_type="application/json")
|
||||
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)
|
||||
|
|
|
@ -74,3 +74,70 @@ def test_unique_reference_per_project(seq, refmodels):
|
|||
|
||||
project.delete()
|
||||
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
|
||||
|
|
|
@ -37,19 +37,23 @@ def data():
|
|||
m.role_points1 = f.RolePointsFactory(role=m.role1,
|
||||
points=m.points1,
|
||||
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,
|
||||
points=m.points2,
|
||||
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,
|
||||
points=m.points3,
|
||||
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],
|
||||
points=m.points4,
|
||||
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_story2 = m.role_points2.user_story
|
||||
|
|
|
@ -54,8 +54,9 @@ def test_create_task_without_status(client):
|
|||
|
||||
|
||||
def test_api_update_task_tags(client):
|
||||
task = f.create_task()
|
||||
f.MembershipFactory.create(project=task.project, user=task.owner, is_owner=True)
|
||||
project = f.ProjectFactory.create()
|
||||
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})
|
||||
data = {"tags": ["back", "front"], "version": task.version}
|
||||
|
||||
|
|
|
@ -152,7 +152,7 @@ def test_update_userstory_points(client):
|
|||
f.PointsFactory.create(project=project, value=1)
|
||||
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
|
||||
|
||||
url = reverse("userstories-detail", args=[us.pk])
|
||||
|
@ -166,7 +166,7 @@ def test_update_userstory_points(client):
|
|||
data["points"].update({'2000': points3.pk})
|
||||
|
||||
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']
|
||||
|
||||
# Api should save successful
|
||||
|
|
Loading…
Reference in New Issue