From 9d3e53f3c5384b499feee6eca131f984912c125a Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Thu, 13 Oct 2016 10:48:05 +0200 Subject: [PATCH] Fixing and refactoring by_ref api endpoints --- taiga/projects/epics/api.py | 23 +++------------ taiga/projects/issues/api.py | 18 ++---------- taiga/projects/mixins/by_ref.py | 48 +++++++++++++++++++++++++++++++ taiga/projects/tasks/api.py | 21 ++------------ taiga/projects/userstories/api.py | 24 ++-------------- taiga/projects/votes/services.py | 33 ++++++++++----------- 6 files changed, 76 insertions(+), 91 deletions(-) create mode 100644 taiga/projects/mixins/by_ref.py diff --git a/taiga/projects/epics/api.py b/taiga/projects/epics/api.py index fed57abd..84b13dad 100644 --- a/taiga/projects/epics/api.py +++ b/taiga/projects/epics/api.py @@ -29,6 +29,7 @@ from taiga.base.api.viewsets import NestedViewSetMixin from taiga.base.utils import json from taiga.projects.history.mixins import HistoryResourceMixin +from taiga.projects.mixins.by_ref import ByRefMixin from taiga.projects.models import Project, EpicStatus from taiga.projects.notifications.mixins import WatchedResourceMixin, WatchersViewSetMixin from taiga.projects.occ import OCCResourceMixin @@ -43,9 +44,8 @@ from . import validators from . import utils as epics_utils -class EpicViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixin, - WatchedResourceMixin, TaggedResourceMixin, BlockedByProjectMixin, - ModelCrudViewSet): +class EpicViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixin, WatchedResourceMixin, + ByRefMixin, TaggedResourceMixin, BlockedByProjectMixin, ModelCrudViewSet): validator_class = validators.EpicValidator queryset = models.Epic.objects.all() permission_classes = (permissions.EpicPermission,) @@ -172,21 +172,6 @@ class EpicViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixin, } return response.Ok(services.get_epics_filters_data(project, querysets)) - @list_route(methods=["GET"]) - def by_ref(self, request): - retrieve_kwargs = { - "ref": request.QUERY_PARAMS.get("ref", None) - } - project_id = request.QUERY_PARAMS.get("project", None) - if project_id is not None: - retrieve_kwargs["project_id"] = project_id - - project_slug = request.QUERY_PARAMS.get("project__slug", None) - if project_slug is not None: - retrieve_kwargs["project__slug"] = project_slug - - return self.retrieve(request, **retrieve_kwargs) - @list_route(methods=["GET"]) def csv(self, request): uuid = request.QUERY_PARAMS.get("uuid", None) @@ -222,7 +207,7 @@ class EpicViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixin, epics = self.get_queryset().filter(id__in=[i.id for i in epics]) for epic in epics: self.persist_history_snapshot(obj=epic) - + epics_serialized = self.get_serializer_class()(epics, many=True) return response.Ok(epics_serialized.data) diff --git a/taiga/projects/issues/api.py b/taiga/projects/issues/api.py index 617b13ec..a7479d64 100644 --- a/taiga/projects/issues/api.py +++ b/taiga/projects/issues/api.py @@ -28,6 +28,7 @@ from taiga.base.api.mixins import BlockedByProjectMixin from taiga.base.api.utils import get_object_or_404 from taiga.projects.history.mixins import HistoryResourceMixin +from taiga.projects.mixins.by_ref import ByRefMixin from taiga.projects.models import Project, IssueStatus, Severity, Priority, IssueType from taiga.projects.notifications.mixins import WatchedResourceMixin, WatchersViewSetMixin from taiga.projects.occ import OCCResourceMixin @@ -44,7 +45,7 @@ from . import validators class IssueViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixin, WatchedResourceMixin, - TaggedResourceMixin, BlockedByProjectMixin, ModelCrudViewSet): + ByRefMixin, TaggedResourceMixin, BlockedByProjectMixin, ModelCrudViewSet): validator_class = validators.IssueValidator queryset = models.Issue.objects.all() permission_classes = (permissions.IssuePermission, ) @@ -174,21 +175,6 @@ class IssueViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixin, W super().pre_conditions_on_save(obj) - @list_route(methods=["GET"]) - def by_ref(self, request): - retrieve_kwargs = { - "ref": request.QUERY_PARAMS.get("ref", None) - } - project_id = request.QUERY_PARAMS.get("project", None) - if project_id is not None: - retrieve_kwargs["project_id"] = project_id - - project_slug = request.QUERY_PARAMS.get("project__slug", None) - if project_slug is not None: - retrieve_kwargs["project__slug"] = project_slug - - return self.retrieve(request, **retrieve_kwargs) - @list_route(methods=["GET"]) def filters_data(self, request, *args, **kwargs): project_id = request.QUERY_PARAMS.get("project", None) diff --git a/taiga/projects/mixins/by_ref.py b/taiga/projects/mixins/by_ref.py new file mode 100644 index 00000000..4e1dbad9 --- /dev/null +++ b/taiga/projects/mixins/by_ref.py @@ -0,0 +1,48 @@ +# -*- 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 as _ + +from taiga.base import response +from taiga.base.decorators import list_route + + +class ByRefMixin: + """ + Get an instance by ref. + """ + @list_route(methods=["GET"]) + def by_ref(self, request): + if "ref" not in request.QUERY_PARAMS: + return response.BadRequest(_("ref param is needed")) + + if "project__slug" not in request.QUERY_PARAMS and "project" not in request.QUERY_PARAMS: + return response.BadRequest(_("project or project__slug param is needed")) + + retrieve_kwargs = { + "ref": request.QUERY_PARAMS.get("ref", None) + } + project_id = request.QUERY_PARAMS.get("project", None) + if project_id is not None: + retrieve_kwargs["project_id"] = project_id + + project_slug = request.QUERY_PARAMS.get("project__slug", None) + if project_slug is not None: + retrieve_kwargs["project__slug"] = project_slug + + return self.retrieve(request, **retrieve_kwargs) diff --git a/taiga/projects/tasks/api.py b/taiga/projects/tasks/api.py index 778e080d..2a10620d 100644 --- a/taiga/projects/tasks/api.py +++ b/taiga/projects/tasks/api.py @@ -28,6 +28,7 @@ from taiga.base.api.mixins import BlockedByProjectMixin from taiga.base.utils import json from taiga.projects.history.mixins import HistoryResourceMixin from taiga.projects.milestones.models import Milestone +from taiga.projects.mixins.by_ref import ByRefMixin from taiga.projects.models import Project, TaskStatus from taiga.projects.notifications.mixins import WatchedResourceMixin, WatchersViewSetMixin from taiga.projects.occ import OCCResourceMixin @@ -44,9 +45,8 @@ from . import validators from . import utils as tasks_utils -class TaskViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixin, - WatchedResourceMixin, TaggedResourceMixin, BlockedByProjectMixin, - ModelCrudViewSet): +class TaskViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixin, WatchedResourceMixin, + ByRefMixin, TaggedResourceMixin, BlockedByProjectMixin, ModelCrudViewSet): validator_class = validators.TaskValidator queryset = models.Task.objects.all() permission_classes = (permissions.TaskPermission,) @@ -220,21 +220,6 @@ class TaskViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixin, } return response.Ok(services.get_tasks_filters_data(project, querysets)) - @list_route(methods=["GET"]) - def by_ref(self, request): - retrieve_kwargs = { - "ref": request.QUERY_PARAMS.get("ref", None) - } - project_id = request.QUERY_PARAMS.get("project", None) - if project_id is not None: - retrieve_kwargs["project_id"] = project_id - - project_slug = request.QUERY_PARAMS.get("project__slug", None) - if project_slug is not None: - retrieve_kwargs["project__slug"] = project_slug - - return self.retrieve(request, **retrieve_kwargs) - @list_route(methods=["GET"]) def csv(self, request): uuid = request.QUERY_PARAMS.get("uuid", None) diff --git a/taiga/projects/userstories/api.py b/taiga/projects/userstories/api.py index 6ee1d72c..bb888f88 100644 --- a/taiga/projects/userstories/api.py +++ b/taiga/projects/userstories/api.py @@ -36,6 +36,7 @@ from taiga.base.utils import json from taiga.projects.history.mixins import HistoryResourceMixin from taiga.projects.history.services import take_snapshot from taiga.projects.milestones.models import Milestone +from taiga.projects.mixins.by_ref import ByRefMixin from taiga.projects.models import Project, UserStoryStatus from taiga.projects.notifications.mixins import WatchedResourceMixin from taiga.projects.notifications.mixins import WatchersViewSetMixin @@ -54,7 +55,7 @@ from . import validators class UserStoryViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixin, WatchedResourceMixin, - TaggedResourceMixin, BlockedByProjectMixin, ModelCrudViewSet): + ByRefMixin, TaggedResourceMixin, BlockedByProjectMixin, ModelCrudViewSet): validator_class = validators.UserStoryValidator queryset = models.UserStory.objects.all() permission_classes = (permissions.UserStoryPermission,) @@ -295,27 +296,6 @@ class UserStoryViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixi } return response.Ok(services.get_userstories_filters_data(project, querysets)) - @list_route(methods=["GET"]) - def by_ref(self, request): - if "ref" not in request.QUERY_PARAMS: - return response.BadRequest(_("ref param is needed")) - - if "project_slug" not in request.QUERY_PARAMS and "project" not in request.QUERY_PARAMS: - return response.BadRequest(_("project or project_slug param is needed")) - - retrieve_kwargs = { - "ref": request.QUERY_PARAMS["ref"] - } - project_id = request.QUERY_PARAMS.get("project", None) - if project_id is not None: - retrieve_kwargs["project_id"] = project_id - - project_slug = request.QUERY_PARAMS.get("project__slug", None) - if project_slug is not None: - retrieve_kwargs["project__slug"] = project_slug - - return self.retrieve(request, **retrieve_kwargs) - @list_route(methods=["GET"]) def csv(self, request): uuid = request.QUERY_PARAMS.get("uuid", None) diff --git a/taiga/projects/votes/services.py b/taiga/projects/votes/services.py index 38c3b93a..6d80c20d 100644 --- a/taiga/projects/votes/services.py +++ b/taiga/projects/votes/services.py @@ -18,13 +18,15 @@ # along with this program. If not, see . from django.db.models import F -from django.db.transaction import atomic +from django.db import transaction as tx + from django.apps import apps from django.contrib.auth import get_user_model from .models import Votes, Vote +@tx.atomic def add_vote(obj, user): """Add a vote to an object. @@ -35,17 +37,17 @@ def add_vote(obj, user): :param user: User adding the vote. :class:`~taiga.users.models.User` instance. """ obj_type = apps.get_model("contenttypes", "ContentType").objects.get_for_model(obj) - with atomic(): - vote, created = Vote.objects.get_or_create(content_type=obj_type, object_id=obj.id, user=user) - if not created: - return + vote, created = Vote.objects.get_or_create(content_type=obj_type, object_id=obj.id, user=user) + if not created: + return - votes, _ = Votes.objects.get_or_create(content_type=obj_type, object_id=obj.id) - votes.count = F('count') + 1 - votes.save() + votes, _ = Votes.objects.get_or_create(content_type=obj_type, object_id=obj.id) + votes.count = F('count') + 1 + votes.save() return vote +@tx.atomic def remove_vote(obj, user): """Remove an user vote from an object. @@ -56,16 +58,15 @@ def remove_vote(obj, user): :param user: User removing her vote. :class:`~taiga.users.models.User` instance. """ obj_type = apps.get_model("contenttypes", "ContentType").objects.get_for_model(obj) - with atomic(): - qs = Vote.objects.filter(content_type=obj_type, object_id=obj.id, user=user) - if not qs.exists(): - return + qs = Vote.objects.filter(content_type=obj_type, object_id=obj.id, user=user) + if not qs.exists(): + return - qs.delete() + qs.delete() - votes, _ = Votes.objects.get_or_create(content_type=obj_type, object_id=obj.id) - votes.count = F('count') - 1 - votes.save() + votes, _ = Votes.objects.get_or_create(content_type=obj_type, object_id=obj.id) + votes.count = F('count') - 1 + votes.save() def get_voters(obj):