Exemple #1
0
    def metadata(self, request):
        """
        Return a dictionary of metadata about the view.
        Used to return responses for OPTIONS requests.

        We override the default behavior, and add some extra information
        about the required request body for POST and PUT operations.
        """
        ret = {}

        actions = {}
        for method in ('PUT', 'POST'):
            if method not in self.allowed_methods:
                continue

            cloned_request = clone_request(request, method)
            try:
                # Test global permissions
                self.check_permissions(cloned_request)
                # Test object permissions
                if method == 'PUT':
                    self.get_object()
            except (exceptions.APIException, PermissionDenied, Http404,
                    MultipleObjectsReturned):
                pass
            else:
                # If user has appropriate permissions for the view, include
                # appropriate metadata about the fields that should be supplied.
                serializer = self.get_serializer()
                actions[method] = serializer.metadata()

        if 'DELETE' in self.allowed_methods:
            cloned_request = clone_request(request, 'DELETE')
            try:
                # Test global permissions
                self.check_permissions(cloned_request)
                self.get_object()
            except (exceptions.APIException, PermissionDenied, Http404,
                    MultipleObjectsReturned):
                pass
            else:
                actions['DELETE'] = None

        if actions:
            if not 'actions' in ret:
                ret['actions'] = {}
            ret['actions'].update(actions)

        return super(GenericAPIView, self).metadata(request, defaults=ret)
    def create_view(self, callback, method, request=None):
        """
        Given a callback, return an actual view instance.
        """
        view = callback.cls(**getattr(callback, "initkwargs", {}))
        view.args = ()
        view.kwargs = {}
        view.format_kwarg = None
        view.request = None
        view.action_map = getattr(callback, "actions", None)

        actions = getattr(callback, "actions", None)
        if actions is not None:
            if method == "OPTIONS":
                view.action = "metadata"
            else:
                view.action = actions.get(method.lower())

        if request is not None:
            view.request = clone_request(request, method)
        is_allowed = True
        if not request.user.is_superuser:
            is_allowed = self._user_has_perm(request.user, view, method)
        if is_allowed:
            return view
Exemple #3
0
    def determine_actions(self, request, view):
        # Add field information for GET requests (so field names/labels are
        # available even when we can't POST/PUT).
        actions = {}
        for method in {'GET', 'PUT', 'POST'} & set(view.allowed_methods):
            view.request = clone_request(request, method)
            obj = None
            try:
                # Test global permissions
                if hasattr(view, 'check_permissions'):
                    view.check_permissions(view.request)
                # Test object permissions
                if method == 'PUT' and hasattr(view, 'get_object'):
                    obj = view.get_object()
            except (exceptions.APIException, PermissionDenied, Http404):
                continue
            else:
                # If user has appropriate permissions for the view, include
                # appropriate metadata about the fields that should be supplied.
                serializer = view.get_serializer(instance=obj)
                actions[method] = self.get_serializer_info(serializer,
                                                           method=method)
            finally:
                view.request = request

            for field, meta in list(actions[method].items()):
                if not isinstance(meta, dict):
                    continue

                if field == "pod_spec_override":
                    meta['default'] = AWXReceptorJob().pod_definition

                # Add type choices if available from the serializer.
                if field == 'type' and hasattr(serializer, 'get_type_choices'):
                    meta['choices'] = serializer.get_type_choices()

                # For GET method, remove meta attributes that aren't relevant
                # when reading a field and remove write-only fields.
                if method == 'GET':
                    attrs_to_remove = ('required', 'read_only', 'default',
                                       'min_length', 'max_length',
                                       'placeholder')
                    for attr in attrs_to_remove:
                        meta.pop(attr, None)
                        meta.get('child', {}).pop(attr, None)
                    if meta.pop('write_only', False):
                        actions['GET'].pop(field)

                # For PUT/POST methods, remove read-only fields.
                if method in ('PUT', 'POST'):
                    # This value should always be False for PUT/POST, so don't
                    # show it (file-based read-only settings can't be updated)
                    meta.pop('defined_in_file', False)

                    if meta.pop('read_only', False):
                        if field == 'id' and hasattr(view, 'attach'):
                            continue
                        actions[method].pop(field)

        return actions
    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        self.object = None
        try:
            self.object = self.get_object()
        except Http404:
            # If this is a PUT-as-create operation, we need to ensure that
            # we have relevant permissions, as if this was a POST request.
            if not self.has_permission(clone_request(request, 'POST')):
                self.permission_denied(self.request)
            created = True
            success_status_code = status.HTTP_201_CREATED
        else:
            created = False
            success_status_code = status.HTTP_200_OK

        serializer = self.get_serializer(self.object, data=request.DATA,
                                         files=request.FILES, partial=partial)

        if serializer.is_valid():
            self.pre_save(serializer.object)
            self.object = serializer.save()
            self.post_save(self.object, created=created)
            return Response(serializer.data, status=success_status_code)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Exemple #5
0
def call_xblock_json_handler(request,
                             usage_id,
                             handler_name,
                             data,
                             auth=False):
    """
    WARN: Tested only for use in ESG. Consult before use outside of ESG.

    Create an internally-routed XBlock.json_handler request. The internal auth code/param unpacking requires a POST
    request with payload in the body. Ideally, we would be able to call functions on XBlocks without this sort of
    hacky request proxying but this is what we have to work with right now.

    params:
        request (HttpRequest): Originating web request, we're going to borrow auth headers/cookies from this
        usage_id (str): Usage ID of the XBlock for running the handler
        handler_name (str): the name of the XBlock handler method
        data (dict): Data to be encoded and sent as the body of the POST request
    returns:
        response (HttpResponse): get response data with json.loads(response.content)
    """
    # XBlock.json_handler operates through a POST request
    proxy_request = clone_request(request, "POST")
    proxy_request.META["REQUEST_METHOD"] = "POST"

    # The body is an encoded JSON blob
    proxy_request.body = json.dumps(data).encode()

    # Course ID can be retrieved from the usage_id
    usage_key = UsageKey.from_string(usage_id)
    course_id = str(usage_key.course_key)

    # Send the request and return the HTTP response from the XBlock
    return handle_xblock_callback_noauth(proxy_request, course_id, usage_id,
                                         handler_name)
