Esempio n. 1
0
    def delete(self, request: Request, name=None) -> Response:
        """Delete all key-value store datastores for the client.

        The request user must not be anonymous and must have browse, annotate
        or administer permissions for at least one project.
        ---
        parameters:
        - name: project_id
          description: |
            ID of a project to delete data from, if any.
          required: false
          type: integer
          paramType: form
        - name: ignore_user
          description: |
            Whether to clear dataassociated with the instance or the request
            user. Only project administrators can do this for project-associated
            instance data, and only super users can do this for global data
            (instance data not associated with any project).
          required: false
          type: boolean
          default: false
          paramType: form
        """
        if request.user == get_anonymous_user(
        ) or not request.user.is_authenticated:
            raise PermissionDenied('Unauthenticated or anonymous users ' \
                                   'can not delete datastores.')

        project_id = request.data.get('project_id', None)
        project = None
        if project_id:
            project_id = int(project_id)
            project = get_object_or_404(Project, pk=project_id)
            if not check_user_role(request.user, project,
                                   [UserRole.Browse, UserRole.Annotate]):
                raise PermissionDenied('User lacks the appropriate ' \
                                       'permissions for this project.')

        ignore_user = get_request_bool(request.data, 'ignore_user', False)
        if ignore_user and not project_id:
            if not request.user.is_superuser:
                raise PermissionDenied('Only super users can delete instance ' \
                                       'data.')
        if ignore_user:
            if not check_user_role(request.user, project, [UserRole.Admin]):
                raise PermissionDenied('Only administrators can delete ' \
                                       'project default data.')
        user = None if ignore_user else request.user

        datastore = ClientDatastore(name=name)
        n_deleted, _ = ClientData.objects.filter(datastore=datastore,
                                                 project=project,
                                                 user=user).delete()
        return Response({
            'n_deleted': n_deleted,
        })
Esempio n. 2
0
    def get(self, request: Request, name=None, format=None) -> Response:
        """List key-value data in a datastore for the client.

        Returns key-values belong to the request user or no user, optionally
        filtering for those pairs belong to a specific project or no project.
        ---
        parameters:
        - name: name
          description: |
            String key for the **datastore** with which this key-value entry is
            associated.
          required: true
          type: string
          paramType: path
        - name: project_id
          description: |
            ID of a project to associate this data with, if any.
          required: false
          type: integer
          paramType: query
        serializer: ClientDataSerializer
        """
        datastore = get_object_or_404(ClientDatastore, name=name)
        data = ClientData.objects.filter(datastore=datastore,
                                         user_id=request.user.id) | \
               ClientData.objects.filter(datastore=datastore,
                                         user_id=None)

        project_id = request.GET.get('project_id', None)
        if project_id:
            project_id = int(project_id)
            project = get_object_or_404(Project, pk=project_id)
            if not check_user_role(request.user, project,
                                   [UserRole.Browse, UserRole.Annotate]):
                raise PermissionDenied('User lacks the appropriate ' \
                                       'permissions for this project.')

            data = data.filter(project_id=project_id) | data.filter(
                project_id=None)
        else:
            data = data.filter(project_id=None)

        serializer = ClientDataSerializer(data, many=True)
        return Response(serializer.data)
Esempio n. 3
0
    def get(self, request, name=None, format=None):
        """List key-value data in a datastore for the client.

        Returns key-values belong to the request user or no user, optionally
        filtering for those pairs belong to a specific project or no project.
        ---
        parameters:
        - name: name
          description: |
            String key for the **datastore** with which this key-value entry is
            associated.
          required: true
          type: string
          paramType: path
        - name: project_id
          description: |
            ID of a project to associate this data with, if any.
          required: false
          type: integer
          paramType: query
        serializer: ClientDataSerializer
        """
        datastore = get_object_or_404(ClientDatastore, name=name)
        data = ClientData.objects.filter(datastore=datastore,
                                         user_id=request.user.id) | \
               ClientData.objects.filter(datastore=datastore,
                                         user_id=None)

        project_id = request.GET.get('project_id', None)
        if project_id:
            project_id = int(project_id)
            project = get_object_or_404(Project, pk=project_id)
            if not check_user_role(request.user,
                                   project,
                                   [UserRole.Browse, UserRole.Annotate]):
                raise PermissionDenied('User lacks the appropriate ' \
                                       'permissions for this project.')

            data = data.filter(project_id=project_id) | data.filter(project_id=None)
        else:
            data = data.filter(project_id=None)

        serializer = ClientDataSerializer(data, many=True)
        return Response(serializer.data)
