diff --git a/taiga/projects/issues/serializers.py b/taiga/projects/issues/serializers.py index 2b773b81..a76fbf7d 100644 --- a/taiga/projects/issues/serializers.py +++ b/taiga/projects/issues/serializers.py @@ -25,12 +25,14 @@ from taiga.projects.mixins.serializers import OwnerExtraInfoSerializerMixin from taiga.projects.mixins.serializers import AssignedToExtraInfoSerializerMixin from taiga.projects.mixins.serializers import StatusExtraInfoSerializerMixin from taiga.projects.notifications.mixins import WatchedResourceSerializer +from taiga.projects.tagging.serializers import TaggedInProjectResourceSerializer from taiga.projects.votes.mixins.serializers import VoteResourceSerializerMixin class IssueListSerializer(VoteResourceSerializerMixin, WatchedResourceSerializer, OwnerExtraInfoSerializerMixin, AssignedToExtraInfoSerializerMixin, - StatusExtraInfoSerializerMixin, serializers.LightSerializer): + StatusExtraInfoSerializerMixin, + TaggedInProjectResourceSerializer, serializers.LightSerializer): id = Field() ref = Field() severity = Field(attr="severity_id") @@ -45,7 +47,6 @@ class IssueListSerializer(VoteResourceSerializerMixin, WatchedResourceSerializer external_reference = Field() version = Field() watchers = Field() - tags = Field() is_closed = Field() diff --git a/taiga/projects/tagging/serializers.py b/taiga/projects/tagging/serializers.py new file mode 100644 index 00000000..494b508a --- /dev/null +++ b/taiga/projects/tagging/serializers.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2014-2016 Andrey Antukh +# Copyright (C) 2014-2016 Jesús Espino +# Copyright (C) 2014-2016 David Barragán +# Copyright (C) 2014-2016 Alejandro Alonso +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from taiga.base.api import serializers +from taiga.base.fields import MethodField + + +class TaggedInProjectResourceSerializer(serializers.LightSerializer): + tags = MethodField() + + def get_tags(self, obj): + if not obj.tags: + return [] + + project_tag_colors = dict(obj.project.tags_colors) + return [[tag, project_tag_colors.get(tag, None)] for tag in obj.tags] diff --git a/taiga/projects/tagging/validators.py b/taiga/projects/tagging/validators.py index 595a5a3f..90dd98cb 100644 --- a/taiga/projects/tagging/validators.py +++ b/taiga/projects/tagging/validators.py @@ -20,6 +20,7 @@ from django.utils.translation import ugettext as _ from taiga.base.api import serializers from taiga.base.api import validators +from taiga.base.exceptions import ValidationError from . import services from . import fields @@ -43,14 +44,14 @@ class CreateTagValidator(ProjectTagValidator): def validate_tag(self, attrs, source): tag = attrs.get(source, None) if services.tag_exist_for_project_elements(self.project, tag): - raise validators.ValidationError(_("The tag exists.")) + raise ValidationError(_("The tag exists.")) return attrs def validate_color(self, attrs, source): color = attrs.get(source, None) - if not re.match('^\#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$', color): - raise validators.ValidationError(_("The color is not a valid HEX color.")) + if color is not None and not re.match('^\#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$', color): + raise ValidationError(_("The color is not a valid HEX color.")) return attrs @@ -63,21 +64,21 @@ class EditTagTagValidator(ProjectTagValidator): def validate_from_tag(self, attrs, source): tag = attrs.get(source, None) if not services.tag_exist_for_project_elements(self.project, tag): - raise validators.ValidationError(_("The tag doesn't exist.")) + raise ValidationError(_("The tag doesn't exist.")) return attrs def validate_to_tag(self, attrs, source): tag = attrs.get(source, None) if services.tag_exist_for_project_elements(self.project, tag): - raise validators.ValidationError(_("The tag exists yet")) + raise ValidationError(_("The tag exists yet")) return attrs def validate_color(self, attrs, source): color = attrs.get(source, None) if not re.match('^\#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$', color): - raise validators.ValidationError(_("The color is not a valid HEX color.")) + raise ValidationError(_("The color is not a valid HEX color.")) return attrs @@ -88,7 +89,7 @@ class DeleteTagValidator(ProjectTagValidator): def validate_tag(self, attrs, source): tag = attrs.get(source, None) if not services.tag_exist_for_project_elements(self.project, tag): - raise validators.ValidationError(_("The tag doesn't exist.")) + raise ValidationError(_("The tag doesn't exist.")) return attrs @@ -101,13 +102,13 @@ class MixTagsValidator(ProjectTagValidator): tags = attrs.get(source, None) for tag in tags: if not services.tag_exist_for_project_elements(self.project, tag): - raise validators.ValidationError(_("The tag doesn't exist.")) + raise ValidationError(_("The tag doesn't exist.")) return attrs def validate_to_tag(self, attrs, source): tag = attrs.get(source, None) if not services.tag_exist_for_project_elements(self.project, tag): - raise validators.ValidationError(_("The tag doesn't exist.")) + raise ValidationError(_("The tag doesn't exist.")) return attrs diff --git a/taiga/projects/tasks/serializers.py b/taiga/projects/tasks/serializers.py index cd649424..b7232cf8 100644 --- a/taiga/projects/tasks/serializers.py +++ b/taiga/projects/tasks/serializers.py @@ -26,13 +26,14 @@ from taiga.projects.mixins.serializers import OwnerExtraInfoSerializerMixin from taiga.projects.mixins.serializers import AssignedToExtraInfoSerializerMixin from taiga.projects.mixins.serializers import StatusExtraInfoSerializerMixin from taiga.projects.notifications.mixins import WatchedResourceSerializer +from taiga.projects.tagging.serializers import TaggedInProjectResourceSerializer from taiga.projects.votes.mixins.serializers import VoteResourceSerializerMixin class TaskListSerializer(VoteResourceSerializerMixin, WatchedResourceSerializer, OwnerExtraInfoSerializerMixin, AssignedToExtraInfoSerializerMixin, StatusExtraInfoSerializerMixin, BasicAttachmentsInfoSerializerMixin, - serializers.LightSerializer): + TaggedInProjectResourceSerializer, serializers.LightSerializer): id = Field() user_story = Field(attr="user_story_id") @@ -52,7 +53,6 @@ class TaskListSerializer(VoteResourceSerializerMixin, WatchedResourceSerializer, watchers = Field() is_blocked = Field() blocked_note = Field() - tags = Field() is_closed = MethodField() def get_milestone_slug(self, obj): diff --git a/taiga/projects/userstories/serializers.py b/taiga/projects/userstories/serializers.py index b23d5708..abb10592 100644 --- a/taiga/projects/userstories/serializers.py +++ b/taiga/projects/userstories/serializers.py @@ -22,6 +22,7 @@ from taiga.base.neighbors import NeighborsSerializerMixin from taiga.mdrender.service import render as mdrender from taiga.projects.attachments.serializers import BasicAttachmentsInfoSerializerMixin +from taiga.projects.tagging.serializers import TaggedInProjectResourceSerializer from taiga.projects.mixins.serializers import OwnerExtraInfoSerializerMixin from taiga.projects.mixins.serializers import AssignedToExtraInfoSerializerMixin from taiga.projects.mixins.serializers import StatusExtraInfoSerializerMixin @@ -45,6 +46,7 @@ class UserStoryListSerializer( VoteResourceSerializerMixin, WatchedResourceSerializer, OwnerExtraInfoSerializerMixin, AssignedToExtraInfoSerializerMixin, StatusExtraInfoSerializerMixin, BasicAttachmentsInfoSerializerMixin, + TaggedInProjectResourceSerializer, serializers.LightSerializer): id = Field() @@ -71,7 +73,6 @@ class UserStoryListSerializer( watchers = Field() is_blocked = Field() blocked_note = Field() - tags = Field() total_points = MethodField() comment = MethodField() origin_issue = OriginIssueSerializer(attr="generated_from_issue") diff --git a/tests/integration/test_issues_tags.py b/tests/integration/test_issues_tags.py index c86dc7aa..cb355f8f 100644 --- a/tests/integration/test_issues_tags.py +++ b/tests/integration/test_issues_tags.py @@ -123,7 +123,7 @@ def test_api_issue_add_new_tags_with_colors(client): def test_api_create_new_issue_with_tags(client): - project = f.ProjectFactory.create() + project = f.ProjectFactory.create(tags_colors=[["front", "#aaaaaa"], ["ux", "#fabada"]]) status = f.IssueStatusFactory.create(project=project) project.default_issue_status = status project.save() @@ -145,16 +145,17 @@ def test_api_create_new_issue_with_tags(client): response = client.json.post(url, json.dumps(data)) assert response.status_code == 201, response.data - assert ("back" in response.data["tags"] and - "front" in response.data["tags"] and - "ux" in response.data["tags"]) + issue_tags_colors = OrderedDict(response.data["tags"]) + + assert issue_tags_colors["back"] == "#fff8e7" + assert issue_tags_colors["front"] == "#aaaaaa" + assert issue_tags_colors["ux"] == "#fabada" tags_colors = OrderedDict(project.tags_colors) - assert not tags_colors.keys() project.refresh_from_db() tags_colors = OrderedDict(project.tags_colors) - assert "back" in tags_colors and "front" in tags_colors and "ux" in tags_colors assert tags_colors["back"] == "#fff8e7" assert tags_colors["ux"] == "#fabada" + assert tags_colors["front"] == "#aaaaaa" diff --git a/tests/integration/test_tasks_tags.py b/tests/integration/test_tasks_tags.py index 08bf434d..60856688 100644 --- a/tests/integration/test_tasks_tags.py +++ b/tests/integration/test_tasks_tags.py @@ -123,7 +123,7 @@ def test_api_task_add_new_tags_with_colors(client): def test_api_create_new_task_with_tags(client): - project = f.ProjectFactory.create() + project = f.ProjectFactory.create(tags_colors=[["front", "#aaaaaa"], ["ux", "#fabada"]]) status = f.TaskStatusFactory.create(project=project) project.default_task_status = status project.save() @@ -135,8 +135,8 @@ def test_api_create_new_task_with_tags(client): "project": project.id, "tags": [ ["back", "#fff8e7"], - ["front", None], - ["ux", "#fabada"] + ["front", "#bbbbbb"], + ["ux", None] ] } @@ -145,16 +145,17 @@ def test_api_create_new_task_with_tags(client): response = client.json.post(url, json.dumps(data)) assert response.status_code == 201, response.data - assert ("back" in response.data["tags"] and - "front" in response.data["tags"] and - "ux" in response.data["tags"]) + task_tags_colors = OrderedDict(response.data["tags"]) + + assert task_tags_colors["back"] == "#fff8e7" + assert task_tags_colors["front"] == "#aaaaaa" + assert task_tags_colors["ux"] == "#fabada" tags_colors = OrderedDict(project.tags_colors) - assert not tags_colors.keys() project.refresh_from_db() tags_colors = OrderedDict(project.tags_colors) - assert "back" in tags_colors and "front" in tags_colors and "ux" in tags_colors assert tags_colors["back"] == "#fff8e7" assert tags_colors["ux"] == "#fabada" + assert tags_colors["front"] == "#aaaaaa" diff --git a/tests/integration/test_userstories_tags.py b/tests/integration/test_userstories_tags.py index c2244f19..d89c172f 100644 --- a/tests/integration/test_userstories_tags.py +++ b/tests/integration/test_userstories_tags.py @@ -123,7 +123,7 @@ def test_api_user_story_add_new_tags_with_colors(client): def test_api_create_new_user_story_with_tags(client): - project = f.ProjectFactory.create() + project = f.ProjectFactory.create(tags_colors=[["front", "#aaaaaa"], ["ux", "#fabada"]]) status = f.UserStoryStatusFactory.create(project=project) project.default_userstory_status = status project.save() @@ -135,8 +135,8 @@ def test_api_create_new_user_story_with_tags(client): "project": project.id, "tags": [ ["back", "#fff8e7"], - ["front", None], - ["ux", "#fabada"] + ["front", "#bbbbbb"], + ["ux", None] ] } @@ -145,16 +145,17 @@ def test_api_create_new_user_story_with_tags(client): response = client.json.post(url, json.dumps(data)) assert response.status_code == 201, response.data - assert ("back" in response.data["tags"] and - "front" in response.data["tags"] and - "ux" in response.data["tags"]) + us_tags_colors = OrderedDict(response.data["tags"]) + + assert us_tags_colors["back"] == "#fff8e7" + assert us_tags_colors["front"] == "#aaaaaa" + assert us_tags_colors["ux"] == "#fabada" tags_colors = OrderedDict(project.tags_colors) - assert not tags_colors.keys() project.refresh_from_db() tags_colors = OrderedDict(project.tags_colors) - assert "back" in tags_colors and "front" in tags_colors and "ux" in tags_colors assert tags_colors["back"] == "#fff8e7" assert tags_colors["ux"] == "#fabada" + assert tags_colors["front"] == "#aaaaaa"