def get_karton_analysis( db_object: Object, root_uid: Optional[str] = None) -> Optional[KartonAnalysis]: # Includes 'karton' permission check metakeys = db_object.get_metakeys(as_dict=True) if "karton" not in metakeys: return None if not root_uid: # Metakeys are ordered from oldest to latest one root_uid = metakeys["karton"][-1] elif root_uid not in metakeys["karton"]: # root_uid must occur in attributes to get the analysis status return None karton_config = KartonConfig(config.karton.config_path) karton_backend = KartonBackend(karton_config) karton_state = KartonState(karton_backend) if root_uid not in karton_state.analyses: return None if karton_state.analyses[root_uid].is_done: return None return karton_state.analyses[root_uid]
def get(self, identifier: str) -> Tuple[Dict[str, Any], int]: db_object = Object.access(identifier) if db_object is None: raise NotFound("Object not found") root_uid = request.args.get("root_uid") analysis = get_karton_analysis(db_object, root_uid) if analysis is None: return {"status": "finished"}, 200 else: queues = { queue_name: { "received_from": list(set( task.headers["origin"] for task in queue.pending_tasks )), "status": list(set( task.status.value for task in queue.pending_tasks )) } for queue_name, queue in analysis.pending_queues.items() } return { "status": "running", "last_update": analysis.last_update, "processing_in": queues }, 200
def put(self, type, parent, child): """ --- summary: Link existing objects description: | Add new relation between existing objects. Requires `adding_parents` capability. security: - bearerAuth: [] tags: - relations parameters: - in: path name: type schema: type: string enum: [file, config, blob, object] description: Type of parent object - in: path name: parent description: Identifier of the parent object required: true schema: type: string - in: path name: child description: Identifier of the child object required: true schema: type: string responses: 200: description: When relation was successfully added 403: description: When user doesn't have `adding_parents` capability. 404: description: | When one of objects doesn't exist or user doesn't have access to object. """ parent_object = access_object(type, parent) if parent_object is None: raise NotFound("Parent object not found") child_object = Object.access(child) if child_object is None: raise NotFound("Child object not found") child_object.add_parent(parent_object, commit=False) db.session.commit() logger.info( "Child added", extra={ "parent": parent_object.dhash, "child": child_object.dhash }, )
def delete(self, identifier): """ --- summary: Unmark favorite object description: | Unmark an object as a favorite for the user. Requires `personalize` capability. security: - bearerAuth: [] tags: - object parameters: - in: path name: identifier schema: type: string description: Object identifier responses: 200: description: Unmark favorite object 400: description: When request body is invalid 403: description: When user doesn't have `personalize` capability. 404: description: When object doesn't exist. 503: description: | Request canceled due to database statement timeout. """ user = g.auth_user favorite_object = Object.access(identifier) if favorite_object is None: raise NotFound("Object not found") if not favorite_object.favorite: logger.info( "Object is not marked as a favorite", extra={ "user": user.login, "object_id": identifier }, ) else: favorite_object.followers.remove(user) db.session.commit() logger.info( "Object unmarked as favorite", extra={ "user": user.login, "object_id": identifier }, )
def create_object(self, params): params = dict(params) # Validate parent object if params["parent"] is not None: if not g.auth_user.has_rights(Capabilities.adding_parents): raise Forbidden("You are not permitted to link with parent") parent_object = Object.access(params["parent"]) if parent_object is None: raise NotFound("Parent object not found") else: parent_object = None # Validate metakeys metakeys = params["metakeys"] for metakey in params["metakeys"]: key = metakey["key"] if not MetakeyDefinition.query_for_set(key).first(): raise NotFound( f"Metakey '{key}' not defined or insufficient " "permissions to set that one" ) # Validate upload_as argument share_with = get_shares_for_upload(params["upload_as"]) item, is_new = self._create_object(params, parent_object, share_with, metakeys) try: db.session.commit() if is_new: hooks.on_created_object(item) self.on_created(item) else: hooks.on_reuploaded_object(item) self.on_reuploaded(item) finally: item.release_after_upload() logger.info( f"{self.ObjectType.__name__} added", extra={"dhash": item.dhash, "is_new": is_new}, ) schema = self.ItemResponseSchema() return schema.dump(item)
def delete(self, identifier): """ --- summary: Unmark favorite object description: | Unmark an object as a favorite for the user. security: - bearerAuth: [] tags: - object parameters: - in: path name: identifier schema: type: string description: Object identifier responses: 200: description: Unmark favorite object 400: description: When request body is invalid 404: description: When object doesn't exist. """ user = g.auth_user favorite_object = Object.access(identifier) if favorite_object is None: raise NotFound("Object not found") if not favorite_object.favorite: logger.info('Object is not marked as a favorite', extra={ 'user': user.login, 'object_id': identifier }) else: favorite_object.followers.remove(user) db.session.commit() logger.info('Object unmarked as favorite', extra={ 'user': user.login, 'object_id': identifier })
def create_object(self, params): params = dict(params) # Validate parent object if params["parent"] is not None: if not g.auth_user.has_rights(Capabilities.adding_parents): raise Forbidden("You are not permitted to link with parent") parent_object = Object.access(params["parent"]) if parent_object is None: raise NotFound("Parent object not found") else: parent_object = None # Validate metakeys and Karton assignment analysis_id = params.get("karton_id") if params["metakeys"]: # If 'metakeys' are defined: keep legacy behavior if "attributes" in params and params["attributes"]: raise BadRequest( "'attributes' and 'metakeys' options can't be mixed") attributes = params["metakeys"] for attribute in params["metakeys"]: key = attribute["key"] if key == "karton": if analysis_id is not None: raise BadRequest( "You can't provide more than one Karton analysis identifier" ) try: analysis_id = UUID(attribute["value"]) except (ValueError, AttributeError): raise BadRequest( "'karton' attribute accepts only UUID values") elif not AttributeDefinition.query_for_set(key).first(): raise NotFound( f"Attribute '{key}' not defined or insufficient " "permissions to set that one") else: # If not, rely on 'attributes' attributes = params["attributes"] for attribute in params["attributes"]: key = attribute["key"] if not AttributeDefinition.query_for_set(key).first(): raise NotFound( f"Attribute '{key}' not defined or insufficient " "permissions to set that one") if analysis_id is not None: if not g.auth_user.has_rights(Capabilities.karton_assign): raise Forbidden( "You are not permitted to assign Karton analysis to object" ) # Validate upload_as argument share_with = get_shares_for_upload(params["upload_as"]) # Tags argument tags = params.get("tags") item, is_new = self._create_object(params, parent_object, share_with, attributes, analysis_id, tags) try: db.session.commit() if is_new: self.on_created(item, params) else: self.on_reuploaded(item, params) finally: item.release_after_upload() logger.info( f"{self.ObjectType.__name__} added", extra={ "dhash": item.dhash, "is_new": is_new }, ) schema = self.ItemResponseSchema() return schema.dump(item)
def get(self): """ --- summary: Search or list objects description: | Returns list of objects matching provided query, ordered from the latest one. Limited to 10 objects, use `older_than` parameter to fetch more. Don't rely on maximum count of returned objects because it can be changed/parametrized in future. security: - bearerAuth: [] tags: - object parameters: - in: query name: older_than schema: type: string description: | Fetch objects which are older than the object specified by identifier. Used for pagination required: false - in: query name: query schema: type: string description: Filter results using Lucene query required: false responses: 200: description: List of objects content: application/json: schema: ObjectListResponseSchema 400: description: | When wrong parameters were provided or syntax error occurred in Lucene query 404: description: When user doesn't have access to the `older_than` object 503: description: | Request canceled due to database statement timeout. """ if "page" in request.args: logger.warning("'%s' used legacy 'page' parameter", g.auth_user.login) obj = load_schema(request.args, ObjectListRequestSchema()) pivot_obj = None if obj["older_than"]: pivot_obj = Object.access(obj["older_than"]) if pivot_obj is None: raise NotFound( "Object specified in 'older_than' parameter not found") query = obj["query"] if query: try: db_query = SQLQueryBuilder().build_query( query, queried_type=self.ObjectType) except SQLQueryBuilderBaseException as e: raise BadRequest(str(e)) except ParseError as e: raise BadRequest(str(e)) else: db_query = db.session.query(self.ObjectType) db_query = db_query.filter(g.auth_user.has_access_to_object( Object.id)).order_by(Object.id.desc()) if pivot_obj: db_query = db_query.filter(Object.id < pivot_obj.id) # Legacy parameter - to be removed in the future elif obj["page"] is not None and obj["page"] > 1: db_query = db_query.offset((obj["page"] - 1) * 10) objects = db_query.limit(10).all() schema = self.ListResponseSchema() return schema.dump(objects, many=True)
def create_object(self, params): params = dict(params) # Validate parent object if params["parent"] is not None: if not g.auth_user.has_rights(Capabilities.adding_parents): raise Forbidden("You are not permitted to link with parent") parent_object = Object.access(params["parent"]) if parent_object is None: raise NotFound("Parent object not found") else: parent_object = None # Validate metakeys metakeys = params["metakeys"] for metakey in params["metakeys"]: key = metakey["key"] if not MetakeyDefinition.query_for_set(key).first(): raise NotFound(f"Metakey '{key}' not defined or insufficient " "permissions to set that one") # Validate upload_as argument upload_as = params["upload_as"] if upload_as == "*": # If '*' is provided: share with all user's groups except 'public' share_with = [ group for group in g.auth_user.groups if group.name != "public" ] else: share_group = Group.get_by_name(upload_as) # Does group exist? if share_group is None: raise NotFound(f"Group {upload_as} doesn't exist") # Has user access to group? if share_group not in g.auth_user.groups and not g.auth_user.has_rights( Capabilities.sharing_objects): raise NotFound(f"Group {upload_as} doesn't exist") # Is group pending? if share_group.pending_group is True: raise NotFound(f"Group {upload_as} is pending") share_with = [share_group, Group.get_by_name(g.auth_user.login)] item, is_new = self._create_object(params, parent_object, share_with, metakeys) db.session.commit() if is_new: hooks.on_created_object(item) self.on_created(item) else: hooks.on_reuploaded_object(item) self.on_reuploaded(item) logger.info(f'{self.ObjectType.__name__} added', extra={ 'dhash': item.dhash, 'is_new': is_new }) schema = self.ItemResponseSchema() return schema.dump(item)
def delete(self, type, parent, child): """ --- summary: Remove relation between existing objects description: | Remove relation between existing objects with permission inheritance. Requires `adding_parents` capability. security: - bearerAuth: [] tags: - relations parameters: - in: path name: type schema: type: string enum: [file, config, blob, object] description: Type of parent object - in: path name: parent description: Identifier of the parent object required: true schema: type: string - in: path name: child description: Identifier of the child object required: true schema: type: string responses: 200: description: When relation was successfully removed. 403: description: When user doesn't have `removing_parents` capability. 404: description: | When one of objects doesn't exist or user doesn't have access to object. 503: description: | Request canceled due to database statement timeout. """ parent_object = access_object(type, parent) if parent_object is None: raise NotFound("Parent object not found") child_object = Object.access(child) if child_object is None: raise NotFound("Child object not found") result = child_object.remove_parent(parent_object) if not result: # Relation already removed return hooks.on_removed_relation(parent_object, child_object) if parent_object.id != child_object.id: hooks.on_changed_object(parent_object) hooks.on_changed_object(child_object) else: hooks.on_changed_object(parent_object) logger.info( "Child removed", extra={ "parent": parent_object.dhash, "child": child_object.dhash }, )