Esempio n. 4
0
    def put(self,
            request: Request,
            name: Optional[int] = None,
            format=None) -> Response:
        """Create or replace a key-value data entry for the client.

        Each entry is associated with a datastore, an optional project, an
        optional user, and a key. Creating a request that duplicates this
        quadruple will replace rather than create the value in the key-value
        pair.

        Entries associated with neither a project nor user are considered
        global; those associated with a project but no user are project-
        default; those associated with a user but no project are user-default;
        and those associated with both a project and a user are user-project
        specific. When listing key-value data, all four of these values, if
        existing, will be returned.
        ---
        parameters:
        - name: name
          description: |
            String key for the **datastore** with which this key-value entry is
            associated.
          required: true
          type: string
          paramType: path
        - name: project_id
          description: |
            ID of a project to associate this data with, if any.
          required: false
          type: integer
          paramType: form
        - name: ignore_user
          description: |
            Whether to associate this key-value entry with the instance rather
            than the request user. Only project administrators can do this
            for project-associated instance data, and only super users can do
            this for global data (instance data not associated with any
            project).
          required: false
          type: boolean
          default: false
          paramType: form
        - name: key
          description: A key for this entry.
          required: true
          type: string
          paramType: form
        - name: value
          description: A value for this entry. Must be valid JSON.
          required: true
          type: string
          paramType: form
        - name: format
          description: This function parameter is ignored
          required: false
          type: Any
          default: None
        response_serializer: ClientDataSerializer
        """
        if request.user == get_anonymous_user(
        ) or not request.user.is_authenticated:
            raise PermissionDenied('Unauthenticated or anonymous users ' \
                                   'can not create data.')
        datastore = get_object_or_404(ClientDatastore, name=name)

        key = request.data.get('key', None)
        if not key:
            raise ValidationError('A key for the data must be provided.')

        value = request.data.get('value', None)
        if not value:
            raise ValidationError('A value for the data must be provided.')
        # Validate JSON by reserializing.
        try:
            value = json.loads(value)
        except ValueError as exc:
            raise ValidationError('Data value is invalid JSON: ' + str(exc))

        project_id = request.data.get('project_id', None)
        project = None
        if project_id:
            project_id = int(project_id)
            project = get_object_or_404(Project, pk=project_id)
            if not check_user_role(request.user, project,
                                   [UserRole.Browse, UserRole.Annotate]):
                raise PermissionDenied('User lacks the appropriate ' \
                                       'permissions for this project.')

        ignore_user = get_request_bool(request.data, 'ignore_user', False)
        if ignore_user and not project_id:
            if not request.user.is_superuser:
                raise PermissionDenied('Only super users can create instance ' \
                                       'data.')
        if ignore_user:
            if not check_user_role(request.user, project, [UserRole.Admin]):
                raise PermissionDenied('Only administrators can create ' \
                                       'project default data.')
        user = None if ignore_user else request.user

        try:
            data = ClientData.objects.get(datastore=datastore,
                                          key=key,
                                          project=project,
                                          user=user)
            data.value = value
            data.full_clean()
            data.save()
            return Response(status=status.HTTP_204_NO_CONTENT)
        except ClientData.DoesNotExist:
            data = ClientData(datastore=datastore,
                              key=key,
                              value=value,
                              project=project,
                              user=user)
            data.full_clean()
            data.save()
            serializer = ClientDataSerializer(data)
            return Response(serializer.data)