Exemple #6
0
    def determine_actions(self, request, view):
        """
        Replace the stock determine_actions() method to assess object permissions only
        when viewing a specific object. This is necessary to support OPTIONS requests
        with bulk update in place (see #5470).
        """
        actions = {}
        for method in {"PUT", "POST"} & set(view.allowed_methods):
            view.request = clone_request(request, method)
            try:
                # Test global permissions
                if hasattr(view, "check_permissions"):
                    view.check_permissions(view.request)
                # Test object permissions (if viewing a specific object)
                if method == "PUT" and view.lookup_url_kwarg and hasattr(
                        view, "get_object"):
                    view.get_object()
            except (exceptions.APIException, PermissionDenied, Http404):
                pass
            else:
                # If user has appropriate permissions for the view, include
                # appropriate metadata about the fields that should be supplied.
                serializer = view.get_serializer()
                actions[method] = self.get_serializer_info(serializer)
            finally:
                view.request = request

        return actions
    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        self.object = None
        try:
            self.object = self.get_object()
        except Http404:
            # If this is a PUT-as-create operation, we need to ensure that
            # we have relevant permissions, as if this was a POST request.
            self.check_permissions(clone_request(request, 'POST'))
            created = True
            save_kwargs = {'force_insert': True}
            success_status_code = status.HTTP_201_CREATED
        else:
            created = False
            save_kwargs = {'force_update': True}
            success_status_code = status.HTTP_200_OK

        serializer = self.get_serializer(self.object, data=request.DATA,
                                         files=request.FILES, partial=partial)

        if serializer.is_valid():
            self.pre_save(serializer.object)
            self.object = serializer.save(**save_kwargs)
            self.post_save(self.object, created=created)
            return Response({
                    'success': True,
                    'data': serializer.data,
                    'message': "",
                }, status=success_status_code)

        return Response({
                'success': False,
                'data': {},
                'message': repr(serializer.errors),
            }, status=status.HTTP_400_BAD_REQUEST)
    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        self.object = None
        try:
            self.object = self.get_object()
        except Http404:
            # If this is a PUT-as-create operation, we need to ensure that
            # we have relevant permissions, as if this was a POST request.
            self.check_permissions(clone_request(request, 'POST'))
            created = True
            save_kwargs = {'force_insert': True}
            success_status_code = status.HTTP_201_CREATED
        else:
            created = False
            save_kwargs = {'force_update': True}
            success_status_code = status.HTTP_200_OK

        serializer = self.get_serializer(self.object,
                                         data=request.DATA,
                                         files=request.FILES,
                                         partial=partial)

        if serializer.is_valid():
            self.pre_save(serializer.object)
            self.object = serializer.save(**save_kwargs)
            self.post_save(self.object, created=created)
            return Response(serializer.data, status=success_status_code)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Exemple #9
0
    def determine_actions(self, request, view):
        """Allow all allowed methods"""
        from rest_framework.generics import GenericAPIView
        actions = {}
        excluded_methods = {'HEAD', 'OPTIONS', 'PATCH', 'DELETE'}
        for method in set(view.allowed_methods) - excluded_methods:
            view.request = clone_request(request, method)
            try:
                if isinstance(view, GenericAPIView):
                    has_object = view.lookup_url_kwarg or view.lookup_field in view.kwargs
                elif method in {'PUT', 'POST'}:
                    has_object = method in {'PUT'}
                else:
                    continue
                # Test global permissions
                if hasattr(view, 'check_permissions'):
                    view.check_permissions(view.request)
                # Test object permissions
                if has_object and hasattr(view, 'get_object'):
                    view.get_object()
            except (exceptions.APIException, PermissionDenied, Http404):
                pass
            else:
                # If user has appropriate permissions for the view, include
                # appropriate metadata about the fields that should be supplied.
                serializer = view.get_serializer()
                actions[method] = self.get_serializer_info(serializer)
            finally:
                view.request = request

        return actions
Exemple #10
0
    def get_actions(self, request, view):
        """
        For generic class based views we return information about
        the fields that are accepted for 'PUT' and 'POST' methods.
        """
        actions = {}
        print
        for method in {'PUT', 'POST'} & set(view.allowed_methods):
            view.request = clone_request(request, method)
            try:
                # Test global permissions
                if hasattr(view, 'check_permissions'):
                    view.check_permissions(view.request)
                # Test object permissions
                if method == 'PUT' and hasattr(view, 'get_object'):
                    view.get_object()
            except (exceptions.APIException, PermissionDenied, Http404):
                pass
            else:
                # If user has appropriate permissions for the view, include
                # appropriate metadata about the fields that should be supplied.
                serializer = view.get_serializer()
                actions[method] = self.get_serializer_info2(serializer)
            finally:
                view.request = request

        return actions
 def create(self, request, *args, **kwargs):
     project = get_object_or_404(Project, id=self.kwargs.get('project_id', None))
     if hasattr(project, 'view_invite'):
         #when view invite already exists then return the existing view invite:
         return self.retrieve(clone_request(request, 'GET'), *args, **kwargs)
     self.check_object_permissions(self.request, project)
     return super(ViewInviteDetail, self).create(request, *args, **kwargs)
