Ejemplo n.º 1
0
 def check_get_permissions(self, request, view, obj=None):
     if hasattr(view, 'parent_model'):
         parent_obj = get_object_or_400(view.parent_model, pk=view.kwargs['pk'])
         if not check_user_access(request.user, view.parent_model, 'read',
                                  parent_obj):
             return False
     if not obj:
         return True
     return check_user_access(request.user, view.model, 'read', obj)
Ejemplo n.º 2
0
    def check_put_permissions(self, request, view, obj=None):
        if not obj:
            # FIXME: For some reason this needs to return True
            # because it is first called with obj=None?
            return True

        if getattr(view, 'is_variable_data', False):
            return check_user_access(request.user, view.model, 'change', obj,
                                     dict(variables=request.DATA))
        else:
            return check_user_access(request.user, view.model, 'change', obj,
                                     request.DATA)
Ejemplo n.º 3
0
 def update_filter(self, request, *args, **kwargs):
     # make sure non-read-only fields that can only be edited by admins,
     # are only edited by admins
     obj = User.objects.get(pk=kwargs['pk'])
     can_change = check_user_access(request.user, User, 'change', obj, request.data)
     can_admin = check_user_access(request.user, User, 'admin', obj, request.data)
     if can_change and not can_admin:
         admin_only_edit_fields = ('full_name', 'username', 'is_active', 'is_superuser')
         changed = {}
         for field in admin_only_edit_fields:
             left = getattr(obj, field, None)
             right = request.data.get(field, None)
             if left is not None and right is not None and left != right:
                 changed[field] = (left, right)
         if changed:
             raise PermissionDenied('Cannot change %s' % ', '.join(changed.keys()))
Ejemplo n.º 4
0
 def check_parent_access(self, parent=None):
     parent = parent or self.get_parent_object()
     parent_access = getattr(self, 'parent_access', 'read')
     if parent_access in ('read', 'delete'):
         args = (parent_access, parent)
     else:
         args = (parent_access, parent, None)
     if not check_user_access(self.request.user, self.parent_model, *args):
         # logger.debug('check_parent_access: parent_access=%s parent=%s', parent_access, parent.__class__.__name__)
         raise PermissionDenied()
Ejemplo n.º 5
0
 def check_post_permissions(self, request, view, obj=None):
     if hasattr(view, 'parent_model'):
         get_object_or_400(view.parent_model, pk=view.kwargs['pk'])
         return True
     else:
         if obj:
             return True
         if hasattr(view, 'model'):
             return check_user_access(request.user, view.model, 'add', request.DATA)
         return True
Ejemplo n.º 6
0
    def unattach(self, request, *args, **kwargs):
        sub_id = request.DATA.get('id', None)
        if not sub_id:
            data = dict(msg='"id" is required to disassociate')
            return Response(data, status=status.HTTP_400_BAD_REQUEST)

        parent = self.get_parent_object()
        parent_key = getattr(self, 'parent_key', None)
        relationship = getattr(parent, self.relationship)
        sub = get_object_or_400(self.model, pk=sub_id)

        #if not request.user.can_access(self.parent_model, 'unattach', parent,
        if not check_user_access(request.user, self.parent_model, 'unattach',
                                 parent, sub, self.relationship):
            raise PermissionDenied()

        if parent_key:
            # sub object has a ForeignKey to the parent, so we can't remove it
            # from the set, only mark it as inactive.
            sub.mark_inactive()
        else:
            relationship.remove(sub)

        return Response(status=status.HTTP_204_NO_CONTENT)
Ejemplo n.º 7
0
    def attach(self, request, *args, **kwargs):
        attached = False
        created = False
        modified = False
        parent = self.get_parent_object()
        relationship = getattr(parent, self.relationship)
        sub_id = request.DATA.get('id', None)
        data = request.DATA

        # FIXME: We have special case handling for RoleRatings
        #        which would probably be better moved into
        #        a new class and overridden completely
        is_role_rating = isinstance(parent, RoleRating)
        #logger.debug('SubListCreateAPIView.attach: parent=%s', parent.__class__.__name__)

        # Create the sub object if an ID is not provided.
        # We never create objects when attaching to a RoleRating
        if not sub_id and not is_role_rating:
            try:
                response = self.create(request, *args, **kwargs)
                if response.status_code != status.HTTP_201_CREATED:
                    return response
                sub_id = response.data['id']
                data = response.data
                try:
                    location = response['Location']
                except KeyError:
                    location = None
                created = True
            except:
                # logger.debug('SubListCreateAPIView.attach: not sub_id and not is_role_rating threw Permission Denied')
                raise PermissionDenied()

        # Retrive the sub object (whether created or by ID).
        sub = get_object_or_400(self.model, pk=sub_id)

        # likewise with creation, we never try and update
        # the sub-object if we're dealing with a RoleRating
        if not created and not is_role_rating:
            # Update the object to make sure the data is correct, but
            # verify we have permission to edit before trying to update
            if not check_user_access(request.user, self.model, 'change', sub, data):
                raise PermissionDenied()
            else:
                sub.__dict__.update(data)
                if sub.is_dirty:
                    sub.save()
                    modified = True

        # Verify we have permission to attach.
        if not check_user_access(request.user, self.parent_model,
                                 'attach', parent, sub,
                                 self.relationship, data,
                                 skip_sub_obj_read_check=created):
            raise PermissionDenied()

        # Attach the object to the collection.
        if sub not in relationship.all():
            relationship.add(sub)
            attached = True

        # SPECIAL CASE
        # FIXME: the base view for objects with mutually exclusive
        #        relationship should probably be split off into a
        #        new view, which codifies the mutually exclusive things
        #if attached and is_role_rating:
            """
            Up/down votes are mutually exclusive. If we've attached
            the user to one of the lists, we need to make sure we
            remove them from the other (if they're in it).
            """
            # mux_relationship = None
            # if self.relationship == 'up_votes':
            #    mux_relationship = getattr(parent, 'down_votes')
            # elif self.relationship == 'down_votes':
            #    mux_relationship = getattr(parent, 'up_votes')
            # if mux_relationship and sub in mux_relationship.all():
            #    mux_relationship.remove(sub)

        if created:
            headers = {}
            if location:
                headers['Location'] = location
            return Response(data, status=status.HTTP_201_CREATED, headers=headers)
        elif modified or attached:
            return Response(data, status=status.HTTP_200_OK)
        else:
            return Response(status=status.HTTP_204_NO_CONTENT)
