示例#1
0
async def list_catalog_records(
        record_id: str,
        auth: Authorized = Depends(Authorize(ODPScope.RECORD_READ)),
        paginator: Paginator = Depends(),
):
    if not (record := Session.get(Record, record_id)):
        raise HTTPException(HTTP_404_NOT_FOUND)
示例#2
0
def _delete_record(
    record_id: str,
    auth: Authorized,
    ignore_collection_tags: bool = False,
) -> None:
    if not (record := Session.get(Record, record_id)):
        raise HTTPException(HTTP_404_NOT_FOUND)
示例#3
0
async def tag_record(
        record_id: str,
        tag_instance_in: TagInstanceModelIn,
        tag_schema: JSONSchema = Depends(get_tag_schema),
        auth: Authorized = Depends(TagAuthorize()),
):
    if not (record := Session.get(Record, record_id)):
        raise HTTPException(HTTP_404_NOT_FOUND)
示例#4
0
def _untag_record(
    record_id: str,
    tag_instance_id: str,
    auth: Authorized,
    ignore_user_id: bool = False,
) -> None:
    if not (record := Session.get(Record, record_id)):
        raise HTTPException(HTTP_404_NOT_FOUND)
示例#5
0
async def get_catalog_record(
        record_id: str,
        catalog_id: str,
        auth: Authorized = Depends(Authorize(ODPScope.RECORD_READ)),
):
    if not (catalog_record := Session.get(CatalogRecord,
                                          (catalog_id, record_id))):
        raise HTTPException(HTTP_404_NOT_FOUND)
示例#6
0
    def login_callback(self):
        """Save the token and log the user in."""
        token = self.oauth.hydra.authorize_access_token()
        userinfo = self.oauth.hydra.userinfo()
        user_id = userinfo['sub']

        if not (token_model := Session.get(OAuth2Token, (self.client_id, user_id))):
            token_model = OAuth2Token(client_id=self.client_id, user_id=user_id)
async def update_collection(
        collection_in: CollectionModelIn,
        auth: Authorized = Depends(Authorize(ODPScope.COLLECTION_ADMIN)),
):
    if auth.collection_ids != '*' and collection_in.id not in auth.collection_ids:
        raise HTTPException(HTTP_403_FORBIDDEN)

    if not (collection := Session.get(Collection, collection_in.id)):
        raise HTTPException(HTTP_404_NOT_FOUND)
示例#8
0
async def update_client(
        client_in: ClientModelIn,
        auth: Authorized = Depends(Authorize(ODPScope.CLIENT_ADMIN)),
):
    if auth.collection_ids != '*' and client_in.collection_id not in auth.collection_ids:
        raise HTTPException(HTTP_403_FORBIDDEN)

    if not (client := Session.get(Client, client_in.id)):
        raise HTTPException(HTTP_404_NOT_FOUND)
示例#9
0
async def update_role(
        role_in: RoleModelIn,
        auth: Authorized = Depends(Authorize(ODPScope.ROLE_ADMIN)),
):
    if auth.collection_ids != '*' and role_in.collection_id not in auth.collection_ids:
        raise HTTPException(HTTP_403_FORBIDDEN)

    if not (role := Session.get(Role, role_in.id)):
        raise HTTPException(HTTP_404_NOT_FOUND)
示例#10
0
def init_roles():
    """Create or update role definitions."""
    with open(datadir / 'roles.yml') as f:
        role_data = yaml.safe_load(f)

    for role_id, role_spec in role_data.items():
        role = Session.get(Role, role_id) or Role(id=role_id)
        role.scopes = [Session.get(Scope, (scope_id, ScopeType.odp)) for scope_id in role_spec['scopes']]
        role.save()
