Skip to content

Commit

Permalink
collections: move records search into service
Browse files Browse the repository at this point in the history
* Added resource for collections
* Moved records search from community records to collections service
  • Loading branch information
alejandromumo committed Oct 31, 2024
1 parent 9e56947 commit 27eeac6
Show file tree
Hide file tree
Showing 18 changed files with 135 additions and 68 deletions.
7 changes: 7 additions & 0 deletions invenio_rdm_records/collections/resources/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2024 CERN.
#
# Invenio-RDM is free software; you can redistribute it and/or modify
# it under the terms of the MIT License; see LICENSE file for more details.
"""Collection resource module."""
50 changes: 50 additions & 0 deletions invenio_rdm_records/collections/resources/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2024 CERN.
#
# Invenio-RDM is free software; you can redistribute it and/or modify
# it under the terms of the MIT License; see LICENSE file for more details.
"""Collection resource config."""

from flask_resources import (
HTTPJSONException,
JSONSerializer,
ResourceConfig,
ResponseHandler,
create_error_handler,
)
from invenio_records_resources.resources.records.args import SearchRequestArgsSchema
from invenio_records_resources.resources.records.headers import etag_headers
from marshmallow.fields import Integer

from invenio_rdm_records.resources.serializers import UIJSONSerializer

from ..errors import CollectionNotFound


class CollectionsResourceConfig(ResourceConfig):
"""Configuration for the Collection resource."""

blueprint_name = "collections"
url_prefix = "/collections"

routes = {
"search-records": "/<id>/records",
}

request_view_args = {"id": Integer()}
request_search_args = SearchRequestArgsSchema
error_handlers = {
CollectionNotFound: create_error_handler(
HTTPJSONException(
code=404,
description="Collection was not found.",
)
),
}
response_handlers = {
"application/json": ResponseHandler(JSONSerializer(), headers=etag_headers),
"application/vnd.inveniordm.v1+json": ResponseHandler(
UIJSONSerializer(), headers=etag_headers
),
}
43 changes: 43 additions & 0 deletions invenio_rdm_records/collections/resources/resource.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2024 CERN.
#
# Invenio-RDM is free software; you can redistribute it and/or modify
# it under the terms of the MIT License; see LICENSE file for more details.
"""Collection resource."""

from flask import g
from flask_resources import Resource, resource_requestctx, response_handler, route
from invenio_records_resources.resources.records.resource import (
request_search_args,
request_view_args,
)


class CollectionsResource(Resource):
"""Collection resource."""

def __init__(self, config, service):
"""Instantiate the resource."""
super().__init__(config)
self.service = service

def create_url_rules(self):
"""Create the URL rules for the record resource."""
routes = self.config.routes
return [
route("GET", routes["search-records"], self.search_records),
]

@request_view_args
@request_search_args
@response_handler(many=True)
def search_records(self):
"""Search records in a collection."""
id_ = resource_requestctx.view_args["id"]
records = self.service.search_collection_records(
g.identity,
id_,
params=resource_requestctx.args,
)
return records.to_dict(), 200
5 changes: 0 additions & 5 deletions invenio_rdm_records/collections/searchapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,5 @@ def search_app_context():
sort_options=current_app.config["RDM_SORT_OPTIONS"],
headers={"Accept": "application/vnd.inveniordm.v1+json"},
pagination_options=(10, 25, 50, 100),
# endpoint=/communities/eu/records
# endpoint=/api/records
# hidden_params=[
# ["q", collection.query]
# ]
)
}
7 changes: 7 additions & 0 deletions invenio_rdm_records/collections/services/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2024 CERN.
#
# Invenio-RDM is free software; you can redistribute it and/or modify
# it under the terms of the MIT License; see LICENSE file for more details.
"""Collection service module."""
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,7 @@ class CollectionServiceConfig(ServiceConfig, ConfiguratorMixin):
schema = CollectionSchema

links_item = {
"search": ConditionalLink(
cond=lambda coll, ctx: coll.community,
if_=CollectionLink("/api/communities/{community}/records"),
else_="/api/records",
),
"search": CollectionLink("/api/collections/{id}/records"),
"self_html": ConditionalLink(
cond=lambda coll, ctx: coll.community,
if_=CollectionLink(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,6 @@ def vars(collection, vars):
"community": collection.community.slug,
"tree": collection.collection_tree.slug,
"collection": collection.slug,
"id": collection.id,
}
)
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
current_rdm_records_service,
)

from .api import Collection, CollectionTree
from .errors import LogoNotFoundError
from ..api import Collection, CollectionTree
from ..errors import LogoNotFoundError
from .links import CollectionLinkstemplate
from .results import CollectionItem, CollectionList, CollectionTreeList

Expand Down Expand Up @@ -198,12 +198,11 @@ def search_collection_records(self, identity, collection_or_id, params=None):
else:
collection = collection_or_id

params.update({"collection_id": collection.id})
if collection.community:
res = current_community_records_service.search(
identity,
community_id=collection.community.id,
params=params,
extra_filter=collection.query,
)
else:
raise NotImplementedError(
Expand Down
12 changes: 10 additions & 2 deletions invenio_rdm_records/ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
from invenio_records_resources.resources.files import FileResource

from . import config
from .collections.config import CollectionServiceConfig
from .collections.service import CollectionsService
from .collections.resources.config import CollectionsResourceConfig
from .collections.resources.resource import CollectionsResource
from .collections.services.config import CollectionServiceConfig
from .collections.services.service import CollectionsService
from .oaiserver.resources.config import OAIPMHServerResourceConfig
from .oaiserver.resources.resources import OAIPMHServerResource
from .oaiserver.services.config import OAIPMHServerServiceConfig
Expand Down Expand Up @@ -278,6 +280,12 @@ def init_resource(self, app):
config=RDMCommunityRecordsResourceConfig.build(app),
)

