Merge pull request #804 from taigaio/Refactoring-tags-and-colors-in-API
Refactoring tags and colors in APIremotes/origin/issue/4795/notification_even_they_are_disabled
commit
f20a9737a1
|
@ -25,12 +25,14 @@ from taiga.projects.mixins.serializers import OwnerExtraInfoSerializerMixin
|
||||||
from taiga.projects.mixins.serializers import AssignedToExtraInfoSerializerMixin
|
from taiga.projects.mixins.serializers import AssignedToExtraInfoSerializerMixin
|
||||||
from taiga.projects.mixins.serializers import StatusExtraInfoSerializerMixin
|
from taiga.projects.mixins.serializers import StatusExtraInfoSerializerMixin
|
||||||
from taiga.projects.notifications.mixins import WatchedResourceSerializer
|
from taiga.projects.notifications.mixins import WatchedResourceSerializer
|
||||||
|
from taiga.projects.tagging.serializers import TaggedInProjectResourceSerializer
|
||||||
from taiga.projects.votes.mixins.serializers import VoteResourceSerializerMixin
|
from taiga.projects.votes.mixins.serializers import VoteResourceSerializerMixin
|
||||||
|
|
||||||
|
|
||||||
class IssueListSerializer(VoteResourceSerializerMixin, WatchedResourceSerializer,
|
class IssueListSerializer(VoteResourceSerializerMixin, WatchedResourceSerializer,
|
||||||
OwnerExtraInfoSerializerMixin, AssignedToExtraInfoSerializerMixin,
|
OwnerExtraInfoSerializerMixin, AssignedToExtraInfoSerializerMixin,
|
||||||
StatusExtraInfoSerializerMixin, serializers.LightSerializer):
|
StatusExtraInfoSerializerMixin,
|
||||||
|
TaggedInProjectResourceSerializer, serializers.LightSerializer):
|
||||||
id = Field()
|
id = Field()
|
||||||
ref = Field()
|
ref = Field()
|
||||||
severity = Field(attr="severity_id")
|
severity = Field(attr="severity_id")
|
||||||
|
@ -45,7 +47,6 @@ class IssueListSerializer(VoteResourceSerializerMixin, WatchedResourceSerializer
|
||||||
external_reference = Field()
|
external_reference = Field()
|
||||||
version = Field()
|
version = Field()
|
||||||
watchers = Field()
|
watchers = Field()
|
||||||
tags = Field()
|
|
||||||
is_closed = Field()
|
is_closed = Field()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2014-2016 Andrey Antukh <niwi@niwi.nz>
|
||||||
|
# Copyright (C) 2014-2016 Jesús Espino <jespinog@gmail.com>
|
||||||
|
# Copyright (C) 2014-2016 David Barragán <bameda@dbarragan.com>
|
||||||
|
# Copyright (C) 2014-2016 Alejandro Alonso <alejandro.alonso@kaleidos.net>
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
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]
|
|
@ -20,6 +20,7 @@ from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
from taiga.base.api import serializers
|
from taiga.base.api import serializers
|
||||||
from taiga.base.api import validators
|
from taiga.base.api import validators
|
||||||
|
from taiga.base.exceptions import ValidationError
|
||||||
|
|
||||||
from . import services
|
from . import services
|
||||||
from . import fields
|
from . import fields
|
||||||
|
@ -43,14 +44,14 @@ class CreateTagValidator(ProjectTagValidator):
|
||||||
def validate_tag(self, attrs, source):
|
def validate_tag(self, attrs, source):
|
||||||
tag = attrs.get(source, None)
|
tag = attrs.get(source, None)
|
||||||
if services.tag_exist_for_project_elements(self.project, tag):
|
if services.tag_exist_for_project_elements(self.project, tag):
|
||||||
raise validators.ValidationError(_("The tag exists."))
|
raise ValidationError(_("The tag exists."))
|
||||||
|
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
def validate_color(self, attrs, source):
|
def validate_color(self, attrs, source):
|
||||||
color = attrs.get(source, None)
|
color = attrs.get(source, None)
|
||||||
if not re.match('^\#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$', color):
|
if color is not None and 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
|
return attrs
|
||||||
|
|
||||||
|
@ -63,21 +64,21 @@ class EditTagTagValidator(ProjectTagValidator):
|
||||||
def validate_from_tag(self, attrs, source):
|
def validate_from_tag(self, attrs, source):
|
||||||
tag = attrs.get(source, None)
|
tag = attrs.get(source, None)
|
||||||
if not services.tag_exist_for_project_elements(self.project, tag):
|
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
|
return attrs
|
||||||
|
|
||||||
def validate_to_tag(self, attrs, source):
|
def validate_to_tag(self, attrs, source):
|
||||||
tag = attrs.get(source, None)
|
tag = attrs.get(source, None)
|
||||||
if services.tag_exist_for_project_elements(self.project, tag):
|
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
|
return attrs
|
||||||
|
|
||||||
def validate_color(self, attrs, source):
|
def validate_color(self, attrs, source):
|
||||||
color = attrs.get(source, None)
|
color = attrs.get(source, None)
|
||||||
if not re.match('^\#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$', color):
|
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
|
return attrs
|
||||||
|
|
||||||
|
@ -88,7 +89,7 @@ class DeleteTagValidator(ProjectTagValidator):
|
||||||
def validate_tag(self, attrs, source):
|
def validate_tag(self, attrs, source):
|
||||||
tag = attrs.get(source, None)
|
tag = attrs.get(source, None)
|
||||||
if not services.tag_exist_for_project_elements(self.project, tag):
|
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
|
return attrs
|
||||||
|
|
||||||
|
@ -101,13 +102,13 @@ class MixTagsValidator(ProjectTagValidator):
|
||||||
tags = attrs.get(source, None)
|
tags = attrs.get(source, None)
|
||||||
for tag in tags:
|
for tag in tags:
|
||||||
if not services.tag_exist_for_project_elements(self.project, tag):
|
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
|
return attrs
|
||||||
|
|
||||||
def validate_to_tag(self, attrs, source):
|
def validate_to_tag(self, attrs, source):
|
||||||
tag = attrs.get(source, None)
|
tag = attrs.get(source, None)
|
||||||
if not services.tag_exist_for_project_elements(self.project, tag):
|
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
|
return attrs
|
||||||
|
|
|
@ -26,13 +26,14 @@ from taiga.projects.mixins.serializers import OwnerExtraInfoSerializerMixin
|
||||||
from taiga.projects.mixins.serializers import AssignedToExtraInfoSerializerMixin
|
from taiga.projects.mixins.serializers import AssignedToExtraInfoSerializerMixin
|
||||||
from taiga.projects.mixins.serializers import StatusExtraInfoSerializerMixin
|
from taiga.projects.mixins.serializers import StatusExtraInfoSerializerMixin
|
||||||
from taiga.projects.notifications.mixins import WatchedResourceSerializer
|
from taiga.projects.notifications.mixins import WatchedResourceSerializer
|
||||||
|
from taiga.projects.tagging.serializers import TaggedInProjectResourceSerializer
|
||||||
from taiga.projects.votes.mixins.serializers import VoteResourceSerializerMixin
|
from taiga.projects.votes.mixins.serializers import VoteResourceSerializerMixin
|
||||||
|
|
||||||
|
|
||||||
class TaskListSerializer(VoteResourceSerializerMixin, WatchedResourceSerializer,
|
class TaskListSerializer(VoteResourceSerializerMixin, WatchedResourceSerializer,
|
||||||
OwnerExtraInfoSerializerMixin, AssignedToExtraInfoSerializerMixin,
|
OwnerExtraInfoSerializerMixin, AssignedToExtraInfoSerializerMixin,
|
||||||
StatusExtraInfoSerializerMixin, BasicAttachmentsInfoSerializerMixin,
|
StatusExtraInfoSerializerMixin, BasicAttachmentsInfoSerializerMixin,
|
||||||
serializers.LightSerializer):
|
TaggedInProjectResourceSerializer, serializers.LightSerializer):
|
||||||
|
|
||||||
id = Field()
|
id = Field()
|
||||||
user_story = Field(attr="user_story_id")
|
user_story = Field(attr="user_story_id")
|
||||||
|
@ -52,7 +53,6 @@ class TaskListSerializer(VoteResourceSerializerMixin, WatchedResourceSerializer,
|
||||||
watchers = Field()
|
watchers = Field()
|
||||||
is_blocked = Field()
|
is_blocked = Field()
|
||||||
blocked_note = Field()
|
blocked_note = Field()
|
||||||
tags = Field()
|
|
||||||
is_closed = MethodField()
|
is_closed = MethodField()
|
||||||
|
|
||||||
def get_milestone_slug(self, obj):
|
def get_milestone_slug(self, obj):
|
||||||
|
|
|
@ -22,6 +22,7 @@ from taiga.base.neighbors import NeighborsSerializerMixin
|
||||||
|
|
||||||
from taiga.mdrender.service import render as mdrender
|
from taiga.mdrender.service import render as mdrender
|
||||||
from taiga.projects.attachments.serializers import BasicAttachmentsInfoSerializerMixin
|
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 OwnerExtraInfoSerializerMixin
|
||||||
from taiga.projects.mixins.serializers import AssignedToExtraInfoSerializerMixin
|
from taiga.projects.mixins.serializers import AssignedToExtraInfoSerializerMixin
|
||||||
from taiga.projects.mixins.serializers import StatusExtraInfoSerializerMixin
|
from taiga.projects.mixins.serializers import StatusExtraInfoSerializerMixin
|
||||||
|
@ -45,6 +46,7 @@ class UserStoryListSerializer(
|
||||||
VoteResourceSerializerMixin, WatchedResourceSerializer,
|
VoteResourceSerializerMixin, WatchedResourceSerializer,
|
||||||
OwnerExtraInfoSerializerMixin, AssignedToExtraInfoSerializerMixin,
|
OwnerExtraInfoSerializerMixin, AssignedToExtraInfoSerializerMixin,
|
||||||
StatusExtraInfoSerializerMixin, BasicAttachmentsInfoSerializerMixin,
|
StatusExtraInfoSerializerMixin, BasicAttachmentsInfoSerializerMixin,
|
||||||
|
TaggedInProjectResourceSerializer,
|
||||||
serializers.LightSerializer):
|
serializers.LightSerializer):
|
||||||
|
|
||||||
id = Field()
|
id = Field()
|
||||||
|
@ -71,7 +73,6 @@ class UserStoryListSerializer(
|
||||||
watchers = Field()
|
watchers = Field()
|
||||||
is_blocked = Field()
|
is_blocked = Field()
|
||||||
blocked_note = Field()
|
blocked_note = Field()
|
||||||
tags = Field()
|
|
||||||
total_points = MethodField()
|
total_points = MethodField()
|
||||||
comment = MethodField()
|
comment = MethodField()
|
||||||
origin_issue = OriginIssueSerializer(attr="generated_from_issue")
|
origin_issue = OriginIssueSerializer(attr="generated_from_issue")
|
||||||
|
|
|
@ -123,7 +123,7 @@ def test_api_issue_add_new_tags_with_colors(client):
|
||||||
|
|
||||||
|
|
||||||
def test_api_create_new_issue_with_tags(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)
|
status = f.IssueStatusFactory.create(project=project)
|
||||||
project.default_issue_status = status
|
project.default_issue_status = status
|
||||||
project.save()
|
project.save()
|
||||||
|
@ -145,16 +145,17 @@ def test_api_create_new_issue_with_tags(client):
|
||||||
response = client.json.post(url, json.dumps(data))
|
response = client.json.post(url, json.dumps(data))
|
||||||
assert response.status_code == 201, response.data
|
assert response.status_code == 201, response.data
|
||||||
|
|
||||||
assert ("back" in response.data["tags"] and
|
issue_tags_colors = OrderedDict(response.data["tags"])
|
||||||
"front" in response.data["tags"] and
|
|
||||||
"ux" in 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)
|
tags_colors = OrderedDict(project.tags_colors)
|
||||||
assert not tags_colors.keys()
|
|
||||||
|
|
||||||
project.refresh_from_db()
|
project.refresh_from_db()
|
||||||
|
|
||||||
tags_colors = OrderedDict(project.tags_colors)
|
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["back"] == "#fff8e7"
|
||||||
assert tags_colors["ux"] == "#fabada"
|
assert tags_colors["ux"] == "#fabada"
|
||||||
|
assert tags_colors["front"] == "#aaaaaa"
|
||||||
|
|
|
@ -123,7 +123,7 @@ def test_api_task_add_new_tags_with_colors(client):
|
||||||
|
|
||||||
|
|
||||||
def test_api_create_new_task_with_tags(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)
|
status = f.TaskStatusFactory.create(project=project)
|
||||||
project.default_task_status = status
|
project.default_task_status = status
|
||||||
project.save()
|
project.save()
|
||||||
|
@ -135,8 +135,8 @@ def test_api_create_new_task_with_tags(client):
|
||||||
"project": project.id,
|
"project": project.id,
|
||||||
"tags": [
|
"tags": [
|
||||||
["back", "#fff8e7"],
|
["back", "#fff8e7"],
|
||||||
["front", None],
|
["front", "#bbbbbb"],
|
||||||
["ux", "#fabada"]
|
["ux", None]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,16 +145,17 @@ def test_api_create_new_task_with_tags(client):
|
||||||
response = client.json.post(url, json.dumps(data))
|
response = client.json.post(url, json.dumps(data))
|
||||||
assert response.status_code == 201, response.data
|
assert response.status_code == 201, response.data
|
||||||
|
|
||||||
assert ("back" in response.data["tags"] and
|
task_tags_colors = OrderedDict(response.data["tags"])
|
||||||
"front" in response.data["tags"] and
|
|
||||||
"ux" in 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)
|
tags_colors = OrderedDict(project.tags_colors)
|
||||||
assert not tags_colors.keys()
|
|
||||||
|
|
||||||
project.refresh_from_db()
|
project.refresh_from_db()
|
||||||
|
|
||||||
tags_colors = OrderedDict(project.tags_colors)
|
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["back"] == "#fff8e7"
|
||||||
assert tags_colors["ux"] == "#fabada"
|
assert tags_colors["ux"] == "#fabada"
|
||||||
|
assert tags_colors["front"] == "#aaaaaa"
|
||||||
|
|
|
@ -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):
|
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)
|
status = f.UserStoryStatusFactory.create(project=project)
|
||||||
project.default_userstory_status = status
|
project.default_userstory_status = status
|
||||||
project.save()
|
project.save()
|
||||||
|
@ -135,8 +135,8 @@ def test_api_create_new_user_story_with_tags(client):
|
||||||
"project": project.id,
|
"project": project.id,
|
||||||
"tags": [
|
"tags": [
|
||||||
["back", "#fff8e7"],
|
["back", "#fff8e7"],
|
||||||
["front", None],
|
["front", "#bbbbbb"],
|
||||||
["ux", "#fabada"]
|
["ux", None]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,16 +145,17 @@ def test_api_create_new_user_story_with_tags(client):
|
||||||
response = client.json.post(url, json.dumps(data))
|
response = client.json.post(url, json.dumps(data))
|
||||||
assert response.status_code == 201, response.data
|
assert response.status_code == 201, response.data
|
||||||
|
|
||||||
assert ("back" in response.data["tags"] and
|
us_tags_colors = OrderedDict(response.data["tags"])
|
||||||
"front" in response.data["tags"] and
|
|
||||||
"ux" in 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)
|
tags_colors = OrderedDict(project.tags_colors)
|
||||||
assert not tags_colors.keys()
|
|
||||||
|
|
||||||
project.refresh_from_db()
|
project.refresh_from_db()
|
||||||
|
|
||||||
tags_colors = OrderedDict(project.tags_colors)
|
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["back"] == "#fff8e7"
|
||||||
assert tags_colors["ux"] == "#fabada"
|
assert tags_colors["ux"] == "#fabada"
|
||||||
|
assert tags_colors["front"] == "#aaaaaa"
|
||||||
|
|
Loading…
Reference in New Issue