From b0c57d8171d30fd00eabd4af09d0aed2dff45fe4 Mon Sep 17 00:00:00 2001 From: David Burke Date: Sat, 17 Oct 2015 15:53:28 -0400 Subject: [PATCH] Added ref GET param to resolver API. Useful if we know the the ref ID but not the type of object it is. Reduces number of API calls in cases when we want to reference an object by it's ref ID. Modified integration test to confirm ref works just like using a us, ect params and has same permissions. --- AUTHORS.rst | 1 + CHANGELOG.md | 1 + taiga/projects/references/api.py | 17 +++++++++ taiga/projects/references/serializers.py | 12 ++++++ .../test_resolver_resources.py | 18 +++++++++ .../integration/test_references_sequences.py | 38 +++++++++++++++++++ 6 files changed, 87 insertions(+) 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