def _register_index(self): """ Call the "signpost" (index client) for the transaction to register a new index record for this entity. """ project_id = self.transaction.project_id submitter_id = self.node._props.get("submitter_id") hashes = {"md5": self.node._props.get("md5sum")} size = self.node._props.get("file_size") alias = "{}/{}".format(project_id, submitter_id) project = utils.lookup_project( self.transaction.db_driver, self.transaction.program, self.transaction.project, ) if utils.is_project_public(project): acl = ["*"] else: acl = self.transaction.get_phsids() urls = [] if self.urls: urls.extend(self.urls) # IndexClient doc = self._create_index( did=self.file_index, hashes=hashes, size=size, urls=urls, acl=acl ) if self.use_object_id(self.entity_type): self.object_id = str(doc.did) self.node._props["object_id"] = self.object_id self._create_alias(record=alias, hashes=hashes, size=size, release="private")
def _register_index(self): """ Call the "signpost" (index client) for the transaction to register a new index record for this entity. """ project_id = self.transaction.project_id submitter_id = self.node._props.get('submitter_id') hashes = {'md5': self.node._props.get('md5sum')} size = self.node._props.get('file_size') alias = "{}/{}".format(project_id, submitter_id) project = utils.lookup_project( self.transaction.db_driver, self.transaction.program, self.transaction.project ) if utils.is_project_public(project): acl = ['*'] else: acl = self.transaction.get_phsids() urls = [] if self.urls: urls.extend(self.urls) # IndexClient self._create_index(did=self.file_index, hashes=hashes, size=size, urls=urls, acl=acl) self._create_alias( record=alias, hashes=hashes, size=size, release='private' )
def delete_project(program, project): """ Delete project under a specific program Summary: Delete a project Tags: project Args: program (str): |program_id| project (str): |project_id| Responses: 204: Success. 400: User error. 404: Resource not found. 403: Unauthorized request. """ with flask.current_app.db.session_scope() as session: node = utils.lookup_project(flask.current_app.db, program, project) if node.edges_in: raise UserError("ERROR: Can not delete the project.\ Project {} is not empty".format(project)) transaction_args = dict(program=program, project=project, flask_config=flask.current_app.config) with (transactions.deletion.transaction.DeletionTransaction( **transaction_args)) as trans: session.delete(node) trans.claim_transaction_log() trans.write_transaction_log() session.commit() return flask.jsonify(trans.json), 204
def take_action(self): """Attempt to transition the current project state to ``release``.""" project = utils.lookup_project(self.db_driver, self.program, self.project) if project.released: return self.record_error('Project is already released.') project.released = True self.commit(assert_has_entities=False)
def get_phsids(self): """Fetch the phsids for the current project.""" project = utils.lookup_project(self.db_driver, self.program, self.project) program = project.programs[0] numbers = [ project.dbgap_accession_number, program.dbgap_accession_number ] return [n for n in numbers if n is not None]
def _register_index(self): """ Call the index client for the transaction to register a new index record for this entity. """ project_id = self.transaction.project_id submitter_id = self.node._props.get("submitter_id") hashes = {"md5": self.node._props.get("md5sum")} size = self.node._props.get("file_size") alias = "{}/{}".format(project_id, submitter_id) project = utils.lookup_project( self.transaction.db_driver, self.transaction.program, self.transaction.project, ) if utils.is_project_public(project): acl = ["*"] else: acl = self.transaction.get_phsids() urls = [] if self.urls: urls.extend(self.urls) namespace = flask.current_app.config.get("AUTH_NAMESPACE", "").rstrip("/") authz = [ "{}/programs/{}/projects/{}".format(namespace, self.transaction.program, self.transaction.project) ] use_consent_codes = (dictionary.schema.get(self.entity_type, {}).get( "properties", {}).get("consent_codes")) if use_consent_codes: consent_codes = self.node._props.get("consent_codes") if consent_codes: authz.extend("/consents/" + code for code in consent_codes) # IndexClient doc = self._create_index( did=self.file_index, hashes=hashes, size=size, urls=urls, acl=acl, authz=authz, ) if self.use_object_id(self.entity_type): self.object_id = str(doc.did) self.node._props["object_id"] = self.object_id self._create_alias(record=alias, hashes=hashes, size=size, release="private")
def assert_project_state(self): """Assert that the transaction is allowed given the Project.state.""" project = utils.lookup_project(self.db_driver, self.program, self.project) state = project.state if state not in self.REQUIRED_PROJECT_STATES: states = ' or '.join(self.REQUIRED_PROJECT_STATES) msg = ("Project is in state '{}', which prevents {}. In order to" " perform this action, the project must be in state <{}>.") raise UserError(msg.format(state, flask.request.path, states))
def take_action(self): """For the current project, attempt to transition all nodes from their current states to ``open`` :returns: None """ project = utils.lookup_project(self.db_driver, self.program, self.project) project.state = self.to_state self.commit(assert_has_entities=False)
def __init__(self, **kwargs): super(SubmissionTransaction, self).__init__(role='submit', **kwargs) if ROLE_SUBMIT not in self.user.roles.get(self.project_id, []): self.record_error( 'You do not have submit permission for project {}'.format( self.project_id), type=EntityErrors.INVALID_PERMISSIONS) return self.project_node = utils.lookup_project(self.db_driver, self.program, self.project)
def take_action(self): """Attempt to transition the current project state to ``release``.""" project = utils.lookup_project(self.db_driver, self.program, self.project) if project.released: return self.record_error("Project is already released.") if project.releasable is not True: message = "Project is not releasable. " "Project must be submitted at least once first." return self.record_error(message) project.released = True self.commit(assert_has_entities=False)
def __init__(self, smtp_conf=None, **kwargs): super(SubmissionTransaction, self).__init__(role='submit', **kwargs) self.app_config = capp.config if utils.should_send_email(self.app_config): self.smtp_conf = smtp_conf roles = get_program_project_roles(*self.project_id.split('-', 1)) if ROLE_SUBMIT not in roles: self.record_error( 'You do not have submit permission for project {}'.format( self.project_id), type=EntityErrors.INVALID_PERMISSIONS) return self.project_node = utils.lookup_project(self.db_driver, self.program, self.project)
def __init__(self, smtp_conf=None, **kwargs): super(SubmissionTransaction, self).__init__(role="submit", **kwargs) self.app_config = capp.config if utils.should_send_email(self.app_config): self.smtp_conf = smtp_conf try: program, project = self.transaction.project_id.split("-", 1) authorize(program, project, [ROLE_SUBMIT]) except AuthZError: return self.record_error( "You do not have submit permission for project {}".format( self.project_id), type=EntityErrors.INVALID_PERMISSIONS, ) self.project_node = utils.lookup_project(self.db_driver, self.program, self.project)
def delete_project(program, project): """ Delete project under a specific program """ auth.current_user.require_admin() with flask.current_app.db.session_scope() as session: node = utils.lookup_project(flask.current_app.db, program, project) if node.edges_in: raise UserError('ERROR: Can not delete the project.\ Project {} is not empty'.format(project)) transaction_args = dict(program=program, project=project, flask_config=flask.current_app.config) with (transactions.deletion.transaction.DeletionTransaction( **transaction_args)) as trans: session.delete(node) trans.claim_transaction_log() trans.write_transaction_log() session.commit() return flask.jsonify(trans.json), 204
def create_project(program): """ Register a project. The content of the request is a JSON containing the information describing a project. Authorization for registering projects is limited to administrative users. Summary: Create a project Tags: project Args: program (str): |program_id| body (schema_project): input body Responses: 200: Registered successfully. 400: User error. 404: Program not found. 403: Unauthorized request. :reqheader Content-Type: |reqheader_Content-Type| :reqheader Accept: |reqheader_Accept| :reqheader X-Auth-Token: |reqheader_X-Auth-Token| :resheader Content-Type: |resheader_Content-Type| Example: .. code-block:: http POST /v0/submission/CGCI/ HTTP/1.1 Host: example.com Content-Type: application/json X-Auth-Token: MIIDKgYJKoZIhvcNAQcC... Accept: application/json .. code-block:: JavaScript { "type": "project", "code": "BLGSP", "disease_type": "Burkitt Lymphoma", "name": "Burkitt Lymphoma Genome Sequencing Project", "primary_site": "Lymph Nodes", "dbgap_accession_number": "phs000527", "state": "active" } """ auth.current_user.require_admin() doc = utils.parse.parse_request_json() if not isinstance(doc, dict): raise UserError("Program endpoint only supports single documents") if doc.get("type") and doc.get("type") not in ["project"]: raise UserError( "Invalid post to program endpoint with type='{}'".format( doc.get("type"))) # Parse project.code project = doc.get("code") if not project: raise UserError("No project specified in key 'code'") project = project.encode("utf-8") # Parse dbgap accession number. phsid = doc.get("dbgap_accession_number") if not phsid: raise UserError("No dbGaP accesion number specified.") # Create base JSON document. base_doc = utils.parse.parse_request_json() with flask.current_app.db.session_scope() as session: program_node = utils.lookup_program(flask.current_app.db, program) if not program_node: raise NotFoundError("Program {} is not registered".format(program)) # Look up project node. node = utils.lookup_project(flask.current_app.db, program, project) if not node: # Create a new project node node_uuid = str(uuid.uuid5(PROJECT_SEED, project.encode("utf-8"))) if flask.current_app.db.nodes( models.Project).ids(node_uuid).first(): raise UserError( "ERROR: Project {} already exists in DB".format(project)) node = models.Project(node_uuid) # pylint: disable=not-callable node.programs = [program_node] action = "create" node.props["state"] = "open" else: action = "update" # silently drop system_properties base_doc.pop("type", None) base_doc.pop("state", None) base_doc.pop("released", None) node.props.update(base_doc) doc = dict( { "type": "project", "programs": { "id": program_node.node_id } }, **base_doc) # Create transaction transaction_args = dict( program=program, project=project, role=ROLES["UPDATE"], flask_config=flask.current_app.config, ) with UploadTransaction(**transaction_args) as trans: node = session.merge(node) session.commit() entity = UploadEntityFactory.create( trans, doc=None, config=flask.current_app.config) entity.action = action entity.doc = doc entity.entity_type = "project" entity.unique_keys = node._secondary_keys_dicts entity.node = node entity.entity_id = entity.node.node_id trans.entities = [entity] return flask.jsonify(trans.json)
def create_project(program): """ Register a project. The content of the request is a JSON containing the information describing a project. Authorization for registering projects is limited to administrative users. Args: program (str): |program_id| :reqheader Content-Type: |reqheader_Content-Type| :reqheader Accept: |reqheader_Accept| :reqheader X-Auth-Token: |reqheader_X-Auth-Token| :resheader Content-Type: |resheader_Content-Type| :statuscode 200: Registered successfully. :statuscode 404: Program not found. :statuscode 403: Unauthorized request. Example: .. code-block:: http POST /v0/submission/CGCI/ HTTP/1.1 Host: example.com Content-Type: application/json X-Auth-Token: MIIDKgYJKoZIhvcNAQcC... Accept: application/json .. code-block:: JavaScript { "type": "project", "code": "BLGSP", "disease_type": "Burkitt Lymphoma", "name": "Burkitt Lymphoma Genome Sequencing Project", "primary_site": "Lymph Nodes", "dbgap_accession_number": "phs000527", "state": "active" } """ auth.admin_auth() doc = utils.parse.parse_request_json() if not isinstance(doc, dict): raise UserError('Program endpoint only supports single documents') if doc.get('type') and doc.get('type') not in ['project']: raise UserError( "Invalid post to program endpoint with type='{}'".format( doc.get('type'))) # Parse project.code project = doc.get('code') if not project: raise UserError("No project specified in key 'code'") project = project.encode('utf-8') # Parse dbgap accession number. phsid = doc.get('dbgap_accession_number') if not phsid: raise UserError("No dbGaP accesion number specified.") # Create base JSON document. base_doc = utils.parse.parse_request_json() with flask.current_app.db.session_scope() as session: program_node = utils.lookup_program(flask.current_app.db, program) if not program_node: raise NotFoundError('Program {} is not registered'.format(program)) # Look up project node. node = utils.lookup_project(flask.current_app.db, program, project) if not node: # Create a new project node node_uuid = str(uuid.uuid5(PROJECT_SEED, project.encode('utf-8'))) node = models.Project(node_uuid) # pylint: disable=not-callable node.programs = [program_node] action = 'create' node.props['state'] = 'open' else: action = 'update' # silently drop system_properties base_doc.pop('type', None) base_doc.pop('state', None) base_doc.pop('released', None) node.props.update(base_doc) doc = dict( { 'type': 'project', 'programs': { 'id': program_node.node_id }, }, **base_doc) # Create transaction transaction_args = dict(program=program, project=project, role=ROLES['UPDATE'], flask_config=flask.current_app.config) with UploadTransaction(**transaction_args) as trans: node = session.merge(node) session.commit() entity = UploadEntityFactory.create( trans, doc=None, config=flask.current_app.config) entity.action = action entity.doc = doc entity.entity_type = 'project' entity.unique_keys = node._secondary_keys_dicts entity.node = node entity.entity_id = entity.node.node_id trans.entities = [entity] return flask.jsonify(trans.json)