Exemple #12
0
    def _get_actions(self, request, view):
        """Return a JSON Schema for GET, PATCH, PUT, and POST methods."""
        if not hasattr(view, 'get_serializer'):
            return None

        actions = OrderedDict()
        for method in ('GET', 'POST', 'PUT', 'PATCH'):
            if method in view.allowed_methods:
                view.request = clone_request(request, method)
                try:
                    # Test global permissions
                    if hasattr(view, 'check_permissions'):
                        view.check_permissions(view.request)
                    # Test object permissions
                    if method == 'PATCH' and hasattr(view, 'get_object'):
                        view.get_object()
                    if method == 'PUT' and hasattr(view, 'get_object'):
                        view.get_object()
                except (exceptions.APIException, PermissionDenied, Http404):
                    pass
                else:
                    # If user has appropriate permissions for the view, include
                    # appropriate metadata about the fields that should be
                    # supplied.
                    serializer = view.get_serializer()
                    actions[method] = self._get_serializer_fields(serializer)
                finally:
                    view.request = request

        return actions
    def get_schema(self, request=None):
        if request is None:
            endpoints = self.endpoints
        else:
            # Filter the list of endpoints to only include those that
            # the user has permission on.
            endpoints = []
            for key, link, callback in self.endpoints:
                method = link.action.upper()
                view = callback.cls()
                view.request = clone_request(request, method)
                view.format_kwarg = None
                try:
                    view.check_permissions(view.request)
                except exceptions.APIException:
                    pass
                else:
                    endpoints.append((key, link, callback))

        if not endpoints:
            return None

        # Generate the schema content structure, from the endpoints.
        # ('users', 'list'), Link -> {'users': {'list': Link()}}
        content = {}
        for key, link, callback in endpoints:
            insert_into(content, key, link)

        # Return the schema document.
        return coreapi.Document(title=self.title,
                                content=content,
                                url=self.url)
Exemple #14
0
    def get_actions(self, request, view):
        """
        Return metadata for resource-specific actions,
        such as start, stop, unlink
        """
        metadata = OrderedDict()
        actions = self.get_resource_actions(view)

        resource = view.get_object()
        for action_name, action in actions.items():
            if action_name == 'update':
                view.request = clone_request(request, 'PUT')
            else:
                view.action = action_name

            data = ActionSerializer(action, action_name, request, view, resource)
            metadata[action_name] = data.serialize()
            if not metadata[action_name]['enabled']:
                continue
            fields = self.get_action_fields(view, action_name, resource)
            if not fields:
                metadata[action_name]['type'] = 'button'
            else:
                metadata[action_name]['type'] = 'form'
                metadata[action_name]['fields'] = fields

            view.action = None
            view.request = request

        return metadata
    def get_schema(self, request=None):
        if request is None:
            endpoints = self.endpoints
        else:
            # Filter the list of endpoints to only include those that
            # the user has permission on.
            endpoints = []
            for key, link, callback in self.endpoints:
                method = link.action.upper()
                view = callback.cls()
                view.request = clone_request(request, method)
                view.format_kwarg = None
                try:
                    view.check_permissions(view.request)
                except exceptions.APIException:
                    pass
                else:
                    endpoints.append((key, link, callback))

        if not endpoints:
            return None

        # Generate the schema content structure, from the endpoints.
        # ('users', 'list'), Link -> {'users': {'list': Link()}}
        content = {}
        for key, link, callback in endpoints:
            insert_into(content, key, link)

        # Return the schema document.
        return coreapi.Document(title=self.title, content=content, url=self.url)
Exemple #16
0
 def determine_actions(self, request, view):
     """
     For generic class based views we return information about
     the fields that are accepted for 'PUT' and 'POST' methods.
     """
     actions = {}
     for method in self.methods & set(view.allowed_methods):
         view.request = clone_request(request, method)
         try:
             # Test global permissions
             if hasattr(view, 'check_permissions'):
                 view.check_permissions(view.request)
             # Test object permissions
             if method == 'PUT' and hasattr(view, 'get_object'):
                 view.get_object()
         except (exceptions.APIException, PermissionDenied, Http404):
             pass
         else:
             # If user has appropriate permissions for the view, include
             # appropriate metadata about the fields that should be supplied.
             serializer = view.get_serializer()
             actions[method] = self.get_serializer_info(serializer)
         finally:
             view.request = request
     return actions
Exemple #17
0
    def update(self, request, *args, **kwargs):
        partial = kwargs.pop("partial", False)
        extra_kwargs = {}
        try:
            instance = self.get_object()
        except Http404:
            # this is derived from https://gist.github.com/tomchristie/a2ace4577eff2c603b1b
            # and supports PUT as create.
            if self.request.method == "PUT":
                # For PUT-as-create operation, we need to ensure that we have
                # relevant permissions, as if this was a POST request.  This
                # will either raise a PermissionDenied exception, or simply
                # return None.
                self.check_permissions(clone_request(self.request, "POST"))
                instance = None
                extra_kwargs.update({"id": kwargs["user_id"], "external_id": kwargs["user_id"]})
            else:
                # PATCH requests where the object does not exist should still
                # return a 404 response.
                raise

        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        serializer.save(**extra_kwargs)
        return Response(serializer.data)
