diff --git a/greenmine/base/api.py b/greenmine/base/api.py index aebe8cd6..bf0d43d4 100644 --- a/greenmine/base/api.py +++ b/greenmine/base/api.py @@ -1,16 +1,35 @@ # -*- coding: utf-8 -*- from rest_framework import viewsets + from .pagination import HeadersPaginationMixin, ConditionalPaginationMixin -class ModelCrudViewSet(HeadersPaginationMixin, +class PreconditionMixin(object): + def pre_conditions_on_save(self, obj): + pass + + def pre_conditions_on_delete(self, obj): + pass + + def pre_save(self, obj): + super().pre_save(obj) + self.pre_conditions_on_save(obj) + + def pre_delete(self, obj): + super().pre_delete(obj) + self.pre_conditions_on_delete(obj) + + +class ModelCrudViewSet(PreconditionMixin, + HeadersPaginationMixin, ConditionalPaginationMixin, viewsets.ModelViewSet): pass -class ModelListViewSet(HeadersPaginationMixin, +class ModelListViewSet(PreconditionMixin, + HeadersPaginationMixin, ConditionalPaginationMixin, viewsets.ReadOnlyModelViewSet): pass diff --git a/greenmine/base/exceptions.py b/greenmine/base/exceptions.py index f293165e..bd161330 100644 --- a/greenmine/base/exceptions.py +++ b/greenmine/base/exceptions.py @@ -45,6 +45,13 @@ class PermissionDenied(exceptions.PermissionDenied): pass +class PreconditionError(BaseException): + """ + Error raised on precondition method on viewset. + """ + default_detail = "Precondition error" + + class InternalError(BaseException): """ Exception for internal errors. diff --git a/greenmine/projects/api.py b/greenmine/projects/api.py index f334dc1a..3ef50c14 100644 --- a/greenmine/projects/api.py +++ b/greenmine/projects/api.py @@ -25,8 +25,8 @@ class ProjectViewSet(ModelCrudViewSet): return qs.distinct() def pre_save(self, obj): - super(ProjectViewSet, self).pre_save(obj) obj.owner = self.request.user + super(ProjectViewSet, self).pre_save(obj) # User Stories commin ViewSets diff --git a/greenmine/projects/milestones/api.py b/greenmine/projects/milestones/api.py index 1cb8d194..bbb7a2ec 100644 --- a/greenmine/projects/milestones/api.py +++ b/greenmine/projects/milestones/api.py @@ -3,9 +3,9 @@ from django.utils.translation import ugettext_lazy as _ from rest_framework.permissions import IsAuthenticated -from rest_framework.exceptions import ParseError from greenmine.base import filters +from greenmine.base import exceptions as exc from greenmine.base.api import ModelCrudViewSet from greenmine.base.notifications.api import NotificationSenderMixin @@ -24,11 +24,16 @@ class MilestoneViewSet(NotificationSenderMixin, ModelCrudViewSet): update_notification_template = "update_milestone_notification" destroy_notification_template = "destroy_milestone_notification" - def pre_save(self, obj): - super(MilestoneViewSet, self).pre_save(obj) - if not obj.id: - obj.owner = self.request.user + def pre_conditions_on_save(self, obj): + super().pre_conditions_on_save(obj) if (obj.project.owner != self.request.user and obj.project.memberships.filter(user=self.request.user).count() == 0): - raise ParseError(detail=_("You must not add a new milestone to this project.")) + raise exc.PreconditionError("You must not add a new milestone to this project.") + + def pre_save(self, obj): + if not obj.id: + obj.owner = self.request.user + + super().pre_save(obj) + diff --git a/greenmine/projects/userstories/api.py b/greenmine/projects/userstories/api.py index fb49680b..f47f7fcf 100644 --- a/greenmine/projects/userstories/api.py +++ b/greenmine/projects/userstories/api.py @@ -4,9 +4,9 @@ from django.utils.translation import ugettext_lazy as _ from django.contrib.contenttypes.models import ContentType from rest_framework.permissions import IsAuthenticated -from rest_framework.exceptions import ParseError from greenmine.base import filters +from greenmine.base import exceptions as exc from greenmine.base.api import ModelCrudViewSet from greenmine.base.notifications.api import NotificationSenderMixin from greenmine.projects.permissions import AttachmentPermission @@ -29,16 +29,17 @@ class UserStoryAttachmentViewSet(ModelCrudViewSet): def get_queryset(self): ct = ContentType.objects.get_for_model(models.UserStory) - qs = super(UserStoryAttachmentViewSet, self).get_queryset() + qs = super().get_queryset() qs = qs.filter(content_type=ct) return qs.distinct() def pre_save(self, obj): - super(UserStoryAttachmentViewSet, self).pre_save(obj) if not obj.id: obj.content_type = ContentType.objects.get_for_model(models.UserStory) obj.owner = self.request.user + super().pre_save(obj) + class UserStoryViewSet(NotificationSenderMixin, ModelCrudViewSet): model = models.UserStory @@ -46,25 +47,31 @@ class UserStoryViewSet(NotificationSenderMixin, ModelCrudViewSet): permission_classes = (IsAuthenticated, permissions.UserStoryPermission) filter_backends = (filters.IsProjectMemberFilterBackend,) filter_fields = ['project', 'milestone', 'milestone__isnull'] + create_notification_template = "create_userstory_notification" update_notification_template = "update_userstory_notification" destroy_notification_template = "destroy_userstory_notification" - def pre_save(self, obj): - super(UserStoryViewSet, self).pre_save(obj) - if not obj.id: - obj.owner = self.request.user + def pre_conditions_on_save(self, obj): + super().pre_conditions_on_save(obj) if (obj.project.owner != self.request.user and obj.project.memberships.filter(user=self.request.user).count() == 0): - raise ParseError(detail=_("You must not add a new user story to this project.")) + raise exc.PreconditionError("You must not add a new user story to this project.") if obj.milestone and obj.milestone.project != obj.project: - raise ParseError(detail=_("You must not add a new user story to this milestone.")) + raise exc.PreconditionError("You must not add a new user story to this milestone.") + + def pre_save(self, obj): + if not obj.id: + obj.owner = self.request.user + + super().pre_save(obj) def post_save(self, obj, created=False): with reversion.create_revision(): if "comment" in self.request.DATA: # Update the comment in the last version reversion.set_comment(self.request.DATA['comment']) - super(UserStoryViewSet, self).post_save(obj, created) + + super().post_save(obj, created)