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, })
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)
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)
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)
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)
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)