Exemple #18
0
    def determine_actions(self, request, view):
        """
        For generic class based views we return information about
        the fields that are accepted for 'PUT' and 'POST' methods.

        NOTE: This method is based directly on `SimpleMetadata.determine_actions`
        and would need to change if it ever changed.
        """
        actions = {}
        meta_action = view.action
        for method in {"PUT", "POST"} & set(view.allowed_methods):
            view.action = view.action_map.get(method.lower())
            view.request = clone_request(request, method=method)
            try:
                # Test global permissions
                if hasattr(view, "check_permissions"):
                    view.check_permissions(view.request)
                # Test object permissions
                if method == "PUT" and hasattr(view, "get_object"):
                    view.get_object()
            except (exceptions.APIException, PermissionDenied, Http404):
                pass
            else:
                # If user has appropriate permissions for the view, include
                # appropriate metadata about the fields that should be supplied.
                serializer = view.get_serializer()
                actions[method] = self.get_serializer_info(serializer)
            finally:
                view.request = request
                view.action = meta_action
        return actions
    def get_form(self, view, method, request):
        """
        Get a form, possibly bound to either the input or output data.
        In the absence on of the Resource having an associated form then
        provide a form that can be used to submit arbitrary content.
        """
        obj = getattr(view, 'object', None)
        cloned_request = clone_request(request, method)

        if not self.show_form_for_method(view, method, cloned_request, obj):
            return

        if method in ('DELETE', 'OPTIONS'):
            return True  # Don't actually need to return a form

        if not getattr(view, 'get_serializer', None) or not parsers.FormParser in view.parser_classes:
            return

        serializer = view.get_serializer(instance=obj, request=cloned_request)
        fields = self.serializer_to_form_fields(serializer)

        # Creating an on the fly form see:
        # http://stackoverflow.com/questions/3915024/dynamically-creating-classes-python
        OnTheFlyForm = type(str("OnTheFlyForm"), (forms.Form,), fields)
        data = (obj is not None) and serializer.data or None
        form_instance = OnTheFlyForm(data)
        return form_instance
    def metadata(self, request):
        """
        Return a dictionary of metadata about the view.
        Used to return responses for OPTIONS requests.

        We override the default behavior, and add some extra information
        about the required request body for POST and PUT operations.
        """
        ret = super(GenericAPIView, self).metadata(request)

        actions = {}
        for method in ('PUT', 'POST'):
            if method not in self.allowed_methods:
                continue

            cloned_request = clone_request(request, method)
            try:
                # Test global permissions
                self.check_permissions(cloned_request)
                # Test object permissions
                if method == 'PUT':
                    self.get_object()
            except (exceptions.APIException, PermissionDenied, Http404):
                pass
            else:
                # If user has appropriate permissions for the view, include
                # appropriate metadata about the fields that should be supplied.
                serializer = self.get_serializer()
                actions[method] = serializer.metadata()

        if actions:
            ret['actions'] = actions

        return ret
Exemple #21
0
 def retrieve_resource_or_none(self):
     try:
         return self.retrieve_resource()
     except Http404:
         if self.request.method == 'PUT':
             self.check_permissions(clone_request(self.request, 'POST'))
         else:
             raise
Exemple #22
0
 def get_object_or_none(self):
     try:
         return self.get_object()
     except Http404:
         if self.request.method == 'PUT':
             self.check_permissions(clone_request(self.request, 'POST'))
         else:
             raise
 def get_object_or_none(self):
     try:
         return self.get_object()
     except Http404:
         # If this is a PUT-as-create operation, we need to ensure that
         # we have relevant permissions, as if this was a POST request.
         # This will either raise a PermissionDenied exception,
         # or simply return None
         self.check_permissions(clone_request(self.request, "POST"))
 def get_object_or_none(self):
     try:
         return self.get_object()
     except Http404:
         # If this is a PUT-as-create operation, we need to ensure that
         # we have relevant permissions, as if this was a POST request.
         # This will either raise a PermissionDenied exception,
         # or simply return None
         self.check_permissions(clone_request(self.request, 'POST'))
 def get_object_or_none(self):
     try:
         return self.get_object()
     except Http404:
         # if self.request.method == 'PUT':
             # For PUT-as-create operation, we need to ensure that we have
             # relevant permissions, as if this was a POST request.  This
             # will either raise a PermissionDenied exception, or simply
             # return None.
         self.check_permissions(clone_request(self.request, 'POST'))
Exemple #26
0
    def get_context(self, request):
        request = clone_request(request, request.method)

        if "current_page" in request.GET:
            # Runs through regex in order to clean up potential double quoted strings.
            request.path = request.path_info = re.sub(r'^"|"$', '', request.GET["current_page"])

        self.process_request(request)
        self.context["request"] = request
        return self.context
    def metadata(self, request):
        """
        Return a dictionary of metadata about the view.
        Used to return responses for OPTIONS requests.

        We override the default behavior, and add some extra information
        about the required request body for POST and PUT operations.
        """
        ret = super(GenericAPIView, self).metadata(request)

        actions = {}
        for method in ('PUT', 'POST'):
            if method not in self.allowed_methods:
                continue

            original_request = clone_request(request, request.method)
            self.request = clone_request(request, method)
            try:
                # Test global permissions
                self.check_permissions(self.request)
                # Test object permissions
                if method == 'PUT':
                    try:
                        self.get_object()
                    except Http404:
                        # Http404 should be acceptable and the serializer
                        # metadata should be populated. Except this so the
                        # outer "else" clause of the try-except-else block
                        # will be executed.
                        pass
            except (exceptions.APIException, PermissionDenied):
                pass
            else:
                # If user has appropriate permissions for the view, include
                # appropriate metadata about the fields that should be supplied.
                serializer = self.get_serializer()
                actions[method] = serializer.metadata()
                self.request = original_request

        if actions:
            ret['actions'] = actions

        return ret
Exemple #28
0
    def create(self, request, *args, **kwargs):
        bulk = isinstance(request.data, list)

        #if not bulk, use regular create:
        if not bulk:
            return super(BulkUpdateWithCreateMixin, self).create(request, *args, **kwargs)

        #if bulk, use bulk create as bulk update:
        else:
            self.request = clone_request(request, 'PUT')
            return self.bulk_update(self.request, *args, **kwargs)
Exemple #29
0
 def _get_raw_data_form(self, view, method, request, media_types):
     # We need to impersonate a request with the correct method,
     # so that eg. any dynamic get_serializer_class methods return the
     # correct form for each method.
     restore = view.request
     request = clone_request(request, method)
     view.request = request
     try:
         return self.get_raw_data_form(view, method, request, media_types)
     finally:
         view.request = restore
