diff --git a/AUTHORS.rst b/AUTHORS.rst index e7b493df..7242d6b1 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -20,6 +20,7 @@ answer newbie questions, and generally made taiga that much better: - Andrés Moya - Andrey Alekseenko - Chris Wilson +- David Burke - Hector Colina - Joe Letts - Julien Palard diff --git a/CHANGELOG.md b/CHANGELOG.md index f2c92439..e8c423ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ - API: Mixin fields 'users', 'members' and 'memberships' in ProjectDetailSerializer. - API: Add stats/system resource with global server stats (total project, total users....) - API: Improve and fix some errors in issues/filters_data and userstories/filters_data. +- API: resolver suport ref GET param and return a story, task or issue. - Webhooks: Add deleted datetime to webhooks responses when isues, tasks or USs are deleted. - Add headers to allow threading for notification emails about changes to issues, tasks, user stories, and wiki pages. (thanks to [@brett](https://github.com/brettp)). - Lots of small and not so small bugfixes. diff --git a/taiga/projects/references/api.py b/taiga/projects/references/api.py index c515f6d1..4b8027cb 100644 --- a/taiga/projects/references/api.py +++ b/taiga/projects/references/api.py @@ -59,4 +59,21 @@ class ResolverViewSet(viewsets.ViewSet): result["wikipage"] = get_object_or_404(project.wiki_pages.all(), slug=data["wikipage"]).pk + if data["ref"]: + ref_found = False # No need to continue once one ref is found + if user_has_perm(request.user, "view_us", project): + us = project.user_stories.filter(ref=data["ref"]).first() + if us: + result["us"] = us.pk + ref_found = True + if ref_found is False and user_has_perm(request.user, "view_tasks", project): + task = project.tasks.filter(ref=data["ref"]).first() + if task: + result["task"] = task.pk + ref_found = True + if ref_found is False and user_has_perm(request.user, "view_issues", project): + issue = project.issues.filter(ref=data["ref"]).first() + if issue: + result["issue"] = issue.pk + return response.Ok(result) diff --git a/taiga/projects/references/serializers.py b/taiga/projects/references/serializers.py index ad9b5def..4755a897 100644 --- a/taiga/projects/references/serializers.py +++ b/taiga/projects/references/serializers.py @@ -23,4 +23,16 @@ class ResolverSerializer(serializers.Serializer): us = serializers.IntegerField(required=False) task = serializers.IntegerField(required=False) issue = serializers.IntegerField(required=False) + ref = serializers.IntegerField(required=False) wikipage = serializers.CharField(max_length=512, required=False) + + def validate(self, attrs): + if "ref" in attrs: + if "us" in attrs: + raise serializers.ValidationError("'us' param is incompatible with 'ref' in the same request") + if "task" in attrs: + raise serializers.ValidationError("'task' param is incompatible with 'ref' in the same request") + if "issue" in attrs: + raise serializers.ValidationError("'issue' param is incompatible with 'ref' in the same request") + + return attrs diff --git a/tests/integration/resources_permissions/test_resolver_resources.py b/tests/integration/resources_permissions/test_resolver_resources.py index 0cb484a3..4f5f4f54 100644 --- a/tests/integration/resources_permissions/test_resolver_resources.py +++ b/tests/integration/resources_permissions/test_resolver_resources.py @@ -128,3 +128,21 @@ def test_resolver_list(client, data): "task": data.task.pk, "issue": data.issue.pk, "milestone": data.milestone.pk} + + response = client.json.get("{}?project={}&ref={}".format(url, + data.private_project2.slug, + data.us.ref)) + assert response.data == {"project": data.private_project2.pk, + "us": data.us.pk} + + response = client.json.get("{}?project={}&ref={}".format(url, + data.private_project2.slug, + data.task.ref)) + assert response.data == {"project": data.private_project2.pk, + "task": data.task.pk} + + response = client.json.get("{}?project={}&ref={}".format(url, + data.private_project2.slug, + data.issue.ref)) + assert response.data == {"project": data.private_project2.pk, + "issue": data.issue.pk} diff --git a/tests/integration/test_references_sequences.py b/tests/integration/test_references_sequences.py index 0ec9d35f..815bf420 100644 --- a/tests/integration/test_references_sequences.py +++ b/tests/integration/test_references_sequences.py @@ -17,6 +17,8 @@ import pytest +from django.core.urlresolvers import reverse + from .. import factories @@ -141,3 +143,39 @@ def test_regenerate_issue_reference_on_project_change(seq, refmodels): issue.save() assert issue.ref == 201 + + +@pytest.mark.django_db +def test_params_validation_in_api_request(client, refmodels): + user = factories.UserFactory.create() + project = factories.ProjectFactory.create(owner=user) + seqname1 = refmodels.make_sequence_name(project) + role = factories.RoleFactory.create(project=project) + factories.MembershipFactory.create(project=project, user=user, role=role, is_owner=True) + + milestone = factories.MilestoneFactory.create(project=project) + us = factories.UserStoryFactory.create(project=project) + task = factories.TaskFactory.create(project=project) + issue = factories.IssueFactory.create(project=project) + wiki_page = factories.WikiPageFactory.create(project=project) + + client.login(user) + + url = reverse("resolver-list") + response = client.json.get(url) + assert response.status_code == 400 + response = client.json.get("{}?project={}".format(url, project.slug)) + assert response.status_code == 200 + response = client.json.get("{}?project={}&ref={}".format(url, project.slug, us.ref)) + assert response.status_code == 200 + response = client.json.get("{}?project={}&ref={}&us={}".format(url, project.slug, us.ref, us.ref)) + assert response.status_code == 400 + response = client.json.get("{}?project={}&ref={}&task={}".format(url, project.slug, us.ref, task.ref)) + assert response.status_code == 400 + response = client.json.get("{}?project={}&ref={}&issue={}".format(url, project.slug, us.ref, issue.ref)) + assert response.status_code == 400 + response = client.json.get("{}?project={}&us={}&task={}".format(url, project.slug, us.ref, task.ref)) + assert response.status_code == 200 + response = client.json.get("{}?project={}&ref={}&milestone={}".format(url, project.slug, us.ref, + milestone.slug)) + assert response.status_code == 200