예제 #1
0
    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")
예제 #2
0
    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'
        )
예제 #3
0
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
예제 #4
0
 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)
예제 #5
0
 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]
예제 #6
0
    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")
예제 #7
0
 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))
예제 #8
0
    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)
예제 #9
0
    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)
예제 #10
0
    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)
예제 #11
0
    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)
예제 #12
0
    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)
예제 #13
0
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
예제 #14
0
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)
예제 #15
0
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)