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
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)
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)
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)
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
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)
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)
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 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
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)
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
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
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'))
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
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)
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_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_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())
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
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
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
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
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)
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 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
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
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 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
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
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 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
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)
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()
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
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