From 6e3eeb7cca20eac0a931b6e384c82230e6f0a772 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Wed, 6 Jul 2016 09:55:24 +0200 Subject: [PATCH] Migrating custom fields serializer --- taiga/projects/custom_attributes/api.py | 7 + .../projects/custom_attributes/serializers.py | 122 +++------------ .../projects/custom_attributes/validators.py | 146 ++++++++++++++++++ 3 files changed, 174 insertions(+), 101 deletions(-) create mode 100644 taiga/projects/custom_attributes/validators.py diff --git a/taiga/projects/custom_attributes/api.py b/taiga/projects/custom_attributes/api.py index 9bfc774f..2d05d186 100644 --- a/taiga/projects/custom_attributes/api.py +++ b/taiga/projects/custom_attributes/api.py @@ -32,6 +32,7 @@ from taiga.projects.occ.mixins import OCCResourceMixin from . import models from . import serializers +from . import validators from . import permissions from . import services @@ -43,6 +44,7 @@ from . import services class UserStoryCustomAttributeViewSet(BulkUpdateOrderMixin, BlockedByProjectMixin, ModelCrudViewSet): model = models.UserStoryCustomAttribute serializer_class = serializers.UserStoryCustomAttributeSerializer + validator_class = validators.UserStoryCustomAttributeValidator permission_classes = (permissions.UserStoryCustomAttributePermission,) filter_backends = (filters.CanViewProjectFilterBackend,) filter_fields = ("project",) @@ -54,6 +56,7 @@ class UserStoryCustomAttributeViewSet(BulkUpdateOrderMixin, BlockedByProjectMixi class TaskCustomAttributeViewSet(BulkUpdateOrderMixin, BlockedByProjectMixin, ModelCrudViewSet): model = models.TaskCustomAttribute serializer_class = serializers.TaskCustomAttributeSerializer + validator_class = validators.TaskCustomAttributeValidator permission_classes = (permissions.TaskCustomAttributePermission,) filter_backends = (filters.CanViewProjectFilterBackend,) filter_fields = ("project",) @@ -65,6 +68,7 @@ class TaskCustomAttributeViewSet(BulkUpdateOrderMixin, BlockedByProjectMixin, Mo class IssueCustomAttributeViewSet(BulkUpdateOrderMixin, BlockedByProjectMixin, ModelCrudViewSet): model = models.IssueCustomAttribute serializer_class = serializers.IssueCustomAttributeSerializer + validator_class = validators.IssueCustomAttributeValidator permission_classes = (permissions.IssueCustomAttributePermission,) filter_backends = (filters.CanViewProjectFilterBackend,) filter_fields = ("project",) @@ -86,6 +90,7 @@ class BaseCustomAttributesValuesViewSet(OCCResourceMixin, HistoryResourceMixin, class UserStoryCustomAttributesValuesViewSet(BaseCustomAttributesValuesViewSet): model = models.UserStoryCustomAttributesValues serializer_class = serializers.UserStoryCustomAttributesValuesSerializer + validator_class = validators.UserStoryCustomAttributesValuesValidator permission_classes = (permissions.UserStoryCustomAttributesValuesPermission,) lookup_field = "user_story_id" content_object = "user_story" @@ -99,6 +104,7 @@ class UserStoryCustomAttributesValuesViewSet(BaseCustomAttributesValuesViewSet): class TaskCustomAttributesValuesViewSet(BaseCustomAttributesValuesViewSet): model = models.TaskCustomAttributesValues serializer_class = serializers.TaskCustomAttributesValuesSerializer + validator_class = validators.TaskCustomAttributesValuesValidator permission_classes = (permissions.TaskCustomAttributesValuesPermission,) lookup_field = "task_id" content_object = "task" @@ -112,6 +118,7 @@ class TaskCustomAttributesValuesViewSet(BaseCustomAttributesValuesViewSet): class IssueCustomAttributesValuesViewSet(BaseCustomAttributesValuesViewSet): model = models.IssueCustomAttributesValues serializer_class = serializers.IssueCustomAttributesValuesSerializer + validator_class = validators.IssueCustomAttributesValuesValidator permission_classes = (permissions.IssueCustomAttributesValuesPermission,) lookup_field = "issue_id" content_object = "issue" diff --git a/taiga/projects/custom_attributes/serializers.py b/taiga/projects/custom_attributes/serializers.py index 64a934f5..d4fc084e 100644 --- a/taiga/projects/custom_attributes/serializers.py +++ b/taiga/projects/custom_attributes/serializers.py @@ -17,131 +17,51 @@ # along with this program. If not, see . -from django.apps import apps -from django.utils.translation import ugettext_lazy as _ - -from taiga.base.fields import JsonField -from taiga.base.api.serializers import ValidationError -from taiga.base.api.serializers import ModelSerializer - -from . import models +from taiga.base.fields import JsonField, Field +from taiga.base.api import serializers ###################################################### # Custom Attribute Serializer ####################################################### -class BaseCustomAttributeSerializer(ModelSerializer): - class Meta: - read_only_fields = ('id',) - exclude = ('created_date', 'modified_date') - - def _validate_integrity_between_project_and_name(self, attrs, source): - """ - Check the name is not duplicated in the project. Check when: - - create a new one - - update the name - - update the project (move to another project) - """ - data_id = attrs.get("id", None) - data_name = attrs.get("name", None) - data_project = attrs.get("project", None) - - if self.object: - data_id = data_id or self.object.id - data_name = data_name or self.object.name - data_project = data_project or self.object.project - - model = self.Meta.model - qs = (model.objects.filter(project=data_project, name=data_name) - .exclude(id=data_id)) - if qs.exists(): - raise ValidationError(_("Already exists one with the same name.")) - - return attrs - - def validate_name(self, attrs, source): - return self._validate_integrity_between_project_and_name(attrs, source) - - def validate_project(self, attrs, source): - return self._validate_integrity_between_project_and_name(attrs, source) +class BaseCustomAttributeSerializer(serializers.LightSerializer): + name = Field() + description = Field() + type = Field() + order = Field() + project = Field(attr="project_id") + created_date = Field() + modified_date = Field() class UserStoryCustomAttributeSerializer(BaseCustomAttributeSerializer): - class Meta(BaseCustomAttributeSerializer.Meta): - model = models.UserStoryCustomAttribute + pass class TaskCustomAttributeSerializer(BaseCustomAttributeSerializer): - class Meta(BaseCustomAttributeSerializer.Meta): - model = models.TaskCustomAttribute + pass class IssueCustomAttributeSerializer(BaseCustomAttributeSerializer): - class Meta(BaseCustomAttributeSerializer.Meta): - model = models.IssueCustomAttribute + pass ###################################################### # Custom Attribute Serializer ####################################################### - - -class BaseCustomAttributesValuesSerializer(ModelSerializer): - attributes_values = JsonField(source="attributes_values", label="attributes values") - _custom_attribute_model = None - _container_field = None - - class Meta: - exclude = ("id",) - - def validate_attributes_values(self, attrs, source): - # values must be a dict - data_values = attrs.get("attributes_values", None) - if self.object: - data_values = (data_values or self.object.attributes_values) - - if type(data_values) is not dict: - raise ValidationError(_("Invalid content. It must be {\"key\": \"value\",...}")) - - # Values keys must be in the container object project - data_container = attrs.get(self._container_field, None) - if data_container: - project_id = data_container.project_id - elif self.object: - project_id = getattr(self.object, self._container_field).project_id - else: - project_id = None - - values_ids = list(data_values.keys()) - qs = self._custom_attribute_model.objects.filter(project=project_id, - id__in=values_ids) - if qs.count() != len(values_ids): - raise ValidationError(_("It contain invalid custom fields.")) - - return attrs +class BaseCustomAttributesValuesSerializer(serializers.LightSerializer): + attributes_values = Field() + version = Field() class UserStoryCustomAttributesValuesSerializer(BaseCustomAttributesValuesSerializer): - _custom_attribute_model = models.UserStoryCustomAttribute - _container_model = "userstories.UserStory" - _container_field = "user_story" - - class Meta(BaseCustomAttributesValuesSerializer.Meta): - model = models.UserStoryCustomAttributesValues + user_story = Field(attr="user_story.id") -class TaskCustomAttributesValuesSerializer(BaseCustomAttributesValuesSerializer, ModelSerializer): - _custom_attribute_model = models.TaskCustomAttribute - _container_field = "task" - - class Meta(BaseCustomAttributesValuesSerializer.Meta): - model = models.TaskCustomAttributesValues +class TaskCustomAttributesValuesSerializer(BaseCustomAttributesValuesSerializer): + task = Field(attr="task.id") -class IssueCustomAttributesValuesSerializer(BaseCustomAttributesValuesSerializer, ModelSerializer): - _custom_attribute_model = models.IssueCustomAttribute - _container_field = "issue" - - class Meta(BaseCustomAttributesValuesSerializer.Meta): - model = models.IssueCustomAttributesValues +class IssueCustomAttributesValuesSerializer(BaseCustomAttributesValuesSerializer): + issue = Field(attr="issue.id") diff --git a/taiga/projects/custom_attributes/validators.py b/taiga/projects/custom_attributes/validators.py new file mode 100644 index 00000000..506c040c --- /dev/null +++ b/taiga/projects/custom_attributes/validators.py @@ -0,0 +1,146 @@ +# -*- 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 django.utils.translation import ugettext_lazy as _ + +from taiga.base.fields import JsonField +from taiga.base.api.serializers import ValidationError +from taiga.base.api.validators import ModelValidator + +from . import models + + +###################################################### +# Custom Attribute Validator +####################################################### + +class BaseCustomAttributeValidator(ModelValidator): + class Meta: + read_only_fields = ('id',) + exclude = ('created_date', 'modified_date') + + def _validate_integrity_between_project_and_name(self, attrs, source): + """ + Check the name is not duplicated in the project. Check when: + - create a new one + - update the name + - update the project (move to another project) + """ + data_id = attrs.get("id", None) + data_name = attrs.get("name", None) + data_project = attrs.get("project", None) + + if self.object: + data_id = data_id or self.object.id + data_name = data_name or self.object.name + data_project = data_project or self.object.project + + model = self.Meta.model + qs = (model.objects.filter(project=data_project, name=data_name) + .exclude(id=data_id)) + if qs.exists(): + raise ValidationError(_("Already exists one with the same name.")) + + return attrs + + def validate_name(self, attrs, source): + return self._validate_integrity_between_project_and_name(attrs, source) + + def validate_project(self, attrs, source): + return self._validate_integrity_between_project_and_name(attrs, source) + + +class UserStoryCustomAttributeValidator(BaseCustomAttributeValidator): + class Meta(BaseCustomAttributeValidator.Meta): + model = models.UserStoryCustomAttribute + + +class TaskCustomAttributeValidator(BaseCustomAttributeValidator): + class Meta(BaseCustomAttributeValidator.Meta): + model = models.TaskCustomAttribute + + +class IssueCustomAttributeValidator(BaseCustomAttributeValidator): + class Meta(BaseCustomAttributeValidator.Meta): + model = models.IssueCustomAttribute + + +###################################################### +# Custom Attribute Validator +####################################################### + + +class BaseCustomAttributesValuesValidator(ModelValidator): + attributes_values = JsonField(source="attributes_values", label="attributes values") + _custom_attribute_model = None + _container_field = None + + class Meta: + exclude = ("id",) + + def validate_attributes_values(self, attrs, source): + # values must be a dict + data_values = attrs.get("attributes_values", None) + if self.object: + data_values = (data_values or self.object.attributes_values) + + if type(data_values) is not dict: + raise ValidationError(_("Invalid content. It must be {\"key\": \"value\",...}")) + + # Values keys must be in the container object project + data_container = attrs.get(self._container_field, None) + if data_container: + project_id = data_container.project_id + elif self.object: + project_id = getattr(self.object, self._container_field).project_id + else: + project_id = None + + values_ids = list(data_values.keys()) + qs = self._custom_attribute_model.objects.filter(project=project_id, + id__in=values_ids) + if qs.count() != len(values_ids): + raise ValidationError(_("It contain invalid custom fields.")) + + return attrs + + +class UserStoryCustomAttributesValuesValidator(BaseCustomAttributesValuesValidator): + _custom_attribute_model = models.UserStoryCustomAttribute + _container_model = "userstories.UserStory" + _container_field = "user_story" + + class Meta(BaseCustomAttributesValuesValidator.Meta): + model = models.UserStoryCustomAttributesValues + + +class TaskCustomAttributesValuesValidator(BaseCustomAttributesValuesValidator, ModelValidator): + _custom_attribute_model = models.TaskCustomAttribute + _container_field = "task" + + class Meta(BaseCustomAttributesValuesValidator.Meta): + model = models.TaskCustomAttributesValues + + +class IssueCustomAttributesValuesValidator(BaseCustomAttributesValuesValidator, ModelValidator): + _custom_attribute_model = models.IssueCustomAttribute + _container_field = "issue" + + class Meta(BaseCustomAttributesValuesValidator.Meta): + model = models.IssueCustomAttributesValues