Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

project: add collection resource #566

Merged
merged 3 commits into from
Jun 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ target/
sonar/modules/organisations/jsonschemas/organisations/organisation-v1.0.0.json
sonar/modules/documents/jsonschemas/documents/document-v1.0.0.json
sonar/modules/deposits/jsonschemas/deposits/deposit-v1.0.0.json
sonar/modules/collections/jsonschemas/collections/collection-v1.0.0.json
sonar/resources/projects/jsonschemas/projects/project-v1.0.0.json
sonar/dedicated/*/*/jsonschemas/*/*/*-v1.0.0.json

Expand Down
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ exclude sonar/modules/organisations/jsonschemas/organisations/organisation-v1.0.
exclude sonar/modules/documents/jsonschemas/documents/document-v1.0.0.json
exclude sonar/modules/deposits/jsonschemas/deposits/deposit-v1.0.0.json
exclude sonar/modules/projects/jsonschemas/projects/project-v1.0.0.json
exclude sonar/modules/collections/jsonschemas/collections/collection-v1.0.0.json

include *.html
include *.inv
Expand Down
1 change: 1 addition & 0 deletions babel.ini
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,6 @@ extract_messages = $._, jQuery._
[ignore: **/**/document-v1.0.0.json]
[ignore: **/**/deposit-v1.0.0.json]
[ignore: **/**/project-v1.0.0.json]
[ignore: **/**/collection-v1.0.0.json]
[json: **.json]
keys_to_translate = ['^title$', '^label$', '^description$', '^placeholder$', '^.*Message$']
1 change: 1 addition & 0 deletions scripts/bootstrap
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ section "Compile JSON schemas" "info"
invenio utils compile-json ./sonar/modules/organisations/jsonschemas/organisations/organisation-v1.0.0_src.json -o ./sonar/modules/organisations/jsonschemas/organisations/organisation-v1.0.0.json
invenio utils compile-json ./sonar/modules/documents/jsonschemas/documents/document-v1.0.0_src.json -o ./sonar/modules/documents/jsonschemas/documents/document-v1.0.0.json
invenio utils compile-json ./sonar/modules/deposits/jsonschemas/deposits/deposit-v1.0.0_src.json -o ./sonar/modules/deposits/jsonschemas/deposits/deposit-v1.0.0.json
invenio utils compile-json ./sonar/modules/collections/jsonschemas/collections/collection-v1.0.0_src.json -o ./sonar/modules/collections/jsonschemas/collections/collection-v1.0.0.json
invenio utils compile-json ./sonar/resources/projects/jsonschemas/projects/project-v1.0.0_src.json -o ./sonar/resources/projects/jsonschemas/projects/project-v1.0.0.json
invenio utils compile-json ./sonar/dedicated/hepvs/projects/jsonschemas/hepvs/projects/project-v1.0.0_src.json -o ./sonar/dedicated/hepvs/projects/jsonschemas/hepvs/projects/project-v1.0.0.json

