Skip to content

Commit

Permalink
subdivisions: create resource
Browse files Browse the repository at this point in the history
* Creates a new `subdivisions` resource.
* Links subdivisions to documents.
* Links subdivision to users.
* Links subdivision to deposits in diffusion step.
* Creates a subdivision when a section is found in RERO DOC publication.
* Configures a facet to filter deposits by subdivisions.
* Configures a facet to filter users by subdivision.
* Configures a facet to filter documents by subdivision.
* Updates permissions for collections by adding rules for subdivisions.
* Updates permissions for deposits by adding rules for subdivisions.
* Updates permissions for documents by adding rules for subdivisions.
* Adds organisations and subdivisions info in document detail view below the title.
* Translates subdivisions and collections facets.
* Makes the name of a subdivision or collection unique per language.
* Closes #145.

Co-Authored-by: Sébastien Délèze <[email protected]>
  • Loading branch information
Sébastien Délèze committed Aug 23, 2021
1 parent a393585 commit 0d45c81
Show file tree
Hide file tree
Showing 61 changed files with 2,059 additions and 149 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ 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/modules/subdivisions/jsonschemas/subdivisions/subdivision-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 @@ -17,6 +17,7 @@ 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
exclude sonar/modules/subdivisions/jsonschemas/subdivisions/subdivision-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 @@ -37,5 +37,6 @@ extract_messages = $._, jQuery._
[ignore: **/**/deposit-v1.0.0.json]
[ignore: **/**/project-v1.0.0.json]
[ignore: **/**/collection-v1.0.0.json]
[ignore: **/**/subdivision-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 @@ -92,6 +92,7 @@ invenio utils compile-json ./sonar/modules/organisations/jsonschemas/organisatio
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/modules/subdivisions/jsonschemas/subdivisions/subdivision-v1.0.0_src.json -o ./sonar/modules/subdivisions/jsonschemas/subdivisions/subdivision-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
15 changes: 11 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@
'projects = sonar.resources.projects.jsonschemas',
'projects_hepvs = sonar.dedicated.hepvs.projects.jsonschemas',
'collections = sonar.modules.collections.jsonschemas',
'subdivisions = sonar.modules.subdivisions.jsonschemas',
'common = sonar.common.jsonschemas'
],
'invenio_search.mappings': [
Expand All @@ -123,7 +124,8 @@
'users = sonar.modules.users.mappings',
'deposits = sonar.modules.deposits.mappings',
'projects = sonar.resources.projects.mappings',
'collections = sonar.modules.collections.mappings'
'collections = sonar.modules.collections.mappings',
'subdivisions = sonar.modules.subdivisions.mappings'
],
'invenio_search.templates': [
'base-record = sonar.es_templates:list_es_templates'
Expand All @@ -138,7 +140,9 @@
'deposit_id = \
sonar.modules.deposits.api:deposit_pid_minter',
'collections_id = \
sonar.modules.collections.api:pid_minter'
sonar.modules.collections.api:pid_minter',
'subdivisions_id = \
sonar.modules.subdivisions.api:pid_minter'
],
'invenio_pidstore.fetchers': [
'document_id = \
Expand All @@ -150,14 +154,17 @@
'deposit_id = \
sonar.modules.deposits.api:deposit_pid_fetcher',
'collections_id = \
sonar.modules.collections.api:pid_fetcher'
sonar.modules.collections.api:pid_fetcher',
'subdivisions_id = \
sonar.modules.subdivisions.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",
"collections = sonar.modules.collections.jsonresolvers"
"collections = sonar.modules.collections.jsonresolvers",
"subdivisions = sonar.modules.subdivisions.jsonresolvers"
],
'invenio_celery.tasks' : [
'documents = sonar.modules.documents.tasks'
Expand Down
27 changes: 21 additions & 6 deletions sonar/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
from sonar.modules.permissions import record_permission_factory, \
wiki_edit_permission
from sonar.modules.query import and_term_filter, missing_field_filter
from sonar.modules.subdivisions.config import \
Configuration as SubdivisionConfiguration
from sonar.modules.users.api import UserRecord, UserSearch
from sonar.modules.users.permissions import UserPermission
from sonar.modules.utils import get_current_language
Expand Down Expand Up @@ -496,6 +498,9 @@ def _(x):

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

# Add endpoint for subdivisions
RECORDS_REST_ENDPOINTS['subd'] = SubdivisionConfiguration.rest_endpoint
"""REST endpoints."""

DEFAULT_AGGREGATION_SIZE = 50
Expand All @@ -504,16 +509,16 @@ def _(x):
RECORDS_REST_FACETS = {
'documents':
dict(aggs=dict(
sections=dict(terms=dict(field='sections',
size=DEFAULT_AGGREGATION_SIZE)),
subdivision=dict(terms=dict(field='subdivisions.pid',
size=DEFAULT_AGGREGATION_SIZE)),
organisation=dict(terms=dict(field='organisation.pid',
size=DEFAULT_AGGREGATION_SIZE)),
language=dict(
terms=dict(field='language.value', size=DEFAULT_AGGREGATION_SIZE)),
subject=dict(
terms=dict(field='facet_subjects', size=DEFAULT_AGGREGATION_SIZE)),
collection=dict(terms=dict(field='collections.pid',
size=DEFAULT_AGGREGATION_SIZE)),
size=DEFAULT_AGGREGATION_SIZE)),
document_type=dict(
terms=dict(field='documentType', size=DEFAULT_AGGREGATION_SIZE)),
controlled_affiliation=dict(
Expand All @@ -533,8 +538,8 @@ def _(x):
customField3=dict(terms=dict(field='customField3.raw',
size=DEFAULT_AGGREGATION_SIZE))),
filters={
'sections':
and_term_filter('sections'),
'subdivision':
and_term_filter('subdivisions.pid'),
'organisation':
and_term_filter('organisation.pid'),
'language':
Expand Down Expand Up @@ -564,11 +569,14 @@ def _(x):
}),
'deposits':
dict(aggs=dict(
subdivision=dict(terms=dict(field='diffusion.subdivisions.pid',
size=DEFAULT_AGGREGATION_SIZE)),
status=dict(terms=dict(field='status', size=DEFAULT_AGGREGATION_SIZE)),
user=dict(terms=dict(field='user.pid', size=DEFAULT_AGGREGATION_SIZE)),
contributor=dict(terms=dict(field='facet_contributors',
size=DEFAULT_AGGREGATION_SIZE))),
filters={
'subdivision': and_term_filter('diffusion.subdivisions.pid'),
_('pid'): and_term_filter('pid'),
_('status'): and_term_filter('status'),
_('user'): and_term_filter('user.pid'),
Expand All @@ -586,10 +594,17 @@ def _(x):
}
}
}
},
'subdivision': {
'terms': {
'field': 'subdivision.pid',
'size': DEFAULT_AGGREGATION_SIZE
}
}
},
'filters': {
'missing_organisation': missing_field_filter('organisation')
'missing_organisation': missing_field_filter('organisation'),
'subdivision': and_term_filter('subdivision.pid')
}
}
}
Expand Down
41 changes: 41 additions & 0 deletions sonar/json_schemas/deposits_json_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# -*- 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/>.