Esempio n. 5
0
    def put(self, request, name=None, format=None):
        """Create or replace a key-value data entry for the client.

        Each entry is associated with a datastore, an optional project, an
        optional user, and a key. Creating a request that duplicates this
        quadruple will replace rather than create the value in the key-value
        pair.

        Entries associated with neither a project nor user are considered
        global; those associated with a project but no user are project-
        default; those associated with a user but no project are user-default;
        and those associated with both a project and a user are user-project
        specific. When listing key-value data, all four of these values, if
        existing, will be returned.
        ---
        parameters:
        - name: name
          description: |
            String key for the **datastore** with which this key-value entry is
            associated.
          required: true
          type: string
          paramType: path
        - name: project_id
          description: |
            ID of a project to associate this data with, if any.
          required: false
          type: integer
          paramType: form
        - name: ignore_user
          description: |
            Whether to associate this key-value entry with the instance rather
            than the request user. Only project administrators can do this
            for project-associated instance data, and only super users can do
            this for global data (instance data not associated with any
            project).
          required: false
          type: boolean
          default: false
          paramType: form
        - name: key
          description: A key for this entry.
          required: true
          type: string
          paramType: form
        - name: value
          description: A value for this entry. Must be valid JSON.
          required: true
          type: string
          paramType: form
        response_serializer: ClientDataSerializer
        """
        if request.user == get_anonymous_user() or not request.user.is_authenticated:
            raise PermissionDenied('Unauthenticated or anonymous users ' \
                                   'can not create data.')
        datastore = get_object_or_404(ClientDatastore, name=name)

        key = request.data.get('key', None)
        if not key:
            raise ValidationError('A key for the data must be provided.')

        value = request.data.get('value', None)
        if not value:
            raise ValidationError('A value for the data must be provided.')
        # Validate JSON by reserializing.
        try:
            value = json.loads(value)
        except ValueError as exc:
            raise ValidationError('Data value is invalid JSON: ' + str(exc))

        project_id = request.data.get('project_id', None)
        project = None
        if project_id:
            project_id = int(project_id)
            project = get_object_or_404(Project, pk=project_id)
            if not check_user_role(request.user,
                                   project,
                                   [UserRole.Browse, UserRole.Annotate]):
                raise PermissionDenied('User lacks the appropriate ' \
                                       'permissions for this project.')

        ignore_user = get_request_bool(request.data, 'ignore_user', False)
        if ignore_user and not project_id:
            if not request.user.is_superuser:
                raise PermissionDenied('Only super users can create instance ' \
                                       'data.')
        if ignore_user:
            if not check_user_role(request.user,
                                   project,
                                   [UserRole.Admin]):
                raise PermissionDenied('Only administrators can create ' \
                                       'project default data.')
        user = None if ignore_user else request.user

        try:
            data = ClientData.objects.get(datastore=datastore,
                                          key=key,
                                          project=project,
                                          user=user)
            data.value = value
            data.full_clean()
            data.save()
            return Response(status=status.HTTP_204_NO_CONTENT)
        except ClientData.DoesNotExist:
            data = ClientData(datastore=datastore,
                              key=key,
                              value=value,
                              project=project,
                              user=user)
            data.full_clean()
            data.save()
            serializer = ClientDataSerializer(data)
            return Response(serializer.data)