示例#11
0
async def get_new_doi(
        collection_id: str,
        auth: Authorized = Depends(Authorize(ODPScope.COLLECTION_READ)),
):
    if auth.collection_ids != '*' and collection_id not in auth.collection_ids:
        raise HTTPException(HTTP_403_FORBIDDEN)

    if not (collection := Session.get(Collection, collection_id)):
        raise HTTPException(HTTP_404_NOT_FOUND)
示例#12
0
def _untag_collection(
    collection_id: str,
    tag_instance_id: str,
    auth: Authorized,
    ignore_user_id: bool = False,
) -> None:
    if auth.collection_ids != '*' and collection_id not in auth.collection_ids:
        raise HTTPException(HTTP_403_FORBIDDEN)

    if not (collection := Session.get(Collection, collection_id)):
        raise HTTPException(HTTP_404_NOT_FOUND)
示例#13
0
async def update_record(
        record_id: str,
        record_in: RecordModelIn,
        metadata_schema: JSONSchema = Depends(get_metadata_schema),
        auth: Authorized = Depends(Authorize(ODPScope.RECORD_WRITE)),
):
    if auth.collection_ids != '*' and record_in.collection_id not in auth.collection_ids:
        raise HTTPException(HTTP_403_FORBIDDEN)

    if not (record := Session.get(Record, record_id)):
        raise HTTPException(HTTP_404_NOT_FOUND)
示例#14
0
async def tag_collection(
        collection_id: str,
        tag_instance_in: TagInstanceModelIn,
        tag_schema: JSONSchema = Depends(get_tag_schema),
        auth: Authorized = Depends(TagAuthorize()),
):
    if auth.collection_ids != '*' and collection_id not in auth.collection_ids:
        raise HTTPException(HTTP_403_FORBIDDEN)

    if not (collection := Session.get(Collection, collection_id)):
        raise HTTPException(HTTP_404_NOT_FOUND)
示例#15
0
def init_cli_client():
    """Create or update the Swagger UI client."""
    client = Session.get(Client, ODP_CLI_CLIENT_ID) or Client(id=ODP_CLI_CLIENT_ID)
    client.scopes = [Session.get(Scope, (s.value, ScopeType.odp)) for s in ODPScope]
    client.save()

    hydra_admin_api.create_or_update_client(
        id=ODP_CLI_CLIENT_ID,
        name=ODP_CLI_CLIENT_NAME,
        secret=ODP_CLI_CLIENT_SECRET,
        scope_ids=[s.value for s in ODPScope],
        grant_types=[GrantType.CLIENT_CREDENTIALS],
    )
示例#16
0
async def create_project(
        project_in: ProjectModelIn,
):
    if Session.get(Project, project_in.id):
        raise HTTPException(HTTP_409_CONFLICT, 'Project id is already in use')

    project = Project(
        id=project_in.id,
        name=project_in.name,
        collections=[
            Session.get(Collection, collection_id)
            for collection_id in project_in.collection_ids
        ],
    )
    project.save()
示例#17
0
def validate_auto_login(user_id):
    """
    Validate a login request for which Hydra has indicated that the user is already authenticated,
    returning the user object on success. An ``ODPIdentityError`` is raised if the login cannot be
    permitted for any reason.

    :param user_id: the user id

    :raises ODPUserNotFound: if the user account associated with this id has been deleted
    :raises ODPAccountLocked: if the user account has been temporarily locked
    :raises ODPAccountDisabled: if the user account has been deactivated
    :raises ODPEmailNotVerified: if the user changed their email address since their last login,
        but have not yet verified it
    """
    user = Session.get(User, user_id)
    if not user:
        raise x.ODPUserNotFound

    if is_account_locked(user_id):
        raise x.ODPAccountLocked

    if not user.active:
        raise x.ODPAccountDisabled

    if not user.verified:
        raise x.ODPEmailNotVerified