Expand Down
18 changes: 13 additions & 5 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@
sonar.modules.shibboleth_authenticator.views.client:blueprint',
'pdf_extractor = \
sonar.modules.pdf_extractor.views.client:blueprint',
'validation = sonar.modules.validation.views:blueprint'
'validation = sonar.modules.validation.views:blueprint',
'collections = sonar.modules.collections.views:blueprint'
],
'invenio_base.api_blueprints': [
'pdf_extractor = sonar.modules.pdf_extractor.views.api:blueprint',
Expand Down Expand Up @@ -110,14 +111,16 @@
'deposits = sonar.modules.deposits.jsonschemas',
'projects = sonar.resources.projects.jsonschemas',
'projects_hepvs = sonar.dedicated.hepvs.projects.jsonschemas',
'collections = sonar.modules.collections.jsonschemas',
'common = sonar.common.jsonschemas'
],
'invenio_search.mappings': [
'documents = sonar.modules.documents.mappings',
'organisations = sonar.modules.organisations.mappings',
'users = sonar.modules.users.mappings',
'deposits = sonar.modules.deposits.mappings',
'projects = sonar.resources.projects.mappings'
'projects = sonar.resources.projects.mappings',
'collections = sonar.modules.collections.mappings'
],
'invenio_search.templates': [
'base-record = sonar.es_templates:list_es_templates'
Expand All @@ -130,7 +133,9 @@
'user_id = \
sonar.modules.users.api:user_pid_minter',
'deposit_id = \
sonar.modules.deposits.api:deposit_pid_minter'
sonar.modules.deposits.api:deposit_pid_minter',
'collections_id = \
sonar.modules.collections.api:pid_minter'
],
'invenio_pidstore.fetchers': [
'document_id = \
Expand All @@ -140,13 +145,16 @@
'user_id = \
sonar.modules.users.api:user_pid_fetcher',
'deposit_id = \
sonar.modules.deposits.api:deposit_pid_fetcher'
sonar.modules.deposits.api:deposit_pid_fetcher',
'collections_id = \
sonar.modules.collections.api:pid_fetcher'
],
"invenio_records.jsonresolver": [
"organisation = sonar.modules.organisations.jsonresolvers",
"user = sonar.modules.users.jsonresolvers",
"document = sonar.modules.documents.jsonresolvers",
"project = sonar.resources.projects.jsonresolvers"
"project = sonar.resources.projects.jsonresolvers",
"collections = sonar.modules.collections.jsonresolvers"
],
'invenio_celery.tasks' : [
'documents = sonar.modules.documents.tasks'
Expand Down
35 changes: 30 additions & 5 deletions sonar/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
from invenio_records_rest.facets import range_filter
from invenio_stats.processors import EventsIndexer

from sonar.modules.collections.config import \
Configuration as CollectionConfiguration
from sonar.modules.deposits.api import DepositRecord, DepositSearch
from sonar.modules.deposits.permissions import DepositPermission
from sonar.modules.documents.api import DocumentRecord, DocumentSearch
Expand Down Expand Up @@ -308,7 +310,26 @@ def _(x):
'view_imp': 'sonar.resources.projects.views:detail',
'record_class': 'sonar.resources.projects.api:Record',
'template': 'sonar/projects/detail.html'
}
},
'coll': {
'pid_type': 'coll',
'route': '/<org_code:view>/collections/<pid_value>',
'view_imp': 'sonar.modules.collections.views:detail',
'record_class': 'sonar.modules.collections.api:Record',
'template': 'sonar/collections/detail.html'
},
'coll_previewer': {
'pid_type': 'coll',
'route': '/collections/<pid_value>/preview/<filename>',
'view_imp': 'invenio_previewer.views:preview',
'record_class': 'sonar.modules.collections.api:Record'
},
'coll_files': {
'pid_type': 'coll',
'route': '/collections/<pid_value>/files/<filename>',
'view_imp': 'invenio_records_files.utils:file_download_ui',
'record_class': 'invenio_records_files.api:Record'
},
}
"""Records UI for sonar."""

Expand Down Expand Up @@ -470,6 +491,9 @@ def _(x):
list_permission_factory_imp=lambda record: record_permission_factory(
action='list', record=record, cls=DepositPermission)),
}

# Add endpoint for collections
RECORDS_REST_ENDPOINTS['coll'] = CollectionConfiguration.rest_endpoint
"""REST endpoints."""