Exemple #30
0
    def get_context(self, request):
        request = clone_request(request, request.method)

        if "current_page" in request.GET:
            # Runs through regex in order to clean up potential double quoted strings.
            request.path = request.path_info = re.sub(
                r'^"|"$', '', request.GET["current_page"])

        self.process_request(request)
        self.context["request"] = request
        return self.context
 def _get_raw_data_form(self, view, method, request, media_types):
     # We need to impersonate a request with the correct method,
     # so that eg. any dynamic get_serializer_class methods return the
     # correct form for each method.
     restore = view.request
     request = clone_request(request, method)
     view.request = request
     try:
         return self.get_raw_data_form(view, method, request, media_types)
     finally:
         view.request = restore
 def _get_view_queryset(self, view_class, user_field_qs, with_embed_list=None):
     #get the queryset from the view:
     view_instance = view_class(lookup_url_kwarg='user_pk')
     view_instance.args = self.args
     view_instance.kwargs = self.kwargs
     view_instance.request = clone_request(self.request, self.request.method)
     view_instance.queryset = user_field_qs
     view_instance.initial(view_instance.request, self.args, self.kwargs)
     if with_embed_list:
         view_instance.embed_list += with_embed_list
     return view_instance.filter_queryset(view_instance.get_queryset())
Exemple #33
0
 def determine_actions(self, request, view):
     """
     For generic class based views we return information about
     the fields that are accepted for 'PUT' and 'POST' methods.
     """
     actions = {}
     for method in {'PUT', 'POST'} & set(view.allowed_methods):
         view.request = clone_request(request, method)
         serializer = view.get_serializer()
         actions[method] = self.get_serializer_info(serializer)
         view.request = request
     return actions
Exemple #34
0
    def determine_actions(self, request, view):
        """
        For generic class based views we return information about
        the fields that are accepted for 'PUT' and 'POST' methods.
        """
        actions = {}
        for method in set(['PUT', 'POST']) & set(view.allowed_methods):
            view.request = clone_request(request, method)
            serializer = view.get_serializer()
            actions[method] = self.get_serializer_info(serializer)
            view.request = request

        return actions
Exemple #35
0
 def get_object_or_none(self):
     try:
         return self.get_object()
     except Http404:
         if self.request.method == 'PUT':
             # For PUT-as-create operation, we need to ensure that we have
             # relevant permissions, as if this was a POST request.  This
             # will either raise a PermissionDenied exception, or simply
             # return None.
             self.check_permissions(clone_request(self.request, 'POST'))
         else:
             # PATCH requests where the object does not exist should still
             # return a 404 response.
             raise
Exemple #36
0
 def get_object_or_none(self):
     try:
         return self.get_object()
     except Http404:
         if self.request.method == 'PUT':
             # For PUT-as-create operation, we need to ensure that we have
             # relevant permissions, as if this was a POST request.  This
             # will either raise a PermissionDenied exception, or simply
             # return None.
             self.check_permissions(clone_request(self.request, 'POST'))
         else:
             # PATCH requests where the object does not exist should still
             # return a 404 response.
             raise
Exemple #37
0
    def check_team_permissions(self, request, teamid, orgid=None):
        if orgid is not None:
            team = get_object_or_404(
                SeedTeam, pk=teamid, organization_id=orgid)
        else:
            team = get_object_or_404(SeedTeam, pk=teamid)

        permission = permissions.TeamPermission()
        fake_request = clone_request(request, 'PUT')
        if not permission.has_object_permission(fake_request, self, team):
            self.permission_denied(
                request, message=getattr(permission, 'message', None)
            )
        return team
Exemple #38
0
    def get_schema(self, request=None):
        if self.endpoints is None:
            self.endpoints = self.get_api_endpoints(self.patterns)

        links = []
        for path, method, category, action, callback in self.endpoints:
            view = callback.cls()
            for attr, val in getattr(callback, 'initkwargs', {}).items():
                setattr(view, attr, val)
            view.args = ()
            view.kwargs = {}
            view.format_kwarg = None

            actions = getattr(callback, 'actions', None)
            if actions is not None:
                if method == 'OPTIONS':
                    view.action = 'metadata'
                else:
                    view.action = actions.get(method.lower())

            if request is not None:
                view.request = clone_request(request, method)
                try:
                    view.check_permissions(view.request)
                except exceptions.APIException:
                    continue
            else:
                view.request = None

            link = self.get_link(path, method, callback, view)
            links.append((category, action, link))

        if not links:
            return None

        # Generate the schema content structure, eg:
        # {'users': {'list': Link()}}
        content = {}
        for category, action, link in links:
            if category is None:
                content[action] = link
            elif category in content:
                content[category][action] = link
            else:
                content[category] = {action: link}

        # Return the schema document.
        return coreapi.Document(title=self.title,
                                content=content,
                                url=self.url)
Exemple #39
0
    def show_form_for_method(self, view, method, request, obj):
        """
        Returns True if a form should be shown for this method.
        """
        if not method in view.allowed_methods:
            return  # Not a valid method

        if not api_settings.FORM_METHOD_OVERRIDE:
            return  # Cannot use form overloading

        try:
            view.check_permissions(clone_request(request, method))
        except exceptions.APIException:
            return False  # Doesn't have permissions
        return True
    def show_form_for_method(self, view, method, request, obj):
        """
        Returns True if a form should be shown for this method.
        """
        if not method in view.allowed_methods:
            return  # Not a valid method

        if not api_settings.FORM_METHOD_OVERRIDE:
            return  # Cannot use form overloading

        try:
            view.check_permissions(clone_request(request, method))
        except exceptions.APIException:
            return False  # Doesn't have permissions
        return True
    def get_schema(self, request=None):
        if self.endpoints is None:
            self.endpoints = self.get_api_endpoints(self.patterns)

        links = []
        for path, method, category, action, callback in self.endpoints:
            view = callback.cls()
            for attr, val in getattr(callback, 'initkwargs', {}).items():
                setattr(view, attr, val)
            view.args = ()
            view.kwargs = {}
            view.format_kwarg = None

            actions = getattr(callback, 'actions', None)
            if actions is not None:
                if method == 'OPTIONS':
                    view.action = 'metadata'
                else:
                    view.action = actions.get(method.lower())

            if request is not None:
                view.request = clone_request(request, method)
                try:
                    view.check_permissions(view.request)
                except exceptions.APIException:
                    continue
            else:
                view.request = None

            link = self.get_link(path, method, callback, view)
            links.append((category, action, link))

        if not links:
            return None

        # Generate the schema content structure, eg:
        # {'users': {'list': Link()}}
        content = {}
        for category, action, link in links:
            if category is None:
                content[action] = link
            elif category in content:
                content[category][action] = link
            else:
                content[category] = {action: link}

        # Return the schema document.
        return coreapi.Document(title=self.title, content=content, url=self.url)