"""Deposits JSON schema class."""

from sonar.modules.users.api import current_user_record

from .json_schema_base import JSONSchemaBase


class DepositsJSONSchema(JSONSchemaBase):
"""JSON schema for deposits."""

def process(self):
"""Document JSON schema custom process.
:returns: The processed schema.
"""
schema = super().process()

if current_user_record.is_moderator:
return schema

schema['properties']['diffusion']['properties'].pop(
'subdivisions', None)

return schema
6 changes: 5 additions & 1 deletion sonar/json_schemas/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,18 @@

"""Factory for JSON schema."""

from .deposits_json_schema import DepositsJSONSchema
from .documents_json_schema import DocumentsJSONSchema
from .json_schema_base import JSONSchemaBase


class JSONSchemaFactory():
"""Factory for JSON schema."""

SCHEMAS = {'documents': DocumentsJSONSchema}
SCHEMAS = {
'documents': DocumentsJSONSchema,
'deposits': DepositsJSONSchema
}

@staticmethod
def create(resource_type):
Expand Down
43 changes: 38 additions & 5 deletions sonar/modules/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,8 @@ def get_record_class_by_pid_type(cls, pid_type):
:param pid_type: PID type.
:returns: Record class.
"""
return current_app.config.get(
'RECORDS_REST_ENDPOINTS',
{}).get(pid_type, {}).get('record_class')
return current_app.config.get('RECORDS_REST_ENDPOINTS',
{}).get(pid_type, {}).get('record_class')

@classmethod
def get_all_pids(cls, with_deleted=False):
Expand All @@ -121,8 +120,7 @@ def get_all_pids(cls, with_deleted=False):
:returns: A generator iterator.
"""
query = PersistentIdentifier.query.filter_by(
pid_type=cls.provider.pid_type
)
pid_type=cls.provider.pid_type)
if not with_deleted:
query = query.filter_by(status=PIDStatus.REGISTERED)

