Skip to content
Snippets Groups Projects
decorators.py 3.41 KiB
Newer Older
  • Learn to ignore specific revisions
  • from django.db import transaction
    
    
    from rest_framework import decorators
    
    from rest_framework import exceptions
    from rest_framework import response
    from rest_framework import status
    
    from . import filters
    from . import models
    from . import mutations as common_mutations
    from . import serializers
    from . import signals
    from . import tasks
    from . import utils
    
    
    
    def action_route(serializer_class):
    
        @decorators.action(methods=["post"], detail=False)
    
        def action(self, request, *args, **kwargs):
            queryset = self.get_queryset()
            serializer = serializer_class(request.data, queryset=queryset)
            serializer.is_valid(raise_exception=True)
            result = serializer.save()
            return response.Response(result, status=200)
    
        return action
    
    
    
    def mutations_route(types):
        """
        Given a queryset and a list of mutation types, return a view
        that can be included in any viewset, and serve:
    
        GET /{id}/mutations/ - list of mutations for the given object
        POST /{id}/mutations/ - create a mutation for the given object
        """
    
        @transaction.atomic
        def mutations(self, request, *args, **kwargs):
            obj = self.get_object()
            if request.method == "GET":
                queryset = models.Mutation.objects.get_for_target(obj).filter(
                    type__in=types
                )
                queryset = queryset.order_by("-creation_date")
                filterset = filters.MutationFilter(request.GET, queryset=queryset)
                page = self.paginate_queryset(filterset.qs)
                if page is not None:
                    serializer = serializers.APIMutationSerializer(page, many=True)
                    return self.get_paginated_response(serializer.data)
    
                serializer = serializers.APIMutationSerializer(queryset, many=True)
                return response.Response(serializer.data)
            if request.method == "POST":
                if not request.user.is_authenticated:
                    raise exceptions.NotAuthenticated()
                serializer = serializers.APIMutationSerializer(
                    data=request.data, context={"registry": common_mutations.registry}
                )
                serializer.is_valid(raise_exception=True)
                if not common_mutations.registry.has_perm(
                    actor=request.user.actor,
                    type=serializer.validated_data["type"],
                    obj=obj,
                    perm="approve"
                    if serializer.validated_data.get("is_approved", False)
                    else "suggest",
                ):
                    raise exceptions.PermissionDenied()
    
                final_payload = common_mutations.registry.get_validated_payload(
                    type=serializer.validated_data["type"],
                    payload=serializer.validated_data["payload"],
                    obj=obj,
                )
                mutation = serializer.save(
                    created_by=request.user.actor,
                    target=obj,
                    payload=final_payload,
                    is_approved=serializer.validated_data.get("is_approved", None),
                )
                if mutation.is_approved:
                    utils.on_commit(tasks.apply_mutation.delay, mutation_id=mutation.pk)
    
                utils.on_commit(
                    signals.mutation_created.send, sender=None, mutation=mutation
                )
                return response.Response(serializer.data, status=status.HTTP_201_CREATED)
    
    
        return decorators.action(
            methods=["get", "post"], detail=True, required_scope="edits"
        )(mutations)