Exemple #42
0
    def determine_actions(self, request, view):
        """Simple override to always show the field information even for people
        that don't have POST access.

        Fixes issue #732.
        """
        actions = {}
        for method in {'PUT', 'POST'} & set(view.allowed_methods):
            view.request = clone_request(request, method)
            if method == 'PUT' and hasattr(view, 'get_object'):
                view.get_object()
            serializer = view.get_serializer()
            actions[method] = self.get_serializer_info(serializer)
            view.request = request

        return actions
Exemple #43
0
    def determine_actions(self, request, view):
        """Simple override to always show the field information even for people
        that don't have POST access.

        Fixes issue #732.
        """
        actions = {}
        for method in {"PUT", "POST"} & set(view.allowed_methods):
            view.request = clone_request(request, method)
            if method == "PUT" and hasattr(view, "get_object"):
                view.get_object()
            serializer = view.get_serializer()
            actions[method] = self.get_serializer_info(serializer)
            view.request = request

        return actions
Exemple #44
0
    def show_form_for_method(self, view, method, request, obj):
        """
        Returns True if a form should be shown for this method.
        """
        if not method in view.allowed_methods:
            return  # Not a valid method

        if not api_settings.FORM_METHOD_OVERRIDE:
            return  # Cannot use form overloading

        request = clone_request(request, method)
        try:
            if not view.has_permission(request, obj):
                return  # Don't have permission
        except:
            return  # Don't have permission and exception explicitly raise
        return True
    def show_form_for_method(self, view, method, request, obj):
        """
        Returns True if a form should be shown for this method.
        """
        if not method in view.allowed_methods:
            return  # Not a valid method

        if not api_settings.FORM_METHOD_OVERRIDE:
            return  # Cannot use form overloading

        request = clone_request(request, method)
        try:
            if not view.has_permission(request, obj):
                return  # Don't have permission
        except:
            return  # Don't have permission and exception explicitly raise
        return True
Exemple #46
0
    def determine_actions(self, request, view):
        """For generic class based views we return information about
        the fields that are accepted for 'PUT' and 'POST' methods.
        """
        actions = {}
        for method in {'PUT', 'POST', 'GET'} & set(view.allowed_methods):
            view.request = clone_request(request, method)

            if hasattr(view, 'action_map'):
                view.action = view.action_map.get(method.lower(), None)

            try:
                # Test global permissions
                if hasattr(view, 'check_permissions'):
                    view.check_permissions(view.request)

                # Test object permissions
                instance = None
                lookup_url_kwarg = view.lookup_url_kwarg or view.lookup_field
                if lookup_url_kwarg in view.kwargs and hasattr(
                        view, 'get_object'):
                    instance = view.get_object()

            except (exceptions.APIException, PermissionDenied, Http404):
                pass

            else:
                # If user has appropriate permissions for the view, include
                # appropriate metadata about the fields that should be
                # supplied.
                try:
                    serializer = view.get_serializer(instance=instance)
                except exceptions.PermissionDenied:
                    pass

                else:
                    actions[method] = self.get_serializer_info(serializer)

                    if not actions[method]:
                        del actions[method]

            finally:
                view.request = request

        return actions
Exemple #47
0
    def metadata(self, request):
        """
        Return a dictionary of metadata about the view.
        Used to return responses for OPTIONS requests.

        We override the default behavior, and add some extra information
        about the required request body for POST and PUT operations.
        """
        ret = super(GenericAPIView, self).metadata(request)

        actions = {}
        for method in ('PUT', 'POST'):
            if method not in self.allowed_methods:
                continue

            original_request = self.request
            self.request = clone_request(request, method)
            try:
                # Test global permissions
                self.check_permissions(self.request)
                # Test object permissions
                if method == 'PUT':
                    try:
                        self.get_object()
                    except Http404:
                        # Http404 should be acceptable and the serializer
                        # metadata should be populated. Except this so the
                        # outer "else" clause of the try-except-else block
                        # will be executed.
                        pass
            except (exceptions.APIException, PermissionDenied):
                pass
            else:
                # If user has appropriate permissions for the view, include
                # appropriate metadata about the fields that should be supplied.
                serializer = self.get_serializer()
                actions[method] = serializer.metadata()
            finally:
                self.request = original_request

        if actions:
            ret['actions'] = actions

        return ret
Exemple #48
0
    def get_object_or_none(self):
        """
        Retrieve an object or return None if the object can't be found.

        NOTE: This replaces functionality that was removed in Django Rest Framework v3.1.
        """
        try:
            return self.get_object()
        except Http404:
            if self.request.method == 'PUT':
                # For PUT-as-create operation, we need to ensure that we have
                # relevant permissions, as if this was a POST request.  This
                # will either raise a PermissionDenied exception, or simply
                # return None.
                self.check_permissions(clone_request(self.request, 'POST'))
            else:
                # PATCH requests where the object does not exist should still
                # return a 404 response.
                raise
