From deb363ee1606d73420cab20b9f73ca5cc70e4eca Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 28 Oct 2019 00:01:11 -0400 Subject: [PATCH] API updates - Move all generic API classes definitions to the rest_api.generics module. - Update API status code on insufficient access for the apps: indexes, parsing, documents, metadata, ocr, permission, user management. - Update API tests. Signed-off-by: Roberto Rosario --- HISTORY.rst | 5 + mayan/apps/acls/api_views.py | 2 +- mayan/apps/cabinets/api_views.py | 14 +- mayan/apps/checkouts/api_views.py | 3 +- mayan/apps/common/api_views.py | 3 +- mayan/apps/django_gpg/api_views.py | 8 +- mayan/apps/document_comments/api_views.py | 3 +- mayan/apps/document_indexing/api_views.py | 17 +- .../apps/document_indexing/tests/test_api.py | 4 +- mayan/apps/document_parsing/api_views.py | 4 +- mayan/apps/document_parsing/tests/test_api.py | 2 +- mayan/apps/document_states/api_views.py | 14 +- mayan/apps/documents/api_views.py | 19 +-- mayan/apps/documents/tests/test_api.py | 20 +-- mayan/apps/dynamic_search/api_views.py | 7 +- mayan/apps/dynamic_search/settings.py | 2 - mayan/apps/events/api_views.py | 4 +- mayan/apps/linking/api_views.py | 14 +- mayan/apps/metadata/api_views.py | 12 +- mayan/apps/metadata/tests/test_api.py | 8 +- mayan/apps/motd/api_views.py | 8 +- mayan/apps/ocr/api_views.py | 7 +- mayan/apps/ocr/tests/test_api.py | 6 +- mayan/apps/permissions/api_views.py | 8 +- mayan/apps/permissions/tests/test_api.py | 15 +- mayan/apps/rest_api/generics.py | 75 +++++++++ mayan/apps/sources/api_views.py | 3 +- mayan/apps/tags/api_views.py | 10 +- mayan/apps/user_management/api_views.py | 17 +- mayan/apps/user_management/tests/mixins.py | 4 +- mayan/apps/user_management/tests/test_api.py | 158 +++++++++++------- 31 files changed, 232 insertions(+), 244 deletions(-) create mode 100644 mayan/apps/rest_api/generics.py diff --git a/HISTORY.rst b/HISTORY.rst index 29ceb7331d..59a7c49e1c 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -93,6 +93,11 @@ Robert Schöftner (@robert.schoeftner). - Support simple search disable via the new SEARCH_DISABLE_SIMPLE_SEARCH setting. +- Move all generic API classes definitions to the + rest_api.generics module. +- Update API status code on insufficient access for the apps: + indexes, parsing, documents, metadata, ocr, permission, + user management. 3.2.8 (2019-10-01) ================== diff --git a/mayan/apps/acls/api_views.py b/mayan/apps/acls/api_views.py index 3dcb283982..d4e4dc872f 100644 --- a/mayan/apps/acls/api_views.py +++ b/mayan/apps/acls/api_views.py @@ -3,7 +3,7 @@ from __future__ import absolute_import, unicode_literals from django.contrib.contenttypes.models import ContentType from django.shortcuts import get_object_or_404 -from rest_framework import generics +from mayan.apps.rest_api import generics from .models import AccessControlList from .permissions import permission_acl_edit, permission_acl_view diff --git a/mayan/apps/cabinets/api_views.py b/mayan/apps/cabinets/api_views.py index 63adbac3ce..d558556ec5 100644 --- a/mayan/apps/cabinets/api_views.py +++ b/mayan/apps/cabinets/api_views.py @@ -2,14 +2,12 @@ from __future__ import absolute_import, unicode_literals from django.shortcuts import get_object_or_404 -from rest_framework import generics from rest_framework.response import Response from mayan.apps.acls.models import AccessControlList from mayan.apps.documents.models import Document from mayan.apps.documents.permissions import permission_document_view -from mayan.apps.rest_api.filters import MayanObjectPermissionsFilter -from mayan.apps.rest_api.permissions import MayanPermission +from mayan.apps.rest_api import generics from .models import Cabinet from .permissions import ( @@ -27,10 +25,8 @@ class APIDocumentCabinetListView(generics.ListAPIView): """ Returns a list of all the cabinets to which a document belongs. """ - serializer_class = CabinetSerializer - - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = {'GET': (permission_cabinet_view,)} + serializer_class = CabinetSerializer def get_queryset(self): document = get_object_or_404(klass=Document, pk=self.kwargs['pk']) @@ -48,10 +44,8 @@ class APICabinetListView(generics.ListCreateAPIView): get: Returns a list of all the cabinets. post: Create a new cabinet """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = {'GET': (permission_cabinet_view,)} mayan_view_permissions = {'POST': (permission_cabinet_create,)} - permission_classes = (MayanPermission,) queryset = Cabinet.objects.all() def get_serializer(self, *args, **kwargs): @@ -74,14 +68,12 @@ class APICabinetView(generics.RetrieveUpdateDestroyAPIView): patch: Edit the selected cabinet. put: Edit the selected cabinet. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = { 'GET': (permission_cabinet_view,), 'PUT': (permission_cabinet_edit,), 'PATCH': (permission_cabinet_edit,), 'DELETE': (permission_cabinet_delete,) } - permission_classes = (MayanPermission,) queryset = Cabinet.objects.all() def get_serializer(self, *args, **kwargs): @@ -102,7 +94,6 @@ class APICabinetDocumentListView(generics.ListCreateAPIView): get: Returns a list of all the documents contained in a particular cabinet. post: Add a document to the selected cabinet. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = { 'GET': (permission_cabinet_view,), 'POST': (permission_cabinet_add_document,) @@ -154,7 +145,6 @@ class APICabinetDocumentView(generics.RetrieveDestroyAPIView): delete: Remove a document from the selected cabinet. get: Returns the details of the selected cabinet document. """ - filter_backends = (MayanObjectPermissionsFilter,) lookup_url_kwarg = 'document_pk' mayan_object_permissions = { 'GET': (permission_cabinet_view,), diff --git a/mayan/apps/checkouts/api_views.py b/mayan/apps/checkouts/api_views.py index 3207502700..39fbba273d 100644 --- a/mayan/apps/checkouts/api_views.py +++ b/mayan/apps/checkouts/api_views.py @@ -1,9 +1,8 @@ from __future__ import absolute_import, unicode_literals -from rest_framework import generics - from mayan.apps.acls.models import AccessControlList from mayan.apps.documents.permissions import permission_document_view +from mayan.apps.rest_api import generics from .models import DocumentCheckout from .permissions import ( diff --git a/mayan/apps/common/api_views.py b/mayan/apps/common/api_views.py index 868fa1861e..a556e332b0 100644 --- a/mayan/apps/common/api_views.py +++ b/mayan/apps/common/api_views.py @@ -2,9 +2,10 @@ from __future__ import unicode_literals from django.contrib.contenttypes.models import ContentType -from rest_framework import generics from rest_framework.permissions import IsAuthenticated +from mayan.apps.rest_api import generics + from .classes import Template from .serializers import ContentTypeSerializer, TemplateSerializer diff --git a/mayan/apps/django_gpg/api_views.py b/mayan/apps/django_gpg/api_views.py index 47014873da..d7e152b757 100644 --- a/mayan/apps/django_gpg/api_views.py +++ b/mayan/apps/django_gpg/api_views.py @@ -1,9 +1,6 @@ from __future__ import absolute_import, unicode_literals -from rest_framework import generics - -from mayan.apps.rest_api.filters import MayanObjectPermissionsFilter -from mayan.apps.rest_api.permissions import MayanPermission +from mayan.apps.rest_api import generics from .models import Key from .permissions import ( @@ -17,10 +14,8 @@ class APIKeyListView(generics.ListCreateAPIView): get: Returns a list of all the keys. post: Upload a new key. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = {'GET': (permission_key_view,)} mayan_view_permissions = {'POST': (permission_key_upload,)} - permission_classes = (MayanPermission,) queryset = Key.objects.all() serializer_class = KeySerializer @@ -30,7 +25,6 @@ class APIKeyView(generics.RetrieveDestroyAPIView): delete: Delete the selected key. get: Return the details of the selected key. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = { 'DELETE': (permission_key_delete,), 'GET': (permission_key_view,), diff --git a/mayan/apps/document_comments/api_views.py b/mayan/apps/document_comments/api_views.py index 0638c6f0f4..5fb6fa5493 100644 --- a/mayan/apps/document_comments/api_views.py +++ b/mayan/apps/document_comments/api_views.py @@ -2,10 +2,9 @@ from __future__ import absolute_import, unicode_literals from django.shortcuts import get_object_or_404 -from rest_framework import generics - from mayan.apps.acls.models import AccessControlList from mayan.apps.documents.models import Document +from mayan.apps.rest_api import generics from .permissions import ( permission_document_comment_create, permission_document_comment_delete, diff --git a/mayan/apps/document_indexing/api_views.py b/mayan/apps/document_indexing/api_views.py index e26a766116..efd332d86c 100644 --- a/mayan/apps/document_indexing/api_views.py +++ b/mayan/apps/document_indexing/api_views.py @@ -2,14 +2,11 @@ from __future__ import absolute_import, unicode_literals from django.shortcuts import get_object_or_404 -from rest_framework import generics - from mayan.apps.acls.models import AccessControlList from mayan.apps.documents.models import Document from mayan.apps.documents.permissions import permission_document_view from mayan.apps.documents.serializers import DocumentSerializer -from mayan.apps.rest_api.filters import MayanObjectPermissionsFilter -from mayan.apps.rest_api.permissions import MayanPermission +from mayan.apps.rest_api import generics from .models import Index, IndexInstanceNode, IndexTemplateNode from .permissions import ( @@ -26,10 +23,8 @@ class APIIndexListView(generics.ListCreateAPIView): get: Returns a list of all the defined indexes. post: Create a new index. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = {'GET': (permission_document_indexing_view,)} mayan_view_permissions = {'POST': (permission_document_indexing_create,)} - permission_classes = (MayanPermission,) queryset = Index.objects.all() serializer_class = IndexSerializer @@ -47,7 +42,6 @@ class APIIndexView(generics.RetrieveUpdateDestroyAPIView): 'PATCH': (permission_document_indexing_edit,), 'DELETE': (permission_document_indexing_delete,) } - permission_classes = (MayanPermission,) queryset = Index.objects.all() serializer_class = IndexSerializer @@ -57,7 +51,6 @@ class APIIndexNodeInstanceDocumentListView(generics.ListAPIView): Returns a list of all the documents contained by a particular index node instance. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = {'GET': (permission_document_view,)} serializer_class = DocumentSerializer @@ -78,7 +71,6 @@ class APIIndexTemplateListView(generics.ListAPIView): """ get: Returns a list of all the template nodes for the selected index. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = {'GET': (permission_document_indexing_view,)} serializer_class = IndexTemplateNodeSerializer @@ -90,23 +82,20 @@ class APIIndexTemplateView(generics.RetrieveUpdateDestroyAPIView): patch: Partially edit an index template node. put: Edit an index template node. """ - serializer_class = IndexTemplateNodeSerializer - queryset = IndexTemplateNode.objects.all() - - permission_classes = (MayanPermission,) mayan_object_permissions = { 'GET': (permission_document_indexing_view,), 'PUT': (permission_document_indexing_edit,), 'PATCH': (permission_document_indexing_edit,), 'DELETE': (permission_document_indexing_edit,) } + queryset = IndexTemplateNode.objects.all() + serializer_class = IndexTemplateNodeSerializer class APIDocumentIndexListView(generics.ListAPIView): """ Returns a list of all the indexes to which a document belongs. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = {'GET': (permission_document_indexing_view,)} serializer_class = IndexInstanceNodeSerializer diff --git a/mayan/apps/document_indexing/tests/test_api.py b/mayan/apps/document_indexing/tests/test_api.py index ad72f1ea63..6cb93d38fe 100644 --- a/mayan/apps/document_indexing/tests/test_api.py +++ b/mayan/apps/document_indexing/tests/test_api.py @@ -69,7 +69,7 @@ class DocumentIndexingAPITestCase( self._create_test_index() response = self._request_test_index_delete_api_view() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.assertTrue(self.test_index in Index.objects.all()) @@ -90,7 +90,7 @@ class DocumentIndexingAPITestCase( response = self._request_test_index_detail_api_view() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.assertTrue('id' not in response.data) def test_index_detail_api_view_with_access(self): diff --git a/mayan/apps/document_parsing/api_views.py b/mayan/apps/document_parsing/api_views.py index 7d29b61d94..a4b68d3d69 100644 --- a/mayan/apps/document_parsing/api_views.py +++ b/mayan/apps/document_parsing/api_views.py @@ -2,11 +2,10 @@ from __future__ import absolute_import, unicode_literals from django.shortcuts import get_object_or_404 -from rest_framework import generics from rest_framework.response import Response from mayan.apps.documents.models import Document -from mayan.apps.rest_api.permissions import MayanPermission +from mayan.apps.rest_api import generics from .models import DocumentPageContent from .permissions import permission_content_view @@ -21,7 +20,6 @@ class APIDocumentPageContentView(generics.RetrieveAPIView): mayan_object_permissions = { 'GET': (permission_content_view,), } - permission_classes = (MayanPermission,) serializer_class = DocumentPageContentSerializer def get_document(self): diff --git a/mayan/apps/document_parsing/tests/test_api.py b/mayan/apps/document_parsing/tests/test_api.py index ed72feb7b3..323ce5af45 100644 --- a/mayan/apps/document_parsing/tests/test_api.py +++ b/mayan/apps/document_parsing/tests/test_api.py @@ -28,7 +28,7 @@ class DocumentParsingAPITestCase(DocumentTestMixin, BaseAPITestCase): def test_get_document_version_page_content_no_access(self): response = self._request_document_page_content_view() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_get_document_version_page_content_with_access(self): self.grant_access( diff --git a/mayan/apps/document_states/api_views.py b/mayan/apps/document_states/api_views.py index 29ba509667..3b162c710f 100644 --- a/mayan/apps/document_states/api_views.py +++ b/mayan/apps/document_states/api_views.py @@ -4,13 +4,10 @@ from django.http import HttpResponse from django.shortcuts import get_object_or_404 from django.views.decorators.cache import cache_control, patch_cache_control -from rest_framework import generics - from mayan.apps.acls.models import AccessControlList from mayan.apps.documents.models import Document, DocumentType from mayan.apps.documents.permissions import permission_document_type_view -from mayan.apps.rest_api.filters import MayanObjectPermissionsFilter -from mayan.apps.rest_api.permissions import MayanPermission +from mayan.apps.rest_api import generics from .literals import WORKFLOW_IMAGE_TASK_TIMEOUT from .models import Workflow @@ -34,7 +31,6 @@ class APIDocumentTypeWorkflowRuntimeProxyListView(generics.ListAPIView): """ get: Returns a list of all the document type workflows. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = { 'GET': (permission_workflow_view,), } @@ -61,7 +57,6 @@ class APIWorkflowDocumentTypeList(generics.ListCreateAPIView): get: Returns a list of all the document types attached to a workflow. post: Attach a document type to a specified workflow. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = { 'GET': (permission_document_type_view,), } @@ -123,7 +118,6 @@ class APIWorkflowDocumentTypeView(generics.RetrieveDestroyAPIView): delete: Remove a document type from the selected workflow. get: Returns the details of the selected workflow document type. """ - filter_backends = (MayanObjectPermissionsFilter,) lookup_url_kwarg = 'document_type_pk' mayan_object_permissions = { 'GET': (permission_document_type_view,), @@ -182,7 +176,6 @@ class APIWorkflowImageView(generics.RetrieveAPIView): """ get: Returns an image representation of the selected workflow. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = { 'GET': (permission_workflow_view,), } @@ -219,10 +212,8 @@ class APIWorkflowRuntimeProxyListView(generics.ListCreateAPIView): get: Returns a list of all the workflows. post: Create a new workflow. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = {'GET': (permission_workflow_view,)} mayan_view_permissions = {'POST': (permission_workflow_create,)} - permission_classes = (MayanPermission,) queryset = Workflow.objects.all() def get_serializer(self, *args, **kwargs): @@ -245,7 +236,6 @@ class APIWorkflowView(generics.RetrieveUpdateDestroyAPIView): patch: Edit the selected workflow. put: Edit the selected workflow. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = { 'DELETE': (permission_workflow_delete,), 'GET': (permission_workflow_view,), @@ -467,7 +457,6 @@ class APIWorkflowInstanceListView(generics.ListAPIView): """ get: Returns a list of all the document workflows. """ - filter_backends = (MayanObjectPermissionsFilter,) serializer_class = WorkflowInstanceSerializer mayan_object_permissions = { 'GET': (permission_workflow_view,), @@ -491,7 +480,6 @@ class APIWorkflowInstanceView(generics.RetrieveAPIView): """ get: Return the details of the selected document workflow. """ - filter_backends = (MayanObjectPermissionsFilter,) lookup_url_kwarg = 'workflow_pk' mayan_object_permissions = { 'GET': (permission_workflow_view,), diff --git a/mayan/apps/documents/api_views.py b/mayan/apps/documents/api_views.py index 4d17038722..2b79d8fb61 100644 --- a/mayan/apps/documents/api_views.py +++ b/mayan/apps/documents/api_views.py @@ -7,12 +7,11 @@ from django.shortcuts import get_object_or_404 from django.views.decorators.cache import cache_control, patch_cache_control from django_downloadview import DownloadMixin, VirtualFile -from rest_framework import generics, status +from rest_framework import status from rest_framework.response import Response from mayan.apps.acls.models import AccessControlList -from mayan.apps.rest_api.filters import MayanObjectPermissionsFilter -from mayan.apps.rest_api.permissions import MayanPermission +from mayan.apps.rest_api import generics from .literals import DOCUMENT_IMAGE_TASK_TIMEOUT from .models import ( @@ -45,9 +44,7 @@ class APITrashedDocumentListView(generics.ListAPIView): """ Returns a list of all the trashed documents. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = {'GET': (permission_document_view,)} - permission_classes = (MayanPermission,) queryset = DeletedDocument.objects.all() serializer_class = DeletedDocumentSerializer @@ -62,7 +59,6 @@ class APIDeletedDocumentView(generics.RetrieveDestroyAPIView): 'DELETE': (permission_document_delete,), 'GET': (permission_document_view,) } - permission_classes = (MayanPermission,) queryset = DeletedDocument.objects.all() serializer_class = DeletedDocumentSerializer @@ -74,7 +70,6 @@ class APIDeletedDocumentRestoreView(generics.GenericAPIView): mayan_object_permissions = { 'POST': (permission_document_restore,) } - permission_classes = (MayanPermission,) queryset = DeletedDocument.objects.all() def get_serializer(self, *args, **kwargs): @@ -95,7 +90,6 @@ class APIDocumentDownloadView(DownloadMixin, generics.RetrieveAPIView): mayan_object_permissions = { 'GET': (permission_document_download,) } - permission_classes = (MayanPermission,) queryset = Document.objects.all() def get_encoding(self): @@ -123,9 +117,7 @@ class APIDocumentListView(generics.ListCreateAPIView): get: Returns a list of all the documents. post: Create a new document. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = {'GET': (permission_document_view,)} - permission_classes = (MayanPermission,) queryset = Document.objects.all() def get_serializer(self, *args, **kwargs): @@ -258,10 +250,8 @@ class APIDocumentTypeListView(generics.ListCreateAPIView): get: Returns a list of all the document types. post: Create a new document type. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = {'GET': (permission_document_type_view,)} mayan_view_permissions = {'POST': (permission_document_type_create,)} - permission_classes = (MayanPermission,) queryset = DocumentType.objects.all() serializer_class = DocumentTypeSerializer @@ -291,7 +281,6 @@ class APIDocumentTypeView(generics.RetrieveUpdateDestroyAPIView): 'PATCH': (permission_document_type_edit,), 'DELETE': (permission_document_type_delete,) } - permission_classes = (MayanPermission,) queryset = DocumentType.objects.all() def get_serializer(self, *args, **kwargs): @@ -311,7 +300,6 @@ class APIDocumentTypeDocumentListView(generics.ListAPIView): """ Returns a list of all the documents of a particular document type. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = {'GET': (permission_document_view,)} serializer_class = DocumentSerializer @@ -389,7 +377,6 @@ class APIDocumentView(generics.RetrieveUpdateDestroyAPIView): 'PATCH': (permission_document_properties_edit,), 'DELETE': (permission_document_trash,) } - permission_classes = (MayanPermission,) queryset = Document.objects.all() def get_serializer(self, *args, **kwargs): @@ -448,11 +435,9 @@ class APIDocumentVersionsListView(generics.ListCreateAPIView): get: Return a list of the selected document's versions. post: Create a new document version. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = { 'GET': (permission_document_version_view,), } - permission_classes = (MayanPermission,) def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) diff --git a/mayan/apps/documents/tests/test_api.py b/mayan/apps/documents/tests/test_api.py index 368ae6186b..e4dfae6daa 100644 --- a/mayan/apps/documents/tests/test_api.py +++ b/mayan/apps/documents/tests/test_api.py @@ -88,7 +88,7 @@ class DocumentTypeAPIViewTestCase( ) response = self._request_test_document_type_api_delete_view() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_document_type_api_delete_view_with_access(self): self.test_document_type = DocumentType.objects.create( @@ -110,7 +110,7 @@ class DocumentTypeAPIViewTestCase( ) response = self._request_test_document_type_api_patch_view() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_document_type_api_edit_via_patch_view_with_access(self): self.test_document_type = DocumentType.objects.create( @@ -133,7 +133,7 @@ class DocumentTypeAPIViewTestCase( self._create_document_type() response = self._request_test_document_type_api_put_view() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_document_type_api_edit_via_put_view_with_access(self): self.test_document_type = DocumentType.objects.create( @@ -194,7 +194,7 @@ class DocumentAPIViewTestCase( self.upload_document() response = self._request_test_document_api_download_view() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_document_api_download_view_with_access(self): self.upload_document() @@ -258,7 +258,7 @@ class DocumentAPIViewTestCase( self.upload_document() response = self._request_test_document_description_api_edit_via_patch_view() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_document_description_api_edit_via_patch_view_with_access(self): self.upload_document() @@ -280,7 +280,7 @@ class DocumentAPIViewTestCase( self.upload_document() response = self._request_test_document_description_api_edit_via_put_view() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_document_description_api_edit_via_put_view_with_access(self): self.upload_document() @@ -606,7 +606,7 @@ class TrashedDocumentAPIViewTestCase( self.upload_document() response = self._request_test_document_api_trash_view() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_document_api_trash_view_with_access(self): self.upload_document() @@ -625,7 +625,7 @@ class TrashedDocumentAPIViewTestCase( self.test_document.delete() response = self._request_test_trashed_document_api_delete_view() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.assertEqual(Document.objects.count(), 0) self.assertEqual(Document.trash.count(), 1) @@ -648,7 +648,7 @@ class TrashedDocumentAPIViewTestCase( self.test_document.delete() response = self._request_test_trashed_document_api_detail_view() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.assertFalse('uuid' in response.data) def test_trashed_document_api_detail_view_with_access(self): @@ -708,7 +708,7 @@ class TrashedDocumentAPIViewTestCase( self.test_document.delete() response = self._request_test_trashed_document_api_restore_view() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.assertEqual(Document.trash.count(), 1) self.assertEqual(Document.objects.count(), 0) diff --git a/mayan/apps/dynamic_search/api_views.py b/mayan/apps/dynamic_search/api_views.py index b374059f9e..f4ce98ec73 100644 --- a/mayan/apps/dynamic_search/api_views.py +++ b/mayan/apps/dynamic_search/api_views.py @@ -2,10 +2,9 @@ from __future__ import unicode_literals from django.utils.encoding import force_text -from rest_framework import generics from rest_framework.exceptions import ParseError -from mayan.apps.rest_api.filters import MayanObjectPermissionsFilter +from mayan.apps.rest_api import generics from .classes import SearchModel from .mixins import SearchModelMixin @@ -16,8 +15,6 @@ class APISearchView(SearchModelMixin, generics.ListAPIView): """ get: Perform a search operation """ - filter_backends = (MayanObjectPermissionsFilter,) - def get_queryset(self): search_model = self.get_search_model() @@ -48,8 +45,6 @@ class APIAdvancedSearchView(SearchModelMixin, generics.ListAPIView): """ get: Perform an advanced search operation """ - filter_backends = (MayanObjectPermissionsFilter,) - def get_queryset(self): self.search_model = self.get_search_model() diff --git a/mayan/apps/dynamic_search/settings.py b/mayan/apps/dynamic_search/settings.py index 7d48be879b..e929fb3b5e 100644 --- a/mayan/apps/dynamic_search/settings.py +++ b/mayan/apps/dynamic_search/settings.py @@ -1,6 +1,5 @@ from __future__ import unicode_literals -from django.conf import settings from django.utils.translation import ugettext_lazy as _ from mayan.apps.smart_settings.classes import Namespace @@ -14,4 +13,3 @@ setting_disable_simple_search = namespace.add_setting( 'search button.' ) ) - diff --git a/mayan/apps/events/api_views.py b/mayan/apps/events/api_views.py index dff3b7a3f2..9be9d2e49d 100644 --- a/mayan/apps/events/api_views.py +++ b/mayan/apps/events/api_views.py @@ -5,10 +5,9 @@ from django.http import Http404 from django.shortcuts import get_object_or_404 from actstream.models import Action, any_stream -from rest_framework import generics from mayan.apps.acls.models import AccessControlList -from mayan.apps.rest_api.permissions import MayanPermission +from mayan.apps.rest_api import generics from .classes import EventType, EventTypeNamespace from .models import Notification @@ -119,7 +118,6 @@ class APIEventListView(generics.ListAPIView): get: Returns a list of all the available events. """ mayan_view_permissions = {'GET': (permission_events_view,)} - permission_classes = (MayanPermission,) queryset = Action.objects.all() serializer_class = EventSerializer diff --git a/mayan/apps/linking/api_views.py b/mayan/apps/linking/api_views.py index 63f23ac69d..3be559b23f 100644 --- a/mayan/apps/linking/api_views.py +++ b/mayan/apps/linking/api_views.py @@ -2,13 +2,10 @@ from __future__ import absolute_import, unicode_literals from django.shortcuts import get_object_or_404 -from rest_framework import generics - from mayan.apps.acls.models import AccessControlList from mayan.apps.documents.models import Document from mayan.apps.documents.permissions import permission_document_view -from mayan.apps.rest_api.filters import MayanObjectPermissionsFilter -from mayan.apps.rest_api.permissions import MayanPermission +from mayan.apps.rest_api import generics from .models import SmartLink from .permissions import ( @@ -26,9 +23,7 @@ class APIResolvedSmartLinkDocumentListView(generics.ListAPIView): """ get: Returns a list of the smart link documents that apply to the document. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = {'GET': (permission_document_view,)} - permission_classes = (MayanPermission,) serializer_class = ResolvedSmartLinkDocumentSerializer def get_document(self): @@ -81,10 +76,8 @@ class APIResolvedSmartLinkView(generics.RetrieveAPIView): """ get: Return the details of the selected resolved smart link. """ - filter_backends = (MayanObjectPermissionsFilter,) lookup_url_kwarg = 'smart_link_pk' mayan_object_permissions = {'GET': (permission_smart_link_view,)} - permission_classes = (MayanPermission,) serializer_class = ResolvedSmartLinkSerializer def get_document(self): @@ -119,9 +112,7 @@ class APIResolvedSmartLinkListView(generics.ListAPIView): """ get: Returns a list of the smart links that apply to the document. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = {'GET': (permission_smart_link_view,)} - permission_classes = (MayanPermission,) serializer_class = ResolvedSmartLinkSerializer def get_document(self): @@ -242,10 +233,8 @@ class APISmartLinkListView(generics.ListCreateAPIView): get: Returns a list of all the smart links. post: Create a new smart link. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = {'GET': (permission_smart_link_view,)} mayan_view_permissions = {'POST': (permission_smart_link_create,)} - permission_classes = (MayanPermission,) queryset = SmartLink.objects.all() def get_serializer(self, *args, **kwargs): @@ -268,7 +257,6 @@ class APISmartLinkView(generics.RetrieveUpdateDestroyAPIView): patch: Edit the selected smart link. put: Edit the selected smart link. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = { 'DELETE': (permission_smart_link_delete,), 'GET': (permission_smart_link_view,), diff --git a/mayan/apps/metadata/api_views.py b/mayan/apps/metadata/api_views.py index e343caff59..45a20cf95e 100644 --- a/mayan/apps/metadata/api_views.py +++ b/mayan/apps/metadata/api_views.py @@ -2,15 +2,12 @@ from __future__ import absolute_import, unicode_literals from django.shortcuts import get_object_or_404 -from rest_framework import generics - from mayan.apps.acls.models import AccessControlList from mayan.apps.documents.models import Document, DocumentType from mayan.apps.documents.permissions import ( permission_document_type_view, permission_document_type_edit ) -from mayan.apps.rest_api.filters import MayanObjectPermissionsFilter -from mayan.apps.rest_api.permissions import MayanPermission +from mayan.apps.rest_api import generics from .models import MetadataType from .permissions import ( @@ -130,10 +127,8 @@ class APIMetadataTypeListView(generics.ListCreateAPIView): get: Returns a list of all the metadata types. post: Create a new metadata type. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = {'GET': (permission_metadata_type_view,)} mayan_view_permissions = {'POST': (permission_metadata_type_create,)} - permission_classes = (MayanPermission,) queryset = MetadataType.objects.all() serializer_class = MetadataTypeSerializer @@ -152,7 +147,6 @@ class APIMetadataTypeView(generics.RetrieveUpdateDestroyAPIView): 'PATCH': (permission_metadata_type_edit,), 'DELETE': (permission_metadata_type_delete,) } - permission_classes = (MayanPermission,) queryset = MetadataType.objects.all() serializer_class = MetadataTypeSerializer @@ -188,7 +182,9 @@ class APIDocumentTypeMetadataTypeListView(generics.ListCreateAPIView): if not self.request: return None - return super(APIDocumentTypeMetadataTypeListView, self).get_serializer(*args, **kwargs) + return super( + APIDocumentTypeMetadataTypeListView, self + ).get_serializer(*args, **kwargs) def get_serializer_class(self): if self.request.method == 'GET': diff --git a/mayan/apps/metadata/tests/test_api.py b/mayan/apps/metadata/tests/test_api.py index f74f7cdfce..e55ef4b20f 100644 --- a/mayan/apps/metadata/tests/test_api.py +++ b/mayan/apps/metadata/tests/test_api.py @@ -46,7 +46,7 @@ class MetadataTypeAPITestCase( self._create_test_metadata_type() response = self._request_test_metadata_type_delete_view() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.assertEqual(MetadataType.objects.count(), 1) def test_metadata_type_delete_with_access(self): @@ -70,7 +70,7 @@ class MetadataTypeAPITestCase( self._create_test_metadata_type() response = self._request_metadata_type_detail_view() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_metadata_type_detail_view_with_access(self): self._create_test_metadata_type() @@ -101,7 +101,7 @@ class MetadataTypeAPITestCase( ) response = self._request_test_metadata_type_edit_view_via_patch() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.test_metadata_type.refresh_from_db() self.assertEqual( @@ -145,7 +145,7 @@ class MetadataTypeAPITestCase( ) response = self._request_test_metadata_type_edit_view_via_put() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.test_metadata_type.refresh_from_db() self.assertEqual( diff --git a/mayan/apps/motd/api_views.py b/mayan/apps/motd/api_views.py index 0dba8b92a4..aa449e5c63 100644 --- a/mayan/apps/motd/api_views.py +++ b/mayan/apps/motd/api_views.py @@ -1,9 +1,6 @@ from __future__ import absolute_import, unicode_literals -from rest_framework import generics - -from mayan.apps.rest_api.filters import MayanObjectPermissionsFilter -from mayan.apps.rest_api.permissions import MayanPermission +from mayan.apps.rest_api import generics from .models import Message from .permissions import ( @@ -18,10 +15,8 @@ class APIMessageListView(generics.ListCreateAPIView): get: Returns a list of all the messages. post: Create a new message. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = {'GET': (permission_message_view,)} mayan_view_permissions = {'POST': (permission_message_create,)} - permission_classes = (MayanPermission,) queryset = Message.objects.all() serializer_class = MessageSerializer @@ -33,7 +28,6 @@ class APIMessageView(generics.RetrieveUpdateDestroyAPIView): patch: Edit the selected message. put: Edit the selected message. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = { 'DELETE': (permission_message_delete,), 'GET': (permission_message_view,), diff --git a/mayan/apps/ocr/api_views.py b/mayan/apps/ocr/api_views.py index 0dea74beb3..ba3f214a6f 100644 --- a/mayan/apps/ocr/api_views.py +++ b/mayan/apps/ocr/api_views.py @@ -2,11 +2,11 @@ from __future__ import absolute_import, unicode_literals from django.shortcuts import get_object_or_404 -from rest_framework import generics, status +from rest_framework import status from rest_framework.response import Response from mayan.apps.documents.models import Document, DocumentVersion -from mayan.apps.rest_api.permissions import MayanPermission +from mayan.apps.rest_api import generics from .models import DocumentPageOCRContent from .permissions import permission_ocr_content_view, permission_ocr_document @@ -20,7 +20,6 @@ class APIDocumentOCRView(generics.GenericAPIView): mayan_object_permissions = { 'POST': (permission_ocr_document,) } - permission_classes = (MayanPermission,) queryset = Document.objects.all() def get_serializer(self, *args, **kwargs): @@ -42,7 +41,6 @@ class APIDocumentVersionOCRView(generics.GenericAPIView): mayan_object_permissions = { 'POST': (permission_ocr_document,) } - permission_classes = (MayanPermission,) queryset = DocumentVersion.objects.all() def get_document(self): @@ -70,7 +68,6 @@ class APIDocumentPageOCRContentView(generics.RetrieveAPIView): mayan_object_permissions = { 'GET': (permission_ocr_content_view,), } - permission_classes = (MayanPermission,) serializer_class = DocumentPageOCRContentSerializer def get_document(self): diff --git a/mayan/apps/ocr/tests/test_api.py b/mayan/apps/ocr/tests/test_api.py index e847550141..c6e9a89ced 100644 --- a/mayan/apps/ocr/tests/test_api.py +++ b/mayan/apps/ocr/tests/test_api.py @@ -21,7 +21,7 @@ class OCRAPITestCase(DocumentTestMixin, BaseAPITestCase): def test_submit_document_no_access(self): response = self._request_document_ocr_submit_view() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.assertFalse( hasattr(self.test_document.pages.first(), 'ocr_content') @@ -48,7 +48,7 @@ class OCRAPITestCase(DocumentTestMixin, BaseAPITestCase): def test_submit_document_version_no_access(self): response = self._request_document_version_ocr_submit_view() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.assertFalse( hasattr(self.test_document.pages.first(), 'ocr_content') @@ -76,7 +76,7 @@ class OCRAPITestCase(DocumentTestMixin, BaseAPITestCase): def test_get_document_version_page_content_no_access(self): response = self._request_document_page_content_view() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_get_document_version_page_content_with_access(self): self.test_document.submit_for_ocr() diff --git a/mayan/apps/permissions/api_views.py b/mayan/apps/permissions/api_views.py index fb23c78a00..6cc5a14029 100644 --- a/mayan/apps/permissions/api_views.py +++ b/mayan/apps/permissions/api_views.py @@ -1,9 +1,6 @@ from __future__ import unicode_literals -from rest_framework import generics - -from mayan.apps.rest_api.filters import MayanObjectPermissionsFilter -from mayan.apps.rest_api.permissions import MayanPermission +from mayan.apps.rest_api import generics from .classes import Permission from .models import Role @@ -29,10 +26,8 @@ class APIRoleListView(generics.ListCreateAPIView): get: Returns a list of all the roles. post: Create a new role. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = {'GET': (permission_role_view,)} mayan_view_permissions = {'POST': (permission_role_create,)} - permission_classes = (MayanPermission,) queryset = Role.objects.all() def get_serializer(self, *args, **kwargs): @@ -61,7 +56,6 @@ class APIRoleView(generics.RetrieveUpdateDestroyAPIView): 'PATCH': (permission_role_edit,), 'DELETE': (permission_role_delete,) } - permission_classes = (MayanPermission,) queryset = Role.objects.all() def get_serializer(self, *args, **kwargs): diff --git a/mayan/apps/permissions/tests/test_api.py b/mayan/apps/permissions/tests/test_api.py index 19e318d510..eb476de39a 100644 --- a/mayan/apps/permissions/tests/test_api.py +++ b/mayan/apps/permissions/tests/test_api.py @@ -93,7 +93,7 @@ class RoleAPIViewTestCase(GroupTestMixin, PermissionTestMixin, RoleAPIViewTestMi role_count = Role.objects.count() response = self._request_test_role_delete_api_view() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.assertEqual(Role.objects.count(), role_count) @@ -112,11 +112,10 @@ class RoleAPIViewTestCase(GroupTestMixin, PermissionTestMixin, RoleAPIViewTestMi def test_role_edit_via_patch_no_access(self): self._create_test_role() - response = self._request_test_role_edit_api_view(request_type='patch') - role_label = self.test_role.label - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + response = self._request_test_role_edit_api_view(request_type='patch') + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.test_role.refresh_from_db() self.assertEqual(self.test_role.label, role_label) @@ -140,7 +139,7 @@ class RoleAPIViewTestCase(GroupTestMixin, PermissionTestMixin, RoleAPIViewTestMi role_label = self.test_role.label - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.test_role.refresh_from_db() self.assertEqual(self.test_role.label, role_label) @@ -174,8 +173,7 @@ class RoleAPIViewTestCase(GroupTestMixin, PermissionTestMixin, RoleAPIViewTestMi role_label = self.test_role.label response = self._request_role_edit_api_patch_view_extra_data() - - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.test_role.refresh_from_db() self.assertEqual(self.test_role.label, role_label) @@ -224,8 +222,7 @@ class RoleAPIViewTestCase(GroupTestMixin, PermissionTestMixin, RoleAPIViewTestMi role_label = self.test_role.label response = self._request_role_edit_api_put_view_extra_data() - - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.test_role.refresh_from_db() self.assertEqual(self.test_role.label, role_label) diff --git a/mayan/apps/rest_api/generics.py b/mayan/apps/rest_api/generics.py new file mode 100644 index 0000000000..4528ccea14 --- /dev/null +++ b/mayan/apps/rest_api/generics.py @@ -0,0 +1,75 @@ +from __future__ import absolute_import, unicode_literals + +from rest_framework import generics + +from .filters import MayanObjectPermissionsFilter +from .permissions import MayanPermission + + +class GenericAPIView(generics.GenericAPIView): + filter_backends = (MayanObjectPermissionsFilter,) + permission_classes = (MayanPermission,) + + +class ListAPIView(generics.ListAPIView): + """ + requires: + object_permission = {'GET': ...} + """ + filter_backends = (MayanObjectPermissionsFilter,) + + +class ListCreateAPIView(generics.ListCreateAPIView): + """ + requires: + object_permission = {'GET': ...} + view_permission = {'POST': ...} + """ + filter_backends = (MayanObjectPermissionsFilter,) + permission_classes = (MayanPermission,) + + +class RetrieveAPIView(generics.RetrieveAPIView): + """ + requires: + object_permission = { + 'GET': ..., + } + """ + filter_backends = (MayanObjectPermissionsFilter,) + + +class RetrieveDestroyAPIView(generics.RetrieveDestroyAPIView): + """ + requires: + object_permission = { + 'DELETE': ..., + 'GET': ..., + } + """ + filter_backends = (MayanObjectPermissionsFilter,) + + +class RetrieveUpdateAPIView(generics.RetrieveUpdateAPIView): + """ + requires: + object_permission = { + 'GET': ..., + 'PATCH': ..., + 'PUT': ... + } + """ + filter_backends = (MayanObjectPermissionsFilter,) + + +class RetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView): + """ + requires: + object_permission = { + 'DELETE': ..., + 'GET': ..., + 'PATCH': ..., + 'PUT': ... + } + """ + filter_backends = (MayanObjectPermissionsFilter,) diff --git a/mayan/apps/sources/api_views.py b/mayan/apps/sources/api_views.py index f4f422ea39..5a9dcc7d9f 100644 --- a/mayan/apps/sources/api_views.py +++ b/mayan/apps/sources/api_views.py @@ -3,9 +3,10 @@ from __future__ import unicode_literals from django.http import HttpResponse from django.shortcuts import get_object_or_404 -from rest_framework import generics from rest_framework.response import Response +from mayan.apps.rest_api import generics + from .literals import STAGING_FILE_IMAGE_TASK_TIMEOUT from .models import StagingFolderSource from .serializers import StagingFolderFileSerializer, StagingFolderSerializer diff --git a/mayan/apps/tags/api_views.py b/mayan/apps/tags/api_views.py index 1421c8f815..071d5759b2 100644 --- a/mayan/apps/tags/api_views.py +++ b/mayan/apps/tags/api_views.py @@ -2,7 +2,6 @@ from __future__ import absolute_import, unicode_literals from django.shortcuts import get_object_or_404 -from rest_framework import generics from rest_framework.exceptions import ValidationError from rest_framework.response import Response @@ -10,8 +9,7 @@ from mayan.apps.acls.models import AccessControlList from mayan.apps.documents.models import Document from mayan.apps.documents.permissions import permission_document_view from mayan.apps.documents.serializers import DocumentSerializer -from mayan.apps.rest_api.filters import MayanObjectPermissionsFilter -from mayan.apps.rest_api.permissions import MayanPermission +from mayan.apps.rest_api import generics from .models import Tag from .permissions import ( @@ -29,10 +27,8 @@ class APITagListView(generics.ListCreateAPIView): get: Returns a list of all the tags. post: Create a new tag. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = {'GET': (permission_tag_view,)} mayan_view_permissions = {'POST': (permission_tag_create,)} - permission_classes = (MayanPermission,) queryset = Tag.objects.all() def get_serializer(self, *args, **kwargs): @@ -55,7 +51,6 @@ class APITagView(generics.RetrieveUpdateDestroyAPIView): patch: Edit the selected tag. put: Edit the selected tag. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = { 'DELETE': (permission_tag_delete,), 'GET': (permission_tag_view,), @@ -81,7 +76,6 @@ class APITagDocumentListView(generics.ListAPIView): """ get: Returns a list of all the documents tagged by a particular tag. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = {'GET': (permission_document_view,)} serializer_class = DocumentSerializer @@ -100,7 +94,6 @@ class APIDocumentTagListView(generics.ListCreateAPIView): get: Returns a list of all the tags attached to a document. post: Attach a tag to a document. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = { 'GET': (permission_tag_view,), 'POST': (permission_tag_attach,) @@ -156,7 +149,6 @@ class APIDocumentTagView(generics.RetrieveDestroyAPIView): delete: Remove a tag from the selected document. get: Returns the details of the selected document tag. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = { 'GET': (permission_tag_view,), 'DELETE': (permission_tag_remove,) diff --git a/mayan/apps/user_management/api_views.py b/mayan/apps/user_management/api_views.py index e8a2f91b70..a0eba16841 100644 --- a/mayan/apps/user_management/api_views.py +++ b/mayan/apps/user_management/api_views.py @@ -4,11 +4,8 @@ from django.contrib.auth import get_user_model from django.contrib.auth.models import Group from django.shortcuts import get_object_or_404 -from rest_framework import generics - from mayan.apps.acls.models import AccessControlList -from mayan.apps.rest_api.filters import MayanObjectPermissionsFilter -from mayan.apps.rest_api.permissions import MayanPermission +from mayan.apps.rest_api import generics from .permissions import ( permission_group_create, permission_group_delete, permission_group_edit, @@ -38,10 +35,8 @@ class APIGroupListView(generics.ListCreateAPIView): get: Returns a list of all the groups. post: Create a new group. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = {'GET': (permission_group_view,)} mayan_view_permissions = {'POST': (permission_group_create,)} - permission_classes = (MayanPermission,) queryset = Group.objects.order_by('id') serializer_class = GroupSerializer @@ -59,7 +54,6 @@ class APIGroupView(generics.RetrieveUpdateDestroyAPIView): 'PATCH': (permission_group_edit,), 'DELETE': (permission_group_delete,) } - permission_classes = (MayanPermission,) queryset = Group.objects.order_by('id') serializer_class = GroupSerializer @@ -69,10 +63,8 @@ class APIUserListView(generics.ListCreateAPIView): get: Returns a list of all the users. post: Create a new user. """ - filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = {'GET': (permission_user_view,)} mayan_view_permissions = {'POST': (permission_user_create,)} - permission_classes = (MayanPermission,) queryset = get_user_model().objects.all() serializer_class = UserSerializer @@ -90,7 +82,6 @@ class APIUserView(generics.RetrieveUpdateDestroyAPIView): 'PATCH': (permission_user_edit,), 'DELETE': (permission_user_delete,) } - permission_classes = (MayanPermission,) queryset = get_user_model().objects.all() serializer_class = UserSerializer @@ -100,12 +91,6 @@ class APIUserGroupList(generics.ListCreateAPIView): get: Returns a list of all the groups to which a user belongs. post: Add a user to a list of groups. """ - mayan_object_permissions = { - 'GET': (permission_user_view,), - 'POST': (permission_user_edit,) - } - permission_classes = (MayanPermission,) - def get_serializer(self, *args, **kwargs): if not self.request: return None diff --git a/mayan/apps/user_management/tests/mixins.py b/mayan/apps/user_management/tests/mixins.py index a37792fd55..7f1a6f22e9 100644 --- a/mayan/apps/user_management/tests/mixins.py +++ b/mayan/apps/user_management/tests/mixins.py @@ -12,7 +12,7 @@ from .literals import ( ) -class GroupAPITestMixin(object): +class GroupAPIViewTestMixin(object): def _request_test_group_create_api_view(self): result = self.post( viewname='rest_api:group-list', data={ @@ -91,7 +91,7 @@ class GroupViewTestMixin(object): ) -class UserAPITestMixin(object): +class UserAPIViewTestMixin(object): def _request_test_user_create_api_view(self): result = self.post( viewname='rest_api:user-list', data={ diff --git a/mayan/apps/user_management/tests/test_api.py b/mayan/apps/user_management/tests/test_api.py index 33e24cc0f0..e2ea0eaa31 100644 --- a/mayan/apps/user_management/tests/test_api.py +++ b/mayan/apps/user_management/tests/test_api.py @@ -14,10 +14,14 @@ from ..permissions import ( permission_user_edit, permission_user_view ) -from .mixins import GroupAPITestMixin, GroupTestMixin, UserAPITestMixin +from .mixins import ( + GroupAPIViewTestMixin, GroupTestMixin, UserAPIViewTestMixin +) -class GroupAPITestCase(GroupAPITestMixin, GroupTestMixin, BaseAPITestCase): +class GroupAPITestCase( + GroupAPIViewTestMixin, GroupTestMixin, BaseAPITestCase +): def test_group_create_no_permission(self): group_count = Group.objects.count() @@ -41,8 +45,7 @@ class GroupAPITestCase(GroupAPITestMixin, GroupTestMixin, BaseAPITestCase): group_count = Group.objects.count() response = self._request_test_group_delete_api_view() - - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.assertEqual(Group.objects.count(), group_count) @@ -64,7 +67,7 @@ class GroupAPITestCase(GroupAPITestMixin, GroupTestMixin, BaseAPITestCase): group_name = self.test_group.name response = self._request_test_group_edit_patch_api_view() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.test_group.refresh_from_db() self.assertEqual(self.test_group.name, group_name) @@ -90,7 +93,7 @@ class GroupAPITestCase(GroupAPITestMixin, GroupTestMixin, BaseAPITestCase): group_name = self.test_group.name response = self._request_test_group_edit_put_api_view() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.test_group.refresh_from_db() self.assertEqual(self.test_group.name, group_name) @@ -111,7 +114,7 @@ class GroupAPITestCase(GroupAPITestMixin, GroupTestMixin, BaseAPITestCase): self.assertNotEqual(self.test_group.name, group_name) -class UserAPITestCase(UserAPITestMixin, BaseAPITestCase): +class UserAPIViewTestCase(UserAPIViewTestMixin, BaseAPITestCase): def test_user_create_api_view_no_permission(self): user_count = get_user_model().objects.count() @@ -136,7 +139,7 @@ class UserAPITestCase(UserAPITestMixin, BaseAPITestCase): user_count = get_user_model().objects.count() response = self._request_test_user_delete_api_view() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.assertEqual(get_user_model().objects.count(), user_count) @@ -159,7 +162,7 @@ class UserAPITestCase(UserAPITestMixin, BaseAPITestCase): user_username = self.test_user.username response = self._request_test_user_edit_patch_api_view() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.test_user.refresh_from_db() self.assertEqual(self.test_user.username, user_username) @@ -167,7 +170,9 @@ class UserAPITestCase(UserAPITestMixin, BaseAPITestCase): def test_user_edit_patch_api_view_with_access(self): self._create_test_user() - self.grant_access(obj=self.test_user, permission=permission_user_edit) + self.grant_access( + obj=self.test_user, permission=permission_user_edit + ) user_username = self.test_user.username response = self._request_test_user_edit_patch_api_view() @@ -182,7 +187,7 @@ class UserAPITestCase(UserAPITestMixin, BaseAPITestCase): user_username = self.test_user.username response = self._request_test_user_edit_put_api_view() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.test_user.refresh_from_db() self.assertEqual(self.test_user.username, user_username) @@ -190,7 +195,9 @@ class UserAPITestCase(UserAPITestMixin, BaseAPITestCase): def test_user_edit_put_api_view_with_access(self): self._create_test_user() - self.grant_access(obj=self.test_user, permission=permission_user_edit) + self.grant_access( + obj=self.test_user, permission=permission_user_edit + ) user_username = self.test_user.username response = self._request_test_user_edit_put_api_view() @@ -199,8 +206,58 @@ class UserAPITestCase(UserAPITestMixin, BaseAPITestCase): self.test_user.refresh_from_db() self.assertNotEqual(self.test_user.username, user_username) + def test_user_login_api_view(self): + self._create_test_user() -class UserGroupAPITestCase(GroupTestMixin, UserAPITestMixin, BaseAPITestCase): + self.assertTrue( + self.login( + username=self.test_user.username, + password=self.test_user.cleartext_password + ) + ) + + def test_user_password_change_api_view_no_access(self): + self._create_test_user() + + response = self._request_test_user_password_change_api_view() + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + self.assertFalse( + self.login( + username=self.test_user.username, + password=self.test_user.cleartext_password + ) + ) + + def test_user_password_change_api_view_with_access(self): + self._create_test_user() + + self.grant_access( + obj=self.test_user, permission=permission_user_edit + ) + + response = self._request_test_user_password_change_api_view() + self.assertEqual(response.status_code, status.HTTP_200_OK) + + self.assertTrue( + self.login( + username=self.test_user.username, + password=self.test_user.cleartext_password + ) + ) + + +class UserGroupAPIViewTestMixin(object): + def _create_test_user_with_test_group(self): + self._create_test_group() + self._create_test_user() + self.test_user.groups.add(self.test_group) + + +class UserGroupAPIViewTestCase( + UserGroupAPIViewTestMixin, GroupTestMixin, UserAPIViewTestMixin, + BaseAPITestCase +): def test_user_create_with_group_api_view_no_permission(self): self._create_test_group() @@ -242,7 +299,9 @@ class UserGroupAPITestCase(GroupTestMixin, UserAPITestMixin, BaseAPITestCase): self._create_test_user() self._create_test_group() - self.grant_access(obj=self.test_user, permission=permission_user_edit) + self.grant_access( + obj=self.test_user, permission=permission_user_edit + ) user_group_count = self.test_user.groups.count() @@ -256,7 +315,9 @@ class UserGroupAPITestCase(GroupTestMixin, UserAPITestMixin, BaseAPITestCase): self._create_test_user() self._create_test_group() - self.grant_access(obj=self.test_group, permission=permission_group_view) + self.grant_access( + obj=self.test_group, permission=permission_group_view + ) user_group_count = self.test_user.groups.count() @@ -270,8 +331,12 @@ class UserGroupAPITestCase(GroupTestMixin, UserAPITestMixin, BaseAPITestCase): self._create_test_user() self._create_test_group() - self.grant_access(obj=self.test_user, permission=permission_user_edit) - self.grant_access(obj=self.test_group, permission=permission_group_view) + self.grant_access( + obj=self.test_user, permission=permission_user_edit + ) + self.grant_access( + obj=self.test_group, permission=permission_group_view + ) user_group_count = self.test_user.groups.count() @@ -281,11 +346,6 @@ class UserGroupAPITestCase(GroupTestMixin, UserAPITestMixin, BaseAPITestCase): self.test_user.refresh_from_db() self.assertEqual(self.test_user.groups.count(), user_group_count + 1) - def _create_test_user_with_test_group(self): - self._create_test_group() - self._create_test_user() - self.test_user.groups.add(self.test_group) - def test_user_group_list_no_access(self): self._create_test_user_with_test_group() @@ -295,7 +355,9 @@ class UserGroupAPITestCase(GroupTestMixin, UserAPITestMixin, BaseAPITestCase): def test_user_group_list_with_user_access(self): self._create_test_user_with_test_group() - self.grant_access(obj=self.test_user, permission=permission_user_view) + self.grant_access( + obj=self.test_user, permission=permission_user_view + ) response = self._request_test_user_group_list_api_view() self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['count'], 0) @@ -303,53 +365,21 @@ class UserGroupAPITestCase(GroupTestMixin, UserAPITestMixin, BaseAPITestCase): def test_user_group_list_with_group_access(self): self._create_test_user_with_test_group() - self.grant_access(obj=self.test_group, permission=permission_group_view) + self.grant_access( + obj=self.test_group, permission=permission_group_view + ) response = self._request_test_user_group_list_api_view() self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_user_group_list_with_full_access(self): self._create_test_user_with_test_group() - self.grant_access(obj=self.test_user, permission=permission_user_view) - self.grant_access(obj=self.test_group, permission=permission_group_view) + self.grant_access( + obj=self.test_user, permission=permission_user_view + ) + self.grant_access( + obj=self.test_group, permission=permission_group_view + ) response = self._request_test_user_group_list_api_view() self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['count'], 1) - - def test_user_login_api_view(self): - self._create_test_user() - - self.assertTrue( - self.login( - username=self.test_user.username, - password=self.test_user.cleartext_password - ) - ) - - def test_user_create_login_password_change_api_view_no_access(self): - self._create_test_user() - - response = self._request_test_user_password_change_api_view() - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - - self.assertFalse( - self.login( - username=self.test_user.username, - password=self.test_user.cleartext_password - ) - ) - - def test_user_create_login_password_change_api_view_with_access(self): - self._create_test_user() - - self.grant_access(obj=self.test_user, permission=permission_user_edit) - - response = self._request_test_user_password_change_api_view() - self.assertEqual(response.status_code, status.HTTP_200_OK) - - self.assertTrue( - self.login( - username=self.test_user.username, - password=self.test_user.cleartext_password - ) - )