From 61ebda6e63e4da83f5cb7c033711c1980024bff0 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 7 Feb 2019 20:13:35 -0400 Subject: [PATCH] REST API app updates - Add back support for API views but using the api_urlpatterns list. Needed for the current user API until a dynamic route router is implemented that can allow a viewset action to specify its entire URL. - Make sure the user is authenticated before trying to the user permissions. - Improve how external_object_list options are read from the class. - None authenticated users will get a blank queryset if the view doesn't require a permission. Signed-off-by: Roberto Rosario --- mayan/apps/rest_api/apps.py | 17 ++++++++-- mayan/apps/rest_api/filters.py | 3 ++ mayan/apps/rest_api/mixins.py | 52 +++++++++++++++++++----------- mayan/apps/rest_api/permissions.py | 5 ++- 4 files changed, 56 insertions(+), 21 deletions(-) diff --git a/mayan/apps/rest_api/apps.py b/mayan/apps/rest_api/apps.py index d913ccd02c..9cebabfb52 100644 --- a/mayan/apps/rest_api/apps.py +++ b/mayan/apps/rest_api/apps.py @@ -36,9 +36,22 @@ class RESTAPIApp(MayanAppConfig): for app in apps.get_app_configs(): if getattr(app, 'has_rest_api', False): try: - for entry in import_string('{}.urls.api_router_entries'.format(app.name)): - router.register(**entry) + app_api_router_entries = import_string( + dotted_path='{}.urls.api_router_entries'.format(app.name) + ) except ImportError: pass + else: + for entry in app_api_router_entries: + router.register(**entry) + + try: + app_api_urlpatterns = import_string( + dotted_path='{}.urls.api_urlpatterns'.format(app.name) + ) + except ImportError: + pass + else: + urlpatterns.extend(app_api_urlpatterns) urlpatterns.extend(router.urls) diff --git a/mayan/apps/rest_api/filters.py b/mayan/apps/rest_api/filters.py index 928c997bc8..0c1e521188 100644 --- a/mayan/apps/rest_api/filters.py +++ b/mayan/apps/rest_api/filters.py @@ -17,6 +17,9 @@ class MayanViewSetObjectPermissionsFilter(BaseFilterBackend): 'list': permission_..._view } """ + if not request.user or not request.user.is_authenticated: + return queryset.none() + object_permission_dictionary = getattr(view, 'object_permission_map', {}) object_permission = object_permission_dictionary.get( view.action, None diff --git a/mayan/apps/rest_api/mixins.py b/mayan/apps/rest_api/mixins.py index efacb23ac1..3a08e520c6 100644 --- a/mayan/apps/rest_api/mixins.py +++ b/mayan/apps/rest_api/mixins.py @@ -6,12 +6,21 @@ from mayan.apps.acls.models import AccessControlList class ExternalObjectListSerializerMixin(object): - class Meta: - external_object_list_model = None - external_object_list_permission = None - external_object_list_queryset = None - external_object_list_pk_field = None - external_object_list_pk_list_field = None + """ + Mixin to allow serializers to get a restricted object list with minimal code. + This mixin adds the follow class Meta options to a serializer: + external_object_list_model + external_object_list_permission + external_object_list_queryset + external_object_list_pk_field + external_object_list_pk_list_field + + The source queryset can also be provided overriding the + .get_external_object_list() method. + """ + def __init__(self, *args, **kwargs): + super(ExternalObjectListSerializerMixin, self).__init__(*args, **kwargs) + self.external_object_list_options = getattr(self, 'Meta', None) def get_external_object_list(self): queryset = self.get_external_object_list_queryset() @@ -23,14 +32,13 @@ class ExternalObjectListSerializerMixin(object): user=self.context['request'].user ) - if self.Meta.external_object_list_pk_field: - id_list = ( - self.validated_data.get(self.Meta.external_object_list_pk_field), - ) - elif self.Meta.external_object_list_pk_list_field: - id_list = self.validated_data.get( - self.Meta.external_object_list_pk_list_field, '' - ).split(',') + pk_field = self.get_external_object_list_option('pk_field') + pk_list_field = self.get_external_object_list_option('pk_list_field') + + if pk_field: + id_list = (self.validated_data.get(pk_field),) + elif pk_list_field: + id_list = self.validated_data.get(pk_list_field, '').split(',') else: raise ImproperlyConfigured( 'ExternalObjectListSerializerMixin requires a ' @@ -40,11 +48,19 @@ class ExternalObjectListSerializerMixin(object): return queryset.filter(pk__in=id_list) + def get_external_object_list_option(self, option_name): + return getattr( + self.external_object_list_options, 'external_object_list_{}'.format(option_name), None + ) + def get_external_object_list_queryset(self): - if self.Meta.external_object_list_model: - queryset = self.Meta.external_object_list_model._meta.default_manager.all() - elif self.Meta.external_object_list_queryset: - return self.Meta.external_object_list_queryset + model = self.get_external_object_list_option('model') + queryset = self.get_external_object_list_option('queryset') + + if model: + queryset = model._meta.default_manager.all() + elif queryset: + return queryset else: raise ImproperlyConfigured( 'ExternalObjectListSerializerMixin requires a ' diff --git a/mayan/apps/rest_api/permissions.py b/mayan/apps/rest_api/permissions.py index 830c4e5a07..faaf8ebc94 100644 --- a/mayan/apps/rest_api/permissions.py +++ b/mayan/apps/rest_api/permissions.py @@ -2,7 +2,7 @@ from __future__ import absolute_import, unicode_literals from django.core.exceptions import PermissionDenied -from rest_framework.permissions import BasePermission +from rest_framework.permissions import BasePermission, IsAuthenticated from mayan.apps.permissions import Permission @@ -19,6 +19,9 @@ class MayanViewSetPermission(BasePermission): 'list': permission_..._view } """ + if not request.user or not request.user.is_authenticated: + return False + view_permission_dictionary = getattr(view, 'view_permission_map', {}) view_permission = view_permission_dictionary.get(view.action, None)