Skip to content

oarepo_oaipmh_harvester.oai_record.service

oarepo_oaipmh_harvester.oai_record.service

Service for OAI-PMH harvested records.

OAIRecordSearchOptions

Bases: SearchOptions, SearchOptionsMixin

Search options for harvest records.

Source code in oarepo_oaipmh_harvester/oai_record/service.py
class OAIRecordSearchOptions(SearchOptions, SearchOptionsMixin):
    """Search options for harvest records."""

    pagination_options: Mapping[str, Any] = {
        "default_results_per_page": 25,
        "default_max_results": 10000,
    }

    suggest_parser_cls = SuggestQueryParser.factory(
        fields=["oai_identifier^2", "harvester_id^2", "title^3"],
        type="most_fields",
        fuzziness="AUTO",
    )

    params_interpreters_cls = (
        QueryStrParam,
        SortParam,
        PaginationParam,
        FacetsParam,
    )

    facets: Mapping[str, Any] = {
        "harvester": facets.harvester,
        "deleted": facets.deleted,
        "has_errors": facets.has_errors,
        "error_code": facets.error_code,
        "error_message": facets.error_message,
        "error_location": facets.error_location,
    }

Bases: Link

Short cut for writing record links.

Source code in oarepo_oaipmh_harvester/oai_record/service.py
class RecordLink(Link):
    """Short cut for writing record links."""

    @staticmethod
    def vars(record: Any, link_vars: dict) -> None:
        """Variables for the URI template."""
        # Some records don't have record.pid.pid_value yet (e.g. drafts)
        link_vars.update({"id": record.id})

vars(record: Any, link_vars: dict) -> None staticmethod

Variables for the URI template.

Source code in oarepo_oaipmh_harvester/oai_record/service.py
@staticmethod
def vars(record: Any, link_vars: dict) -> None:
    """Variables for the URI template."""
    # Some records don't have record.pid.pid_value yet (e.g. drafts)
    link_vars.update({"id": record.id})

OAIRecordServiceConfig

Bases: RecordServiceConfig, ConfiguratorMixin

Harvest record service configuration.

Source code in oarepo_oaipmh_harvester/oai_record/service.py
class OAIRecordServiceConfig(RecordServiceConfig, ConfiguratorMixin):
    """Harvest record service configuration."""

    # common configuration
    permission_policy_cls = OAIRecordPermissionPolicy
    result_item_cls = OAIRecordItem
    result_list_cls = OAIRecordList

    search = OAIRecordSearchOptions

    service_id = "oai-harvest-record"
    record_cls = OAIRecordAggregate
    schema = cast(
        "type[ma.Schema]",
        FromConfig("OAI_RECORD_SERVICE_SCHEMA", OAIHarvestedRecordSchema),
    )
    indexer_queue_name = "oai-harvest-record"
    index_dumper = None

    # links configuration
    links_item: Mapping[str, Any] = {
        "self": Link("{+api}/oai/harvest/records/{id}"),
        "actions": ActionLinks(
            {
                "harvest": RecordLink(
                    "{+api}/oai/harvest/records/{id}/harvest",
                ),
            }
        ),
    }
    links_search_item: Mapping[str, Any] = {
        "self": Link("{+api}/oai/harvest/records/{id}"),
        "actions": ActionLinks(
            {
                "harvest": RecordLink(
                    "{+api}/oai/harvest/records/{id}/harvest",
                ),
            }
        ),
    }
    links_search = pagination_links("{+api}/oai/harvest/records{?args*}")

    components = ()

OAIRecordService

Bases: RecordService

Service for harvested OAI-PMH records.