Exemple #49
0
 def metadata(self, request):
     """
     Add field information for GET requests (so field names/labels are
     available even when we can't POST/PUT).
     """
     ret = super(GenericAPIView, self).metadata(request)
     actions = ret.get('actions', {})
     # Remove read only fields from PUT/POST data.
     for method in ('POST', 'PUT'):
         fields = actions.get(method, {})
         for field, meta in fields.items():
             if not isinstance(meta, dict):
                 continue
             if meta.get('read_only', False):
                 fields.pop(field)
     if 'GET' in self.allowed_methods:
         cloned_request = clone_request(request, 'GET')
         try:
             # Test global permissions
             self.check_permissions(cloned_request)
             # Test object permissions
             if hasattr(self, 'retrieve'):
                 try:
                     self.get_object()
                 except Http404:
                     # Http404 should be acceptable and the serializer
                     # metadata should be populated. Except this so the
                     # outer "else" clause of the try-except-else block
                     # will be executed.
                     pass
         except Exception:
             pass
         else:
             # If user has appropriate permissions for the view, include
             # appropriate metadata about the fields that
             # should be supplied.
             serializer = self.get_serializer()
             actions['GET'] = serializer.metadata()
     if actions:
         ret['actions'] = actions
     if getattr(self, 'search_fields', None):
         ret['search_fields'] = self.search_fields
     return ret
Exemple #50
0
    def get_object_or_none(self):
        """
        Retrieve an object or return None if the object can't be found.

        NOTE: This replaces functionality that was removed in Django Rest Framework v3.1.
        """
        try:
            return self.get_object()
        except Http404:
            if self.request.method == 'PUT':
                # For PUT-as-create operation, we need to ensure that we have
                # relevant permissions, as if this was a POST request.  This
                # will either raise a PermissionDenied exception, or simply
                # return None.
                self.check_permissions(clone_request(self.request, 'POST'))
            else:
                # PATCH requests where the object does not exist should still
                # return a 404 response.
                raise
    def get_schema(self, request=None,public=False):
        if self.endpoints is None:
            self.endpoints=[]
            self.get_api_endpoints(self.patterns,final_arrays=self.endpoints)
        ret=[]
        for group in self.endpoints:
            contents=group['points']
            prefix=group['prefix']
            view_cls = {}
            view_paths = defaultdict(list)
            for path, method,  callback in contents:
                view = callback.cls()
                _paths={}
                for attr, val in getattr(callback, 'initkwargs', {}).items():
                    setattr(view, attr, val)
                view.args = ()
                view.kwargs = {}
                view.format_kwarg = None

                actions = getattr(callback, 'actions', None)
                if actions is not None:
                    if method == 'OPTIONS':
                        view.action = 'metadata'
                    else:
                        view.action = actions.get(method.lower())

                if request is not None:
                    view.request = clone_request(request, method)
                    try:
                        view.check_permissions(view.request)
                    except exceptions.APIException:
                        continue
                else:
                    view.request = None
                view_paths[path].append((method, view))
                view_cls[path]=callback.cls
            ret.append({"prefix":group['prefix'],"points":{path: (view_cls[path], methods) for path, methods in view_paths.items()}})
        #print(len(ret))
        # return self.get_paths(ret, None, request, public=False)
        # return self.get_register_api(ret, None, request, public=False)
        register_api = self.get_register_api(ret, None, request, public=False)
        return self.handle_api_path(register_api)
Exemple #52
0
    def determine_metadata(self, request, view):
        metadata = OrderedDict()
        metadata['view'] = self.determine_view_meta(view)
        if hasattr(view, 'get_serializer'):
            view.request = clone_request(request, "GET")
            try:
                # Test global permissions
                if hasattr(view, 'check_permissions'):
                    view.check_permissions(view.request)
            except (exceptions.APIException, PermissionDenied, Http404):
                pass
            else:
                # If user has appropriate permissions for the view, include
                # appropriate metadata about the fields that should be supplied.
                serializer = view.get_serializer()
                metadata['table'] = self.get_table_info(serializer)
            finally:
                view.request = request

        return metadata
    def put(self, request, *args, **kwargs):
        #classroom can add any published project:
        qs_projects = Project.objects.filter(publish_mode=Project.PUBLISH_MODE_PUBLISHED)
        try:
            project_obj = qs_projects.get(pk=self.kwargs['pk'])
        except qs_projects.model.DoesNotExist:
            raise PermissionDenied(detail='Only published projects are allowed to be added to a classroom.')

        # If the project is locked.
        if project_obj.lock != Project.NO_LOCK:

            # If the user doesn't have a permission to teach this project.
            if not project_obj.can_teach(request.user):
                raise PermissionDenied(detail='You don\'t have permission to teach this project')

        #use serializer to validate project_obj object, and get project order:
        serializer = self.get_serializer(project_obj, data=request.data)
        if not serializer.is_valid():
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
        project_order = serializer.validated_data['order']

        # Create a new ProjectInClassroom for the classroom and the project in the URL
        # but only if there isn't a ProjectInClassroom already in the DB.
        projectinclassroom, created = ProjectInClassroom.objects.get_or_create(
            classroom_id=self.kwargs.get('classroom_pk'),
            project=project_obj,
            defaults={
                'order': project_order,
            }
        )

        #change the order of the project in case of update:
        if not created and projectinclassroom.order != project_order:
            projectinclassroom.order = project_order
            projectinclassroom.save()

        # Delegate the response to the retrieve method. The reason is that the
        # object we create (ClassroomState) is not the object we want to return
        # (User object)
        self.request = clone_request(request, 'GET')
        return self.retrieve(self.request, *args, **kwargs)
    def get_raw_data_form(self, view, method, request, media_types):
        """
        Returns a form that allows for arbitrary content types to be tunneled
        via standard HTML forms.
        (Which are typically application/x-www-form-urlencoded)
        """

        # If we're not using content overloading there's no point in supplying a generic form,
        # as the view won't treat the form's value as the content of the request.
        if not (api_settings.FORM_CONTENT_OVERRIDE
                and api_settings.FORM_CONTENTTYPE_OVERRIDE):
            return None

        # Check permissions
        obj = getattr(view, 'object', None)
        cloned_request = clone_request(request, method)
        if not self.show_form_for_method(view, method, cloned_request, obj):
            return

        content_type_field = api_settings.FORM_CONTENTTYPE_OVERRIDE
        content_field = api_settings.FORM_CONTENT_OVERRIDE
        choices = [(media_type, media_type) for media_type in media_types]
        initial = media_types[0]

        # NB. http://jacobian.org/writing/dynamic-form-generation/
        class GenericContentForm(forms.Form):
            def __init__(self):
                super(GenericContentForm, self).__init__()

                self.fields[content_type_field] = forms.ChoiceField(
                    label='Media type',
                    choices=choices,
                    initial=initial
                )
                self.fields[content_field] = forms.CharField(
                    label='Content',
                    widget=forms.Textarea
                )

        return GenericContentForm()