# Collections
self.collections_resource = CollectionsResource(
service=self.collections_service,
config=CollectionsResourceConfig,
)

# OAI-PMH
self.oaipmh_server_resource = OAIPMHServerResource(
service=self.oaipmh_server_service,
Expand Down
6 changes: 0 additions & 6 deletions invenio_rdm_records/resources/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,3 @@ class RDMSearchRequestArgsSchema(SearchRequestArgsSchema):
locale = fields.Str()
status = fields.Str()
include_deleted = fields.Bool()


class CommunityRecordsSearchRequestArgsSchema(SearchRequestArgsSchema):
"""Extend schema with collection_id field."""

collection_id = fields.Integer()
4 changes: 1 addition & 3 deletions invenio_rdm_records/resources/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
ReviewStateError,
ValidationErrorWithMessageAsList,
)
from .args import CommunityRecordsSearchRequestArgsSchema, RDMSearchRequestArgsSchema
from .args import RDMSearchRequestArgsSchema
from .deserializers import ROCrateJSONDeserializer
from .deserializers.errors import DeserializerError
from .errors import HTTPJSONException, HTTPJSONValidationWithMessageAsListException
Expand Down Expand Up @@ -558,8 +558,6 @@ class RDMCommunityRecordsResourceConfig(RecordResourceConfig, ConfiguratorMixin)
default=record_serializers,
)

request_search_args = CommunityRecordsSearchRequestArgsSchema


class RDMRecordCommunitiesResourceConfig(CommunityResourceConfig, ConfiguratorMixin):
"""Record communities resource config."""
Expand Down
8 changes: 0 additions & 8 deletions invenio_rdm_records/services/community_records/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,6 @@ def search(
if extra_filter is not None:
community_filter = community_filter & extra_filter

# Search in a specific collection
if "collection_id" in params:
collections_service = current_rdm_records.collections_service
collection = collections_service.read(
identity=identity, id_=params["collection_id"]
)
community_filter &= collection.query

search = self._search(
"search",
identity,
Expand Down
6 changes: 6 additions & 0 deletions invenio_rdm_records/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,9 @@ def create_iiif_bp(app):
"""Create IIIF blueprint."""
ext = app.extensions["invenio-rdm-records"]
return ext.iiif_resource.as_blueprint()


def create_collections_bp(app):
"""Create collections blueprint."""
ext = app.extensions["invenio-rdm-records"]
return ext.collections_resource.as_blueprint()
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ invenio_base.api_blueprints =
invenio_rdm_record_communities = invenio_rdm_records.views:create_record_communities_bp
invenio_rdm_record_requests = invenio_rdm_records.views:create_record_requests_bp
invenio_iiif = invenio_rdm_records.views:create_iiif_bp
invenio_rdm_records_collections = invenio_rdm_records.views:create_collections_bp
invenio_base.api_finalize_app =
invenio_rdm_records = invenio_rdm_records.ext:api_finalize_app
invenio_base.blueprints =
Expand Down
5 changes: 5 additions & 0 deletions tests/services/test_collections_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ def test_collections_results(
"links": {
"search": "/api/communities/blr/records",
"self_html": "/communities/blr/collections/tree-1/collection-1",
"search": f"/api/collections/{c0.id}/records",
},
"num_records": 0,
"order": c0.order,
Expand All @@ -183,6 +184,7 @@ def test_collections_results(
"links": {
"search": "/api/communities/blr/records",
"self_html": "/communities/blr/collections/tree-1/collection-2",
"search": f"/api/collections/{c1.id}/records",
},
"num_records": 0,
"order": c1.order,
Expand Down Expand Up @@ -215,6 +217,7 @@ def test_collections_results(
"links": {
"search": "/api/communities/blr/records",
"self_html": "/communities/blr/collections/tree-1/collection-1",
"search": f"/api/collections/{c0.id}/records",
},
"num_records": 0,
"order": c0.order,
Expand All @@ -228,6 +231,7 @@ def test_collections_results(
"links": {
"search": "/api/communities/blr/records",
"self_html": "/communities/blr/collections/tree-1/collection-2",
"search": f"/api/collections/{c1.id}/records",
},
"num_records": 0,
"order": c1.order,
Expand All @@ -241,6 +245,7 @@ def test_collections_results(
"links": {
"search": "/api/communities/blr/records",
"self_html": "/communities/blr/collections/tree-1/collection-3",
"search": f"/api/collections/{c3.id}/records",
},
"num_records": 0,
"order": c3.order,
Expand Down
35 changes: 0 additions & 35 deletions tests/services/test_service_community_records.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,38 +159,3 @@ def test_search_community_records(
community_id=str(community.id),
)
assert results.to_dict()["hits"]["total"] == 3


def test_search_community_records_in_collections(
community, record_community, service, uploader, minimal_record
):
"""Test search for records in a community collection."""
rec1 = deepcopy(minimal_record)
rec1["metadata"]["title"] = "Another record"
record_community.create_record(record_dict=rec1)
record_community.create_record(record_dict=minimal_record)
ctree = CollectionTree.create(
title="Tree 1",
order=10,
community_id=community.id,
slug="tree-1",
)
collection = Collection.create(
title="My Collection",
query='metadata.title:"Another record"',
slug="my-collection",
ctree=ctree,
)
all_results = service.search(
uploader.identity,
community_id=str(community.id),
)
assert all_results.total == 2

results = service.search(
uploader.identity,
community_id=str(community.id),
params={"collection_id": str(collection.id)},
)
assert results.total == 1
assert results.to_dict()["hits"]["hits"][0]["metadata"]["title"] == "Another record"

0 comments on commit 27eeac6

Please sign in to comment.