Expand Down Expand Up @@ -313,6 +311,41 @@ def delete(self, force=False, dbcommit=False, delindex=False):

return self

def has_organisation(self, organisation_pid):
"""Check if record belongs to the organisation.
:param str organisation_pid: Organisation PID
:returns: True if record has organisation
:rtype: Bool
"""
for org in self.get('organisation', []):
if organisation_pid == org['pid']:
return True

return False

def has_subdivision(self, subdivision_pid):
"""Check if record belongs to the subdivision.
:param str subdivision_pid: Subdivision PID
:returns: True if record has subdivision
:rtype: Bool
"""
# No subdivision passed, means no check to do.
if not subdivision_pid:
return True

# No subdivision in record, the document is accessible.
if not self.get('subdivisions'):
return False

for subdivision in self['subdivisions']:
if subdivision_pid == subdivision['pid']:
return True

# Subdivision not found, record is inaccessible
return False


class SonarSearch(RecordsSearch):
"""Search Class SONAR."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,21 @@
"value",
"language"
]
},
"form": {
"validation": {
"validators": {
"uniqueValueKeysInObject": {
"keys": [
"language"
]
}
},
"messages": {
"uniqueValueKeysInObjectMessage": "Only one value per language is allowed"
}
}
}

},
"description": {
"title": "Descriptions",
Expand Down
15 changes: 6 additions & 9 deletions sonar/modules/collections/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def list(cls, user, record=None):
:return: True is action can be done
:rtype: bool
"""
return user and user.is_moderator
return user and user.is_admin

@classmethod
def create(cls, user, record=None):
Expand All @@ -47,7 +47,7 @@ def create(cls, user, record=None):
:return: True is action can be done
:rtype: bool
"""
return user and user.is_moderator
return cls.list(user, record)

@classmethod
def read(cls, user, record):
Expand All @@ -58,18 +58,15 @@ def read(cls, user, record):
:return: True is action can be done
:rtype: bool
"""
# Only for moderator users
if not user or not user.is_moderator:
return False

# Super user is allowed
if user.is_superuser:
if user and user.is_superuser:
return True

if not cls.create(user, record):
return False

record = Record.get_record_by_pid(record['pid'])
record = record.replace_refs()

# For moderator users, they can read only their own records.
return current_organisation['pid'] == record['organisation']['pid']

@classmethod
Expand Down
11 changes: 10 additions & 1 deletion sonar/modules/deposits/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from sonar.modules.api import SonarRecord
from sonar.modules.collections.api import Record as CollectionRecord
from sonar.modules.documents.api import DocumentRecord
from sonar.modules.users.api import current_user_record
from sonar.modules.users.api import UserRecord, current_user_record
from sonar.proxies import sonar

from ..api import SonarIndexer, SonarRecord, SonarSearch
Expand Down Expand Up @@ -366,6 +366,15 @@ def create_document(self):
if self['diffusion'].get('oa_status'):
metadata['oa_status'] = self['diffusion']['oa_status']

# Subdivisions
if self['diffusion'].get('subdivisions'):
metadata['subdivisions'] = self['diffusion']['subdivisions']
else:
# Guess from submitter
user = UserRecord.get_record_by_ref_link(self['user']['$ref'])
if user and user.is_submitter and user.get('subdivision'):
metadata['subdivisions'] = [user['subdivision']]

document = DocumentRecord.create(metadata,
dbcommit=True,
with_bucket=True)
Expand Down
Loading

0 comments on commit 0d45c81

Please sign in to comment.