Ejemplo n.º 8
0
class SubListCreateAPIView(SubListAPIView, ListCreateAPIView):
    # Base class for a sublist view that allows for creating subobjects and
    # attaching/detaching them from the parent.

    # In addition to SubListAPIView properties, subclasses may define (if the
    # sub_obj requires a foreign key to the parent):
    #   parent_key = 'field_on_model_referring_to_parent'

    def get_description_context(self):
        d = super(SubListCreateAPIView, self).get_description_context()
        d.update({
            'parent_key': getattr(self, 'parent_key', None),
        })
        return d

    def create(self, request, *args, **kwargs):
        # If the object ID was not specified, it probably doesn't exist in the
        # DB yet. We want to see if we can create it.  The URL may choose to
        # inject it's primary key into the object because we are posting to a
        # subcollection. Use all the normal access control mechanisms.

        # Make a copy of the data provided (since it's readonly) in order to
        # inject additional data.

        if hasattr(request.DATA, 'dict'):
            data = request.DATA.dict()
        else:
            data = request.DATA

        # add the parent key to the post data using the pk from the URL
        parent_key = getattr(self, 'parent_key', None)
        # logger.debug('SubListCreateAPIView.create: parent_key=%s', parent_key)
        if parent_key:
            data[parent_key] = self.kwargs['pk']
        # logger.debug('SubListCreateAPIView.create: data.parent_key=%s', data[parent_key])

        # attempt to deserialize the object
        try:
            serializer = self.serializer_class(data=data)
            if not serializer.is_valid():
                # logger.debug('SubListCreateAPIView.create: serializer failed validation')
                return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
        except Exception, e:
            # logger.debug('SubListCreateAPIView.create: serializer threw an error')
            return Response("serializer errors", status=status.HTTP_400_BAD_REQUEST)

        # Verify we have permission to add the object as given.
        if not check_user_access(request.user, self.model, 'add', serializer.validated_data):
            # logger.debug('SubListCreateAPIView.create: permission denied user=%s model=%s action=add',
            #             request.user, self.model._meta.verbose_name)
            raise PermissionDenied()

        # save the object through the serializer, reload and return the saved
        # object deserialized

        try:
            self.pre_save(serializer.validated_data)
            obj = serializer.save()
            data = self.serializer_class(obj).data
        except IntegrityError, e:
            return Response("database integrity conflict", status=status.HTTP_409_CONFLICT)
Ejemplo n.º 9
0
 def check_delete_permissions(self, request, view, obj=None):
     if not obj:
         # FIXME: For some reason this needs to return True
         # because it is first called with obj=None?
         return True
     return check_user_access(request.user, view.model, 'delete', obj)
Ejemplo n.º 10
0
    def attach(self, request, *args, **kwargs):
        attached = False
        created = False
        modified = False
        parent = self.get_parent_object()
        relationship = getattr(parent, self.relationship)
        sub_id = request.DATA.get('id', None)
        data = request.DATA

        # Create the sub object if an ID is not provided.
        if not sub_id:
            try:
                response = self.create(request, *args, **kwargs)
                if response.status_code != status.HTTP_201_CREATED:
                    return response
                sub_id = response.data['id']
                data = response.data
                try:
                    location = response['Location']
                except KeyError:
                    location = None
                created = True
            except Exception:
                raise PermissionDenied()

        # Retrive the sub object (whether created or by ID).
        sub = get_object_or_400(self.model, pk=sub_id)

        # likewise with creation, we never try and update
        if not created:
            # Update the object to make sure the data is correct, but
            # verify we have permission to edit before trying to update
            if not check_user_access(request.user, self.model, 'change', sub,
                                     data):
                raise PermissionDenied()
            else:
                sub.__dict__.update(data)
                if sub.is_dirty:
                    sub.save()
                    modified = True

        # Verify we have permission to attach.
        if not check_user_access(request.user,
                                 self.parent_model,
                                 'attach',
                                 parent,
                                 sub,
                                 self.relationship,
                                 data,
                                 skip_sub_obj_read_check=created):
            raise PermissionDenied()

        # Attach the object to the collection.
        if sub not in relationship.all():
            relationship.add(sub)
            attached = True

        if created:
            headers = {}
            if location:
                headers['Location'] = location
            return Response(data,
                            status=status.HTTP_201_CREATED,
                            headers=headers)
        elif modified or attached:
            return Response(data, status=status.HTTP_200_OK)
        else:
            return Response(status=status.HTTP_204_NO_CONTENT)