def handle_single_transaction(role, program, project, **tx_kwargs): """ Main entry point for single file transactions. This function multiplexes on the content-type to call the appropriate transaction handler. """ doc = flask.request.get_data().decode("utf-8") content_type = flask.request.headers.get("Content-Type", "").lower() if content_type == "text/csv": doc_format = "csv" data, errors = utils.transforms.CSVToJSONConverter().convert(doc) elif content_type in ["text/tab-separated-values", "text/tsv"]: doc_format = "tsv" data, errors = utils.transforms.TSVToJSONConverter().convert(doc) else: doc_format = "json" data = utils.parse.parse_request_json() errors = None # TODO: use errors value? name = flask.request.headers.get("X-Document-Name", None) doc_args = [name, doc_format, doc, data] is_async = tx_kwargs.pop("is_async", utils.is_flag_set(FLAG_IS_ASYNC)) db_driver = tx_kwargs.pop("db_driver", flask.current_app.db) transaction = UploadTransaction( program=program, project=project, role=role, logger=flask.current_app.logger, flask_config=flask.current_app.config, index_client=flask.current_app.index_client, external_proxies=utils.get_external_proxies(), db_driver=db_driver, **tx_kwargs) if is_async: session = transaction.db_driver.session_scope(can_inherit=False) with session, transaction: response = { "code": 200, "message": "Transaction submitted.", "transaction_id": transaction.transaction_id, } flask.current_app.async_pool.schedule(single_transaction_worker, transaction, *doc_args) # create the resource in arborist auth.create_resource(program, project, doc_args[3]) return flask.jsonify(response) else: response, code = single_transaction_worker(transaction, *doc_args) # create the resource in arborist auth.create_resource(program, project, doc_args[3]) return flask.jsonify(response), code
def handle_single_transaction(role, program, project, **tx_kwargs): """ Main entry point for single file transactions. This function multiplexes on the content-type to call the appropriate transaction handler. """ doc = flask.request.get_data() content_type = flask.request.headers.get('Content-Type', '').lower() if content_type == 'text/csv': doc_format = 'csv' data, errors = utils.transforms.CSVToJSONConverter().convert(doc) elif content_type in ['text/tab-separated-values', 'text/tsv']: doc_format = 'tsv' data, errors = utils.transforms.TSVToJSONConverter().convert(doc) else: doc_format = 'json' data = utils.parse.parse_request_json() errors = None # TODO: use errors value? name = flask.request.headers.get('X-Document-Name', None) doc_args = [name, doc_format, doc, data] is_async = tx_kwargs.pop('is_async', utils.is_flag_set(FLAG_IS_ASYNC)) db_driver = tx_kwargs.pop('db_driver', flask.current_app.db) transaction = UploadTransaction(program=program, project=project, role=role, user=flask.g.user, logger=flask.current_app.logger, flask_config=flask.current_app.config, signpost=flask.current_app.signpost, external_proxies=utils.get_external_proxies(), db_driver=db_driver, **tx_kwargs) if is_async: session = transaction.db_driver.session_scope(can_inherit=False) with session, transaction: response = { "code": 200, "message": "Transaction submitted.", "transaction_id": transaction.transaction_id, } flask.current_app.async_pool.schedule( single_transaction_worker, transaction, *doc_args ) return flask.jsonify(response) else: response, code = single_transaction_worker(transaction, *doc_args) return flask.jsonify(response), code
def _single_transaction(role, program, project, *doc_args, **tx_kwargs): """ Create and execute a single (not bulk) transaction. Most non-bulk variations of upload actions (based on content-type, etc.) should wrap this function. Return: Tuple[flask.Response, int]: (API response json, status code) """ is_async = tx_kwargs.pop('is_async', utils.is_flag_set(FLAG_IS_ASYNC)) db_driver = tx_kwargs.pop('db_driver', flask.current_app.db) transaction = UploadTransaction( program=program, project=project, role=role, user=flask.g.user, logger=flask.current_app.logger, signpost=flask.current_app.signpost, flask_config=flask.current_app.config, db_driver=db_driver, external_proxies=utils.get_external_proxies(), **tx_kwargs ) if is_async: session = transaction.db_driver.session_scope(can_inherit=False) with session, transaction: response = { "code": 200, "message": "Transaction submitted.", "transaction_id": transaction.transaction_id, } flask.current_app.async_pool.schedule( single_transaction_worker, transaction, *doc_args ) return flask.jsonify(response) else: response, code = single_transaction_worker(transaction, *doc_args) return flask.jsonify(response), code
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)