示例#18
0
def init_dap_client():
    """Create or update the Data Access Portal client."""
    client = Session.get(Client, ODP_UI_DAP_CLIENT_ID) or Client(id=ODP_UI_DAP_CLIENT_ID)
    client.scopes = [Session.get(Scope, (HydraScope.OPENID, ScopeType.oauth))] + \
                    [Session.get(Scope, (HydraScope.OFFLINE_ACCESS, ScopeType.oauth))]
    client.save()

    hydra_admin_api.create_or_update_client(
        id=ODP_UI_DAP_CLIENT_ID,
        name=ODP_UI_DAP_CLIENT_NAME,
        secret=ODP_UI_DAP_CLIENT_SECRET,
        scope_ids=[HydraScope.OPENID, HydraScope.OFFLINE_ACCESS],
        grant_types=[GrantType.AUTHORIZATION_CODE, GrantType.REFRESH_TOKEN],
        response_types=[ResponseType.CODE],
        redirect_uris=[ODP_UI_DAP_LOGGED_IN_URL],
        post_logout_redirect_uris=[ODP_UI_DAP_LOGGED_OUT_URL],
    )
示例#19
0
    def _select_records(self) -> list[tuple[str, datetime]]:
        """Select records to be evaluated for publication to, or
        retraction from, a catalog.

        A record is selected if:

        * there is no corresponding catalog_record entry; or
        * the record has any embargo tags; or
        * catalog_record.timestamp is less than any of the following:

          * catalog.schema.timestamp
          * collection.timestamp
          * record.timestamp

        :return: a list of (record_id, timestamp) tuples, where
            timestamp is that of the latest contributing change
        """
        catalog = Session.get(Catalog, self.catalog_id)

        records_subq = (
            select(
                Record.id.label('record_id'),
                func.greatest(
                    catalog.schema.timestamp,
                    Collection.timestamp,
                    Record.timestamp,
                ).label('max_timestamp')
            ).
            join(Collection).
            subquery()
        )

        catalog_records_subq = (
            select(
                CatalogRecord.record_id,
                CatalogRecord.timestamp
            ).
            where(CatalogRecord.catalog_id == self.catalog_id).
            subquery()
        )

        stmt = (
            select(
                records_subq.c.record_id,
                records_subq.c.max_timestamp
            ).
            outerjoin_from(records_subq, catalog_records_subq).
            where(or_(
                catalog_records_subq.c.record_id == None,
                catalog_records_subq.c.timestamp < records_subq.c.max_timestamp,
                catalog_records_subq.c.record_id.in_(
                    select(RecordTag.record_id).
                    where(RecordTag.tag_id == ODPRecordTag.EMBARGO)
                )
            ))
        )

        return Session.execute(stmt).all()
示例#20
0
def get_user_profile(user_id):
    """
    Return a dict of user profile info.
    """
    user = Session.get(User, user_id)
    info = {}
    for attr in 'name', 'picture':
        info[attr] = getattr(user, attr)
    return info
示例#21
0
async def create_provider(provider_in: ProviderModelIn, ):
    if Session.get(Provider, provider_in.id):
        raise HTTPException(HTTP_409_CONFLICT, 'Provider id is already in use')

    provider = Provider(
        id=provider_in.id,
        name=provider_in.name,
    )
    provider.save()
示例#22
0
def update_user_verified(user_id, verified):
    """
    Update the verified status of a user.

    :param user_id: the user id
    :param verified: True/False
    """
    user = Session.get(User, user_id)
    user.verified = verified
    user.save()
示例#23
0
def update_user_password(user_id, password):
    """
    Update a user's password.

    :param user_id: the user id
    :param password: the input plain-text password
    """
    user = Session.get(User, user_id)
    user.password = ph.hash(password)
    user.save()
示例#24
0
def init_catalogs():
    """Create or update catalog definitions."""
    with open(datadir / 'catalogs.yml') as f:
        catalog_data = yaml.safe_load(f)

    for catalog_id in (catalog_ids := [c.value for c in ODPCatalog]):
        catalog_spec = catalog_data[catalog_id]
        catalog = Session.get(Catalog, catalog_id) or Catalog(id=catalog_id)
        catalog.schema_id = catalog_spec['schema_id']
        catalog.schema_type = SchemaType.catalog
        catalog.save()