Esempio n. 6
0
    def put(self, request, project_id):
        """Create a new similarity/NBLAST configuration either by providing
        parameters to have the back-end queue a job or by providing the complete
        matrix data.
        ---
        parameters:
          - name: project_id
            description: Project of the NBLAST configuration
            type: integer
            paramType: path
            required: true
          - name: name
            description: Name of the new NBLAST configuration
            type: string
            paramType: form
            required: true
          - name: source
            description: Where random skeletons come from. Either
            "data", "request" or "backend-random".
            required: false
            defaultValue: "backend-random"
            paramType: form
          - name: distance_breaks
            description: Bin boundaries for the distance in nm. Defaults to [0, 500] in an increasing logarithmic bin sizw
            required: false
            defaultValue: 21
            paramType: form
          - name: dot_breaks
            description: Bin boundaries for the absolute dot product. Defaults to [0, 1] in 0.1 steps.
            required: false
            defaultValue: 10
            paramType: form
          - name: tangent_neighbors
            description: The number of neighbor nodes that should be considered when computing a tangent vector.
            required: false
            defaultValue: 20
            paramType: form
          - name: matching_skeleton_ids
            description: A list of matching skeleton IDs if <source> is not "data".
            required: false
            defaultValue: []
            paramType: form
          - name: random_skeleton_ids
            description: A list of random skeleton IDs if <source> is not "request".
            required: false
            defaultValue: []
            paramType: form
          - name: matching_sample_id
            description: An NblastSample foreign key of the matching sample.
            required: false
            defaultValue: None
            paramType: form
          - name: random_sample_id
            description: An NblastSample foreign key tp a random sample.
            required: false
            defaultValue: None
            paramType: form
        """
        name = request.data.get('name')
        if not name:
            raise ValueError("Need name")

        source = request.data.get('source', 'backend-random')
        distance_breaks = get_request_list(request.data, 'distance_breaks', map_fn=float)
        dot_breaks = get_request_list(request.data, 'dot_breaks', map_fn=float)
        tangent_neighbors = int(request.data.get('tangent_neighbors', '20'))
        matching_sample_id = int(request.data.get('matching_sample_id')) \
                if 'matching_sample_id' in request.data else None
        random_sample_id = int(request.data.get('random_sample_id')) \
                if 'random_sample_id' in request.data else None
        min_length = float(request.data.get('min_length', 0))
        user_id = request.user.id

        if not dot_breaks:
            dot_breaks = NblastConfigDefaultDotBreaks

        if not distance_breaks:
            distance_breaks = NblastConfigDefaultDistanceBreaks

        # Make sure bins and breaks match

        if source == 'data':
            data = request.data['data']
            config = self.add_from_raw_data(data, distance_breaks, dot_breaks,
                    matching_sample_id, random_sample_id)
            return Response(serialize_config(config))
        elif source == 'request':
            matching_skeleton_ids = get_request_list(request.data,
                    'matching_skeleton_ids', map_fn=int)
            random_skeleton_ids = get_request_list(request.data,
                    'random_skeleton_ids', map_fn=int)
            if not matching_skeleton_ids:
                raise ValueError("Need matching_skeleton_ids")
            if not random_skeleton_ids:
                raise ValueError("Need random_skeleton_ids")

            # Cancel if user isn't allowed to queue computation tasks
            p = Project.objects.get(pk=project_id)
            has_role = check_user_role(request.user, p, UserRole.QueueComputeTask)
            if not has_role:
                raise PermissionError("User " + str(request.user.id) +
                        " doesn't have permission to queue computation tasks.")

            config = self.add_delayed(matching_skeleton_ids,
                    random_skeleton_ids, distance_breaks, dot_breaks,
                    tangent_neighbors=tangent_neighbors)
            return Response(serialize_config(config))
        elif source == 'backend-random':
            matching_skeleton_ids = get_request_list(request.data,
                    'matching_skeleton_ids', map_fn=int)
            n_random_skeletons = int(request.data.get('n_random_skeletons', 5000))
            if not matching_skeleton_ids:
                raise ValueError("Need matching_skeleton_ids")

            # Cancel if user isn't allowed to queue computation tasks
            p = Project.objects.get(pk=project_id)
            has_role = check_user_role(request.user, p, UserRole.QueueComputeTask)
            if not has_role:
                raise PermissionError("User " + str(request.user.id) +
                        " doesn't have permission to queue computation tasks.")

            config = self.compute_random_and_add_delayed(
                project_id, user_id, name, matching_skeleton_ids,
                distance_breaks, dot_breaks, None, None,
                n_random_skeletons, min_length, tangent_neighbors)
            return Response(serialize_config(config))
        else:
            raise ValueError("Unknown source: " + source)