Exemple #55
0
    def _prepare_view(self, view_class, lookup_url_kwarg, request_method='GET', queryset=None,
                                  action_request=None, action_args=None, action_kwargs=None,
                                  permission_classes=None, authentication_classes=None, override_options=None):
        '''
        Prepares the root view for action.
        '''

        #defaults:
        action_request = action_request if action_request is not None else self.request
        action_args = action_args if action_args is not None else self.args
        action_kwargs = action_kwargs if action_kwargs is not None else self.kwargs

        #make the view instance:
        view_instance = view_class(lookup_url_kwarg=lookup_url_kwarg)
        view_instance.args = action_args
        view_instance.kwargs = action_kwargs
        view_instance.request = clone_request(action_request, request_method)  #clone the same request but with GET method

        #IMPORTANT: set the queryset of the root view to the current queryset:
        #(this allows to concatenate RootViewBuilder's)
        view_instance.queryset = queryset

        #Do not override permission/authentication classes, but add to them to strict more:
        #The rationale beyond this is that any inner object in the url is not accessible if the
        #former object in the URL is not accessible.
        if permission_classes is not None:
            view_instance.permission_classes += permission_classes
        if authentication_classes is not None:
            view_instance.authentication_classes += authentication_classes

        #override more options (preferred not to use it):
        if isinstance(override_options, dict):
            for opt_key, opt_val in override_options:
                if hasattr(view_instance, opt_key):
                    setattr(view_instance, opt_key, opt_val)

        #initialize the view instance:
        view_instance.initial(view_instance.request, *action_args, **action_kwargs)

        return view_instance
Exemple #56
0
    def create_view(self, callback, method, request=None):
        """
        Given a callback, return an actual view instance.
        """
        view = callback.cls(**getattr(callback, 'initkwargs', {}))
        view.args = ()
        view.kwargs = {}
        view.format_kwarg = None
        view.request = None
        view.action_map = getattr(callback, 'actions', None)

        actions = getattr(callback, 'actions', None)
        if actions is not None:
            if method == 'OPTIONS':
                view.action = 'metadata'
            else:
                view.action = get(method.lower())

        if request is not None:
            view.request = clone_request(request, method)

        return view
    def create_view(self, callback, method, request=None):
        """
        Given a callback, return an actual view instance.
        """
        view = callback.cls(**getattr(callback, 'initkwargs', {}))
        view.args = ()
        view.kwargs = {}
        view.format_kwarg = None
        view.request = None
        view.action_map = getattr(callback, 'actions', None)

        actions = getattr(callback, 'actions', None)
        if actions is not None:
            if method == 'OPTIONS':
                view.action = 'metadata'
            else:
                view.action = actions.get(method.lower())

        if request is not None:
            view.request = clone_request(request, method)

        return view
    def get_schema(self, request=None):
        if self.endpoints is None:
            self.endpoints = self.get_api_endpoints(self.patterns)

        links = []
        for key, path, method, callback in self.endpoints:
            view = callback.cls()
            for attr, val in getattr(callback, 'initkwargs', {}).items():
                setattr(view, attr, val)
            view.args = ()
            view.kwargs = {}
            view.format_kwarg = None

            if request is not None:
                view.request = clone_request(request, method)
                try:
                    view.check_permissions(view.request)
                except exceptions.APIException:
                    continue
            else:
                view.request = None

            link = self.get_link(path, method, callback, view)
            links.append((key, link))

        if not link:
            return None

        # Generate the schema content structure, from the endpoints.
        # ('users', 'list'), Link -> {'users': {'list': Link()}}
        content = {}
        for key, link in links:
            insert_into(content, key, link)

        # Return the schema document.
        return coreapi.Document(title=self.title, content=content, url=self.url)
    def create_view(self, callback, method, request=None):
        """
        Given a callback, return an actual view instance.
        """
        view = callback.cls()
        for attr, val in getattr(callback, "initkwargs", {}).items():
            setattr(view, attr, val)
        view.args = ()
        view.kwargs = {}
        view.format_kwarg = None
        view.request = None
        view.action_map = getattr(callback, "actions", None)

        actions = getattr(callback, "actions", None)
        if actions is not None:
            if method == "OPTIONS":
                view.action = "metadata"
            else:
                view.action = actions.get(method.lower())

        if request is not None:
            view.request = clone_request(request, method)

        return view
    def determine_actions(self, request, view):
        """
        For generic class based views we return information about the fields
        that are accepted for 'PUT' and 'POST' methods.

        This method expects that `get_object` may actually fail and gracefully
        handles it.

        Most of the code in this method is copied from the parent class.
        """
        actions = {}
        for method in set(['PUT', 'POST']) & set(view.allowed_methods):
            view.request = clone_request(request, method)
            try:
                # Test global permissions
                if hasattr(view, 'check_permissions'):
                    view.check_permissions(view.request)
                # Test object permissions. This will fail on list url for
                # resources supporting bulk operations. In such case
                # permissions are not checked.
                if method == 'PUT' and hasattr(view, 'get_object'):
                    try:
                        view.get_object()
                    except (AssertionError, KeyError):
                        pass
            except (exceptions.APIException, PermissionDenied, Http404):
                pass
            else:
                # If user has appropriate permissions for the view, include
                # appropriate metadata about the fields that should be supplied.
                serializer = view.get_serializer()
                actions[method] = self.get_serializer_info(serializer)
            finally:
                view.request = request

        return actions