示例#25
0
def new_generic_tag(cardinality):
    return TagFactory(
        type='record',
        cardinality=cardinality,
        scope=Session.get(Scope, (ODPScope.RECORD_QC, ScopeType.odp))
        or Scope(id=ODPScope.RECORD_QC, type=ScopeType.odp),
        schema=SchemaFactory(
            type='tag',
            uri='https://odp.saeon.ac.za/schema/tag/generic',
        ),
    )
示例#26
0
def new_generic_tag(cardinality):
    # we can use any scope; just make it something other than COLLECTION_ADMIN
    return TagFactory(
        type='collection',
        cardinality=cardinality,
        scope=Session.get(Scope, (ODPScope.COLLECTION_READ, ScopeType.odp))
        or Scope(id=ODPScope.COLLECTION_READ, type=ScopeType.odp),
        schema=SchemaFactory(
            type='tag',
            uri='https://odp.saeon.ac.za/schema/tag/generic',
        ),
    )
示例#27
0
    def _evaluate_record(self, record_id: str, timestamp: datetime) -> bool:
        """Evaluate a record model (API) against the publication schema for
        a catalog, and commit the result to the catalog_record table.

        The catalog_record entry is stamped with the `timestamp` of the latest
        contributing change (from catalog/record/record_tag/collection_tag).
        """
        catalog = Session.get(Catalog, self.catalog_id)
        record = Session.get(Record, record_id)
        catalog_record = (Session.get(CatalogRecord, (self.catalog_id, record_id)) or
                          CatalogRecord(catalog_id=self.catalog_id, record_id=record_id))

        record_model = output_record_model(record)
        record_json = JSON(record_model.dict())

        publication_schema = schema_catalog.get_schema(URI(catalog.schema.uri))

        if (result := publication_schema.evaluate(record_json)).valid:
            catalog_record.validity = result.output('flag')
            catalog_record.published = True
            catalog_record.published_record = self._create_published_record(record_model).dict()
            self._save_published_doi(record_model)
示例#28
0
def update_user_profile(user_id, **userinfo):
    """
    Update optional user profile info.

    Only update user attributes that are supplied in the dict.

    :param user_id: the user id
    :param userinfo: dict containing profile info
    """
    user = Session.get(User, user_id)
    for attr in 'name', 'picture':
        if attr in userinfo:
            setattr(user, attr, userinfo[attr])
    user.save()
示例#29
0
async def list_published_records(
        catalog_id: str,
        paginator: Paginator = Depends(),
):
    if not Session.get(Catalog, catalog_id):
        raise HTTPException(HTTP_404_NOT_FOUND)

    stmt = (select(CatalogRecord).where(
        CatalogRecord.catalog_id == catalog_id).where(CatalogRecord.published))
    paginator.sort = 'record_id'

    return paginator.paginate(
        stmt,
        lambda row: PublishedRecordModel(**row.CatalogRecord.published_record),
    )
示例#30
0
def init_tags():
    """Create or update tag definitions."""
    with open(datadir / 'tags.yml') as f:
        tag_data = yaml.safe_load(f)

    for tag_id in (tag_ids := [t.value for t in ODPRecordTag] + [t.value for t in ODPCollectionTag]):
        tag_spec = tag_data[tag_id]
        tag_type = tag_spec['type']
        tag = Session.get(Tag, (tag_id, tag_type)) or Tag(id=tag_id, type=tag_type)
        tag.cardinality = tag_spec['cardinality']
        tag.public = tag_spec['public']
        tag.scope_id = tag_spec['scope_id']
        tag.scope_type = ScopeType.odp
        tag.schema_id = tag_spec['schema_id']
        tag.schema_type = SchemaType.tag
        tag.save()