DEFAULT_AGGREGATION_SIZE = 50
Expand All @@ -486,7 +510,7 @@ def _(x):
terms=dict(field='language.value', size=DEFAULT_AGGREGATION_SIZE)),
subject=dict(
terms=dict(field='facet_subjects', size=DEFAULT_AGGREGATION_SIZE)),
specific_collection=dict(terms=dict(field='specificCollections',
collection=dict(terms=dict(field='collections.pid',
size=DEFAULT_AGGREGATION_SIZE)),
document_type=dict(
terms=dict(field='documentType', size=DEFAULT_AGGREGATION_SIZE)),
Expand Down Expand Up @@ -515,8 +539,8 @@ def _(x):
and_term_filter('language.value'),
'subject':
and_term_filter('facet_subjects'),
'specific_collection':
and_term_filter('specificCollections'),
'collection':
and_term_filter('collections.pid'),
'document_type':
and_term_filter('documentType'),
'controlled_affiliation':
Expand Down Expand Up @@ -601,7 +625,8 @@ def _(x):
'RECORDS_REST_ENDPOINTS': {
'doc': '/files',
'depo': '/files',
'org': '/files'
'org': '/files',
'coll': '/files'
}
}

Expand Down
2 changes: 2 additions & 0 deletions sonar/modules/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,8 @@ def get_record_by_bucket(bucket):
if not record_class:
raise Exception('Class for record not found.')

record_class = obj_or_import_string(record_class)

# Load record by its PID.
return record_class.get_record_by_pid(pid.pid_value)
except Exception:
Expand Down
18 changes: 18 additions & 0 deletions sonar/modules/collections/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
#
# Swiss Open Access Repository
# Copyright (C) 2021 RERO
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

"""Resource."""
92 changes: 92 additions & 0 deletions sonar/modules/collections/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# -*- coding: utf-8 -*-
#
# Swiss Open Access Repository
# Copyright (C) 2021 RERO
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

"""Record API."""

from functools import partial

from ..api import SonarIndexer, SonarRecord, SonarSearch
from ..fetchers import id_fetcher
from ..providers import Provider
from .config import Configuration
from .minters import id_minter

# provider
RecordProvider = type('RecordProvider', (Provider, ),
dict(pid_type=Configuration.pid_type))
# minter
pid_minter = partial(id_minter, provider=RecordProvider)
# fetcher
pid_fetcher = partial(id_fetcher, provider=RecordProvider)


class Record(SonarRecord):
"""Record."""

minter = pid_minter
fetcher = pid_fetcher
provider = RecordProvider
schema = Configuration.schema

@classmethod
def create(cls, data, id_=None, dbcommit=False, with_bucket=True,
**kwargs):
"""Create record.

:param dict data: Metadata of the new record
:param str id_: UUID to use if not generated
:param bool dbcommit: Wether to commit into DB during creation
:param bool with_bucket: Wether to create a bucket for record
:return: New record instance
:rtype: Record
"""
return super().create(data,
id_=id_,
dbcommit=dbcommit,
with_bucket=with_bucket,
**kwargs)
Comment on lines +45 to +61

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this necessary if your create method did nothing more than class parent ?
Into RERO-ILS project, we skip this declaration into children classes if there are no specific process.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it's mandatory because I need to set the default value for with_bucket to True.


@classmethod
def get_pid_by_hash_key(cls, hash_key):
"""Get a record by a hash key.

:param str hash_key: Hash key to find.
:return: The record found.
:rtype: SonarRecord.
"""
result = RecordSearch().filter(
'term', hashKey=hash_key).source(includes='pid').scan()
try:
return next(result).pid
except StopIteration:
return None


class RecordSearch(SonarSearch):
"""Record search."""

class Meta:
"""Search only on item index."""

index = Configuration.index
doc_types = []


class RecordIndexer(SonarIndexer):
"""Indexing documents in Elasticsearch."""

record_cls = Record
107 changes: 107 additions & 0 deletions sonar/modules/collections/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# -*- coding: utf-8 -*-
#
# Swiss Open Access Repository
# Copyright (C) 2021 RERO
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

"""Configuration."""

from sonar.modules.permissions import record_permission_factory

# Resource name
RESOURCE_NAME = 'collections'

# JSON schema name
JSON_SCHEMA_NAME = RESOURCE_NAME[:-1]

# Module path
MODULE_PATH = f'sonar.modules.{RESOURCE_NAME}'

# PID type
PID_TYPE = 'coll'


class Configuration:
"""Resource configuration."""

index = f'{RESOURCE_NAME}'
schema = f'{RESOURCE_NAME}/{JSON_SCHEMA_NAME}-v1.0.0.json'
pid_type = PID_TYPE
resolver_url = f'/api/{RESOURCE_NAME}/<pid>'
rest_endpoint = {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like PEP-8 80 characters line limit. Not easy to read :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Completely agree with you, we should increase this limit.

'pid_type':
PID_TYPE,
'pid_minter':
f'{RESOURCE_NAME}_id',
'pid_fetcher':
f'{RESOURCE_NAME}_id',
'default_endpoint_prefix':
True,
'record_class':
f'{MODULE_PATH}.api:Record',
'search_class':
f'{MODULE_PATH}.api:RecordSearch',
'indexer_class':
f'{MODULE_PATH}.api:RecordIndexer',
'search_index':
RESOURCE_NAME,
'search_type':
None,
'record_serializers': {
'application/json': (f'{MODULE_PATH}.serializers'
':json_v1_response'),
},
'search_serializers': {
'application/json': (f'{MODULE_PATH}.serializers'
':json_v1_search'),
},
'record_loaders': {
'application/json': (f'{MODULE_PATH}.loaders'
':json_v1'),
},
'list_route':
f'/{RESOURCE_NAME}/',
'item_route':
f'/{RESOURCE_NAME}/<pid({PID_TYPE}, record_class="{MODULE_PATH}.api:Record"):pid_value>',
'default_media_type':
'application/json',
'max_result_window':
10000,
'search_factory_imp':
f'{MODULE_PATH}.query:search_factory',
'create_permission_factory_imp':
lambda record: record_permission_factory(
action='create', cls=f'{MODULE_PATH}.permissions:RecordPermission'
),
'read_permission_factory_imp':
lambda record: record_permission_factory(
action='read',
record=record,
cls=f'{MODULE_PATH}.permissions:RecordPermission'),
'update_permission_factory_imp':
lambda record: record_permission_factory(
action='update',
record=record,
cls=f'{MODULE_PATH}.permissions:RecordPermission'),
'delete_permission_factory_imp':
lambda record: record_permission_factory(
action='delete',
record=record,
cls=f'{MODULE_PATH}.permissions:RecordPermission'),
'list_permission_factory_imp':
lambda record: record_permission_factory(
action='list',
record=record,
cls=f'{MODULE_PATH}.permissions:RecordPermission')
}
Loading