From 46f4b7397654f0e9d8d169308b9ef905ce481209 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 4 Nov 2014 17:37:50 -0400 Subject: [PATCH] Close issue #111, Add Checkouts API endpoints --- mayan/apps/checkouts/__init__.py | 3 + mayan/apps/checkouts/api_views.py | 121 ++++++++++++++++++++++++++++ mayan/apps/checkouts/serializers.py | 33 ++++++++ mayan/apps/checkouts/urls.py | 7 ++ 4 files changed, 164 insertions(+) create mode 100644 mayan/apps/checkouts/api_views.py create mode 100644 mayan/apps/checkouts/serializers.py diff --git a/mayan/apps/checkouts/__init__.py b/mayan/apps/checkouts/__init__.py index 1dc3236c94..6b556e3bf3 100644 --- a/mayan/apps/checkouts/__init__.py +++ b/mayan/apps/checkouts/__init__.py @@ -7,6 +7,7 @@ from documents.models import Document from mayan.celery import app from history.api import register_history_type from navigation.api import register_links, register_top_menu +from rest_api.classes import APIEndPoint from .events import (HISTORY_DOCUMENT_AUTO_CHECKED_IN, HISTORY_DOCUMENT_CHECKED_OUT, @@ -55,3 +56,5 @@ register_history_type(HISTORY_DOCUMENT_FORCEFUL_CHECK_IN) register_links(Document, [checkout_info], menu_name='form_header') register_links(['checkouts:checkout_info', 'checkouts:checkout_document', 'checkouts:checkin_document'], [checkout_document, checkin_document], menu_name="sidebar") register_top_menu(name='checkouts', link=checkout_list) + +APIEndPoint('checkouts') diff --git a/mayan/apps/checkouts/api_views.py b/mayan/apps/checkouts/api_views.py new file mode 100644 index 0000000000..b9943b353d --- /dev/null +++ b/mayan/apps/checkouts/api_views.py @@ -0,0 +1,121 @@ +from __future__ import absolute_import + +from django.core.exceptions import PermissionDenied +from django.shortcuts import get_object_or_404 + +import pytz +from rest_framework import generics, status, views +from rest_framework.response import Response + +from acls.models import AccessEntry +from documents.models import Document +from documents.permissions import PERMISSION_DOCUMENT_VIEW +from permissions.models import Permission +from rest_api.filters import MayanObjectPermissionsFilter +from rest_api.permissions import MayanPermission + +from .models import DocumentCheckout +from .permissions import PERMISSION_DOCUMENT_CHECKOUT, PERMISSION_DOCUMENT_CHECKIN, PERMISSION_DOCUMENT_CHECKIN_OVERRIDE +from .serializers import DocumentCheckoutSerializer, NewDocumentCheckoutSerializer + + +class APICheckedoutDocumentListView(generics.ListCreateAPIView): + def get_serializer_class(self): + if self.request.method == 'POST': + return NewDocumentCheckoutSerializer + else: + return DocumentCheckoutSerializer + + def get_queryset(self): + documents = DocumentCheckout.objects.checked_out_documents() + + try: + Permission.objects.check_permissions(self.request.user, [PERMISSION_DOCUMENT_VIEW]) + except PermissionDenied: + filtered_documents = AccessEntry.objects.filter_objects_by_access([PERMISSION_DOCUMENT_VIEW], self.request.user, documents) + else: + filtered_documents = documents + + return DocumentCheckout.objects.filter(document__pk__in=documents.values_list('pk', flat=True)) + + def get(self, request, *args, **kwargs): + """ + Returns a list of all the documents that are currently checked out. + """ + return super(APICheckedoutDocumentListView, self).get(request, *args, **kwargs) + + + def post(self, request, *args, **kwargs): + """ + Checkout a document. + """ + serializer = self.get_serializer(data=request.DATA, files=request.FILES) + + if serializer.is_valid(): + document = get_object_or_404(Document, pk=serializer.data['document']) + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_CHECKOUT]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_CHECKOUT, request.user, document) + + timezone = pytz.utc + + try: + DocumentCheckout.objects.create( + document=document, + expiration_datetime=timezone.localize(serializer.data['expiration_datetime']), + user_object=request.user, + block_new_version=serializer.data['block_new_version'] + ) + except Exception as exception: + return Response(data={'exception': unicode(exception)}, status=status.HTTP_400_BAD_REQUEST) + + return Response(status=status.HTTP_201_CREATED) + + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + +class APICheckedoutDocumentView(generics.RetrieveDestroyAPIView): + serializer_class = DocumentCheckoutSerializer + + def get_queryset(self): + if self.request.method == 'GET': + documents = DocumentCheckout.objects.checked_out_documents() + + try: + Permission.objects.check_permissions(self.request.user, [PERMISSION_DOCUMENT_VIEW]) + except PermissionDenied: + filtered_documents = AccessEntry.objects.filter_objects_by_access([PERMISSION_DOCUMENT_VIEW], self.request.user, documents) + else: + filtered_documents = documents + + return DocumentCheckout.objects.filter(document__pk__in=documents.values_list('pk', flat=True)) + elif self.request.method == 'DELETE': + return DocumentCheckout.objects.all() + + def get(self, request, *args, **kwargs): + """ + Retrieve the details of the selected checked out document entry. + """ + + return super(APICheckedoutDocumentView, self).get(request, *args, **kwargs) + + def delete(self, request, *args, **kwargs): + """ + Checkin a document. + """ + + document = self.get_object().document + + if document.checkout_info().user_object == request.user: + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_CHECKIN]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_CHECKIN, request.user, document) + else: + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_CHECKIN_OVERRIDE]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_CHECKIN_OVERRIDE, request.user, document) + + return super(APICheckedoutDocumentView, self).delete(request, *args, **kwargs) diff --git a/mayan/apps/checkouts/serializers.py b/mayan/apps/checkouts/serializers.py new file mode 100644 index 0000000000..49179eb553 --- /dev/null +++ b/mayan/apps/checkouts/serializers.py @@ -0,0 +1,33 @@ +from __future__ import absolute_import + +from rest_framework import serializers + +from documents.serializers import DocumentSerializer + +from .models import DocumentCheckout + + +#class DocumentCheckoutSerializer(serializers.Serializer): +# document_id = serializers.IntegerField() + + +class DocumentCheckoutSerializer(serializers.ModelSerializer): + document = DocumentSerializer() + #document = serializers.IntegerField() + + class Meta: + model = DocumentCheckout + #fields = ('id', 'document', 'checkout_datetime', 'expiration_datetime', 'block_new_version') + read_only_fields = ('user_content_type', 'user_object_id') + + +class NewDocumentCheckoutSerializer(serializers.Serializer): + #document = DocumentSerializer() + document = serializers.IntegerField() + expiration_datetime = serializers.DateTimeField() + block_new_version = serializers.BooleanField() + + #class Meta: + # model = DocumentCheckout + # fields = ('id', 'document', 'checkout_datetime', 'expiration_datetime', 'block_new_version') + # #read_only_fields = ('user_content_type', 'user_object_id') diff --git a/mayan/apps/checkouts/urls.py b/mayan/apps/checkouts/urls.py index d82a26ee0a..efa04c1341 100644 --- a/mayan/apps/checkouts/urls.py +++ b/mayan/apps/checkouts/urls.py @@ -1,8 +1,15 @@ from django.conf.urls import patterns, url +from .api_views import APICheckedoutDocumentListView, APICheckedoutDocumentView + urlpatterns = patterns('checkouts.views', url(r'^list/$', 'checkout_list', (), 'checkout_list'), url(r'^(?P\d+)/check/out/$', 'checkout_document', (), 'checkout_document'), url(r'^(?P\d+)/check/in/$', 'checkin_document', (), 'checkin_document'), url(r'^(?P\d+)/check/info/$', 'checkout_info', (), 'checkout_info'), ) + +api_urls = patterns('', + url(r'^documents/$', APICheckedoutDocumentListView.as_view(), name='checkout-document-list'), + url(r'^documents/(?P[0-9]+)/$', APICheckedoutDocumentView.as_view(), name='checkedout-document-view'), +)