Source code in oarepo_oaipmh_harvester/oai_record/service.py
class OAIRecordService(RecordService):
    """Service for harvested OAI-PMH records."""

    @property
    def oai_record_cls(self) -> type[OAIRecordAggregate]:
        """Alias for record_cls."""
        return cast("type[OAIRecordAggregate]", self.record_cls)

    @override
    def search(
        self,
        identity: Identity,
        params: dict[str, Any] | None = None,
        search_preference: str | None = None,
        expand: bool = False,
        **kwargs: Any,
    ) -> RecordList:
        """Search harvest records."""
        self.require_permission(identity, "search")

        return super().search(
            identity,
            params=params,
            search_preference=search_preference,
            search_opts=self.config.search,
            permission_action="read",
            expand=expand,
            **kwargs,
        )

    @override
    def read(
        self,
        identity: Identity,
        id_: str,
        expand: bool = False,
        action: str = "read",
        **kwargs: Any,
    ) -> RecordItem:
        """Retrieve a single harvest record."""
        # resolve and require permission
        oai_record = OAIRecordAggregate.get_record(id_)
        if oai_record is None:
            raise PermissionDeniedError

        self.require_permission(identity, "read", record=oai_record)

        # record components
        for component in self.components:
            if hasattr(component, "read"):
                component.read(identity, oai_record=oai_record)

        return self.result_item(self, identity, oai_record, links_tpl=self.links_item_tpl)

    @override
    def rebuild_index(self, identity: Identity, uow: UnitOfWork | None = None) -> bool:
        """Reindex all harvest records."""
        oai_records = db.session.query(OAIHarvestedRecord.oai_identifier).yield_per(1000)
        self.indexer.bulk_index([u.oai_identifier for u in oai_records])
        return True

    def harvest(self, identity: Identity, id_: str) -> RecordItem:
        """Re-harvest a single record from its source."""
        # resolve and require permission
        oai_record = OAIRecordAggregate.get_record(id_)
        if oai_record is None:
            raise PermissionDeniedError

        self.require_permission(identity, "run_harvest", record=oai_record)

        from ..tasks import harvest_oaipmh_records

        # Fire-and-forget: we do not need the result of the Celery task here.
        harvest_oaipmh_records.delay(harvester_id=oai_record.harvester.id, oai_ids=[id_])

        # re-get the record
        oai_record = OAIRecordAggregate.get_record(id_)

        return self.result_item(self, identity, oai_record, links_tpl=self.links_item_tpl)

oai_record_cls: type[OAIRecordAggregate] property

Alias for record_cls.

search(identity: Identity, params: dict[str, Any] | None = None, search_preference: str | None = None, expand: bool = False, **kwargs: Any) -> RecordList

Search harvest records.

Source code in oarepo_oaipmh_harvester/oai_record/service.py
@override
def search(
    self,
    identity: Identity,
    params: dict[str, Any] | None = None,
    search_preference: str | None = None,
    expand: bool = False,
    **kwargs: Any,
) -> RecordList:
    """Search harvest records."""
    self.require_permission(identity, "search")

    return super().search(
        identity,
        params=params,
        search_preference=search_preference,
        search_opts=self.config.search,
        permission_action="read",
        expand=expand,
        **kwargs,
    )

read(identity: Identity, id_: str, expand: bool = False, action: str = 'read', **kwargs: Any) -> RecordItem

Retrieve a single harvest record.

Source code in oarepo_oaipmh_harvester/oai_record/service.py
@override
def read(
    self,
    identity: Identity,
    id_: str,
    expand: bool = False,
    action: str = "read",
    **kwargs: Any,
) -> RecordItem:
    """Retrieve a single harvest record."""
    # resolve and require permission
    oai_record = OAIRecordAggregate.get_record(id_)
    if oai_record is None:
        raise PermissionDeniedError

    self.require_permission(identity, "read", record=oai_record)

    # record components
    for component in self.components:
        if hasattr(component, "read"):
            component.read(identity, oai_record=oai_record)

    return self.result_item(self, identity, oai_record, links_tpl=self.links_item_tpl)

rebuild_index(identity: Identity, uow: UnitOfWork | None = None) -> bool

Reindex all harvest records.

Source code in oarepo_oaipmh_harvester/oai_record/service.py
@override
def rebuild_index(self, identity: Identity, uow: UnitOfWork | None = None) -> bool:
    """Reindex all harvest records."""
    oai_records = db.session.query(OAIHarvestedRecord.oai_identifier).yield_per(1000)
    self.indexer.bulk_index([u.oai_identifier for u in oai_records])
    return True

harvest(identity: Identity, id_: str) -> RecordItem

Re-harvest a single record from its source.

Source code in oarepo_oaipmh_harvester/oai_record/service.py
def harvest(self, identity: Identity, id_: str) -> RecordItem:
    """Re-harvest a single record from its source."""
    # resolve and require permission
    oai_record = OAIRecordAggregate.get_record(id_)
    if oai_record is None:
        raise PermissionDeniedError

    self.require_permission(identity, "run_harvest", record=oai_record)

    from ..tasks import harvest_oaipmh_records

    # Fire-and-forget: we do not need the result of the Celery task here.
    harvest_oaipmh_records.delay(harvester_id=oai_record.harvester.id, oai_ids=[id_])

    # re-get the record
    oai_record = OAIRecordAggregate.get_record(id_)

    return self.result_item(self, identity, oai_record, links_tpl=self.links_item_tpl)