diff --git a/sonar/json_schemas/deposits_json_schema.py b/sonar/json_schemas/deposits_json_schema.py index db85c5a72..14f83327a 100644 --- a/sonar/json_schemas/deposits_json_schema.py +++ b/sonar/json_schemas/deposits_json_schema.py @@ -32,14 +32,33 @@ def process(self): """ schema = super().process() - if not current_user_record or current_user_record.is_moderator: + organisation = {} + if current_user_record: + organisation = current_user_record.replace_refs() \ + .get('organisation') + + if not current_user_record or (current_user_record.is_moderator and \ + organisation.get('isDedicated', False)): return schema + # Remove some fields on json for the shared organisation + if not organisation.get('isDedicated', False): + # Remove collections field + schema['properties']['metadata']['properties']\ + .pop('collections', None) + propertiesOrder = schema['properties']['metadata']\ + .get('propertiesOrder', []) + if 'collections' in propertiesOrder: + schema['properties']['metadata']['propertiesOrder']\ + .remove('collections') + + # Remove subdivisions field schema['properties']['diffusion']['properties'].pop( - 'subdivisions', None) - order = schema['properties']['diffusion']['propertiesOrder'] - schema['properties']['diffusion']['propertiesOrder'] = [ - v for v in order if v != 'subdivisions' - ] + 'subdivisions', None) + propertiesOrder = schema['properties']['diffusion']\ + .get('propertiesOrder', []) + if 'subdivisions' in propertiesOrder: + schema['properties']['diffusion']['propertiesOrder']\ + .remove('subdivisions') return schema diff --git a/sonar/json_schemas/documents_json_schema.py b/sonar/json_schemas/documents_json_schema.py new file mode 100644 index 000000000..73b0abd19 --- /dev/null +++ b/sonar/json_schemas/documents_json_schema.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +# +# Swiss Open Access Repository +# Copyright (C) 2022 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 . + +"""Documents JSON schema class.""" + +from sonar.modules.users.api import current_user_record + +from .json_schema_base import JSONSchemaBase + + +class DocumentsJSONSchema(JSONSchemaBase): + """JSON schema for deposits.""" + + def process(self): + """Documents JSON schema custom process. + + :returns: The processed schema. + """ + schema = super().process() + + if not current_user_record: + return schema + + # Get Organisation for the current logged user + organisation = current_user_record.replace_refs()\ + .get('organisation', {}) + # Remove some fields on json for the shared organisation + if not organisation.get('isDedicated', False): + for field in ['collections', 'subdivisions']: + schema['properties'].pop(field, None) + if field in schema.get('propertiesOrder', []): + schema['propertiesOrder'].remove(field) + + if not current_user_record.is_superuser: + schema['properties'].pop('organisation', None) + if 'organisation' in schema.get('propertiesOrder', []): + schema['propertiesOrder'].remove('organisation') + + return schema diff --git a/sonar/json_schemas/factory.py b/sonar/json_schemas/factory.py index 367e98f19..a153ca00b 100644 --- a/sonar/json_schemas/factory.py +++ b/sonar/json_schemas/factory.py @@ -18,14 +18,22 @@ """Factory for JSON schema.""" from .deposits_json_schema import DepositsJSONSchema +from .documents_json_schema import DocumentsJSONSchema from .json_schema_base import JSONSchemaBase +from .organisations_json_schema import OrganisationsJSONSchema +from .projects_json_schema import ProjectsJSONSchema +from .users_json_schema import UsersJSONSchema class JSONSchemaFactory(): """Factory for JSON schema.""" SCHEMAS = { - 'deposits': DepositsJSONSchema + 'deposits': DepositsJSONSchema, + 'documents': DocumentsJSONSchema, + 'organisations': OrganisationsJSONSchema, + 'projects': ProjectsJSONSchema, + 'users': UsersJSONSchema } @staticmethod diff --git a/sonar/json_schemas/organisations_json_schema.py b/sonar/json_schemas/organisations_json_schema.py new file mode 100644 index 000000000..240c725ce --- /dev/null +++ b/sonar/json_schemas/organisations_json_schema.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +# +# Swiss Open Access Repository +# Copyright (C) 2022 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 . + +"""Organisations JSON schema class.""" + +from sonar.modules.users.api import current_user_record + +from .json_schema_base import JSONSchemaBase + + +class OrganisationsJSONSchema(JSONSchemaBase): + """JSON schema for deposits.""" + + def process(self): + """Organisations JSON schema custom process. + + :returns: The processed schema. + """ + schema = super().process() + + # Remove modes fields if user does not have superuser role. + if not current_user_record.is_superuser: + propertiesOrder = schema.get('propertiesOrder', []); + for field in ['isDedicated', 'isShared']: + if field in propertiesOrder: + schema['propertiesOrder'].remove(field) + + return schema diff --git a/sonar/json_schemas/projects_json_schema.py b/sonar/json_schemas/projects_json_schema.py new file mode 100644 index 000000000..6c5ba7af8 --- /dev/null +++ b/sonar/json_schemas/projects_json_schema.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# +# Swiss Open Access Repository +# Copyright (C) 2022 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 . + +"""Projects JSON schema class.""" + +from sonar.modules.users.api import current_user_record + +from .json_schema_base import JSONSchemaBase + + +class ProjectsJSONSchema(JSONSchemaBase): + """JSON schema for deposits.""" + + def process(self): + """Projects JSON schema custom process. + + :returns: The processed schema. + """ + schema = super().process() + + # Remove modes fields if user does not have superuser role. + if current_user_record and not current_user_record.is_superuser: + schema['properties']['metadata']['properties'].pop( + 'organisation', None) + if 'organisation' in schema['properties']['metadata']\ + ['propertiesOrder']: + schema['properties']['metadata']['propertiesOrder'].remove( + 'organisation') + + return schema diff --git a/sonar/json_schemas/users_json_schema.py b/sonar/json_schemas/users_json_schema.py new file mode 100644 index 000000000..c54588070 --- /dev/null +++ b/sonar/json_schemas/users_json_schema.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +# +# Swiss Open Access Repository +# Copyright (C) 2022 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 . + +"""Users JSON schema class.""" + +from flask_login import current_user + +from sonar.modules.users.api import current_user_record + +from .json_schema_base import JSONSchemaBase + + +class UsersJSONSchema(JSONSchemaBase): + """JSON schema for deposits.""" + + def process(self): + """Users JSON schema custom process. + + :returns: The processed schema. + """ + schema = super().process() + + # Remove modes fields if user does not have superuser role. + if not current_user.is_anonymous and current_user_record: + if current_user_record.is_admin: + reachable_roles = current_user_record.\ + get_all_reachable_roles() + + schema['properties']['role']['form']['options'] = [{ + 'label': 'role_{role}'.format(role=role), + 'value': role + } for role in reachable_roles] + schema['properties']['role'][ + 'enum'] = current_user_record.get_all_reachable_roles( + ) + else: + schema['properties'].pop('role') + if 'role' in schema.get('propertiesOrder', []): + schema['propertiesOrder'].remove('role') + + if not current_user_record.is_superuser: + schema['properties'].pop('organisation') + if 'organisation' in schema.get('propertiesOrder', []): + schema['propertiesOrder'].remove('organisation') + + return schema diff --git a/sonar/theme/views.py b/sonar/theme/views.py index 79adbaa2c..8f0d8b672 100644 --- a/sonar/theme/views.py +++ b/sonar/theme/views.py @@ -206,56 +206,6 @@ def schemas(record_type): """ try: json_schema = JSONSchemaFactory.create(record_type) - schema = json_schema.get_schema() - - # TODO: Maybe find a proper way to do this. - if record_type in [ - 'users', 'documents' - ] and not current_user.is_anonymous and current_user_record: - if record_type == 'users': - # If user is admin, restrict available roles list. - if current_user_record.is_admin: - reachable_roles = current_user_record.\ - get_all_reachable_roles() - - schema['properties']['role']['form']['options'] = [] - for role in reachable_roles: - schema['properties']['role']['form']['options'].append( - { - 'label': 'role_{role}'.format(role=role), - 'value': role - }) - - schema['properties']['role'][ - 'enum'] = current_user_record.get_all_reachable_roles( - ) - # User cannot select role - else: - schema['properties'].pop('role') - if 'role' in schema.get('propertiesOrder', []): - schema['propertiesOrder'].remove('role') - - if not current_user_record.is_superuser: - schema['properties'].pop('organisation') - if 'organisation' in schema.get('propertiesOrder', []): - schema['propertiesOrder'].remove('organisation') - - if (record_type == 'projects' and not current_user.is_anonymous and - current_user_record and not current_user_record.is_superuser): - schema['properties']['metadata']['properties'].pop( - 'organisation', None) - schema['properties']['metadata']['propertiesOrder'].remove( - 'organisation') - - # Remove modes fields if user does not have superuser role. - if (record_type == 'organisations' and - not current_user_record.is_superuser): - if 'isDedicated' in schema.get('propertiesOrder', []): - schema['propertiesOrder'].remove('isDedicated') - - if 'isShared' in schema.get('propertiesOrder', []): - schema['propertiesOrder'].remove('isShared') - return jsonify({'schema': json_schema.process()}) except JSONSchemaNotFound: abort(404) diff --git a/tests/conftest.py b/tests/conftest.py index 8bbe848ba..a1f1735f7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -132,12 +132,12 @@ def app_config(app_config): def make_organisation(app, db, bucket_location, without_oaiset_signals): """Factory for creating organisation.""" - def _make_organisation(code): + def _make_organisation(code, is_shared=True): data = { 'code': code, 'name': code, - 'isShared': True, - 'isDedicated': False, + 'isShared': is_shared, + 'isDedicated': not is_shared, 'documentsCustomField1': { 'label': [{ 'language': 'eng', @@ -194,11 +194,13 @@ def roles(base_app, db): def make_user(app, db, make_organisation): """Factory for creating user.""" - def _make_user(role_name, organisation='org', access=None): + def _make_user( + role_name, organisation='org', organisation_is_shared=True, + access=None): name = role_name if organisation: - make_organisation(organisation) + make_organisation(organisation, is_shared=organisation_is_shared) name = organisation + name email = '{name}@rero.ch'.format(name=name) @@ -283,6 +285,16 @@ def moderator(make_user): return make_user('moderator', access='admin-access') +@pytest.fixture() +def moderator_dedicated(make_user): + """Create moderator organisation dedicated.""" + return make_user( + 'moderator', + organisation='dedicated', + organisation_is_shared=False, + access='admin-access') + + @pytest.fixture() def submitter(make_user): """Create submitter.""" @@ -304,7 +316,7 @@ def superuser(make_user): @pytest.fixture() def document_json(app, db, bucket_location, organisation): """JSON document fixture.""" - data = { + return { 'identifiedBy': [{ 'value': 'urn:nbn:ch:rero-006-108713', 'type': 'bf:Urn' @@ -424,8 +436,6 @@ def document_json(app, db, bucket_location, organisation): 'customField1': ['Test'] } - return data - @pytest.fixture() def make_document(db, document_json, make_organisation, pdf_file, embargo_date): diff --git a/tests/ui/test_views.py b/tests/ui/test_views.py index 6ddf76c9f..4d70a1f40 100644 --- a/tests/ui/test_views.py +++ b/tests/ui/test_views.py @@ -134,52 +134,74 @@ def test_logged_user(app, client, superuser, admin, moderator, submitter, assert not res.json['metadata']['permissions']['deposits']['list'] -def test_schemas(client, admin, user, submitter, moderator): - """Test JSON schemas endpoint.""" - res = client.get(url_for('sonar.schemas', record_type='documents')) - assert res.status_code == 200 - assert res.json['schema']['properties'].get('organisation') +def test_non_existing_schema(client, user): + """Test schema no existing.""" + login_user_via_session(client, email=user['email']) + res = client.get(url_for('sonar.schemas', record_type='not_existing')) + assert res.status_code == 404 - res = client.get(url_for('sonar.schemas', record_type='users')) + +def test_schema_documents(client, user, superuser): + """Test schema documents.""" + res = client.get(url_for('sonar.schemas', record_type='documents')) assert res.status_code == 200 assert res.json['schema']['properties'].get('organisation') - assert res.json['schema']['properties'].get('role') - res = client.get(url_for('sonar.schemas', record_type='deposits')) + login_user_via_session(client, email=user['email']) + res = client.get(url_for('sonar.schemas', record_type='documents')) assert res.status_code == 200 + assert not res.json['schema']['properties'].get('collections') + assert 'collections' not in res.json['schema']['propertiesOrder'] + assert not res.json['schema']['properties'].get('subdivisions') + assert 'subdivisions' not in res.json['schema']['propertiesOrder'] + assert not res.json['schema']['properties'].get('organisations') + assert 'organisations' not in res.json['schema']['propertiesOrder'] - login_user_via_session(client, email=admin['email']) - + login_user_via_session(client, email=superuser['email']) res = client.get(url_for('sonar.schemas', record_type='documents')) assert res.status_code == 200 - assert not res.json['schema']['properties'].get('organisation') + assert not res.json['schema']['properties'].get('collections') + assert 'collections' not in res.json['schema']['propertiesOrder'] + assert not res.json['schema']['properties'].get('subdivisions') + assert 'subdivisions' not in res.json['schema']['propertiesOrder'] + assert res.json['schema']['properties'].get('organisation') + assert 'organisation' in res.json['schema']['propertiesOrder'] - res = client.get(url_for('sonar.schemas', record_type='deposits')) + +def test_schema_users(client, admin): + """Test schema users.""" + res = client.get(url_for('sonar.schemas', record_type='users')) assert res.status_code == 200 + assert res.json['schema']['properties'].get('organisation') + assert res.json['schema']['properties'].get('role') + login_user_via_session(client, email=admin['email']) res = client.get(url_for('sonar.schemas', record_type='users')) assert res.status_code == 200 assert not res.json['schema']['properties'].get('organisation') assert res.json['schema']['properties'].get('role') assert len(res.json['schema']['properties']['role']['enum']) == 4 - res = client.get(url_for('sonar.schemas', record_type='not_existing')) - assert res.status_code == 404 - # Organisations, with admin user --> no fields `isShared` and `isDedicated` +def test_schema_organisations(client, admin, user): + """Test schema organisations.""" + login_user_via_session(client, email=admin['email']) + # admin user --> no fields `isShared` and `isDedicated` res = client.get(url_for('sonar.schemas', record_type='organisations')) assert res.status_code == 200 assert 'isShared' not in res.json['schema']['propertiesOrder'] assert 'isDedicated' not in res.json['schema']['propertiesOrder'] login_user_via_session(client, email=user['email']) - res = client.get(url_for('sonar.schemas', record_type='users')) assert res.status_code == 200 assert not res.json['schema']['properties'].get('organisation') assert not res.json['schema']['properties'].get('role') - # Projects + +def test_schema_projects(client, user): + """Test schema projects.""" + login_user_via_session(client, email=user['email']) res = client.get(url_for('sonar.schemas', record_type='projects')) assert res.status_code == 200 assert not res.json['schema']['properties']['metadata']['properties'].get( @@ -188,20 +210,45 @@ def test_schemas(client, admin, user, submitter, moderator): assert 'organisation' not in res.json['schema']['properties']['metadata'][ 'propertiesOrder'] + +def test_schema_deposits(client, moderator, submitter, moderator_dedicated): + """Test schema deposits.""" login_user_via_session(client, email=moderator['email']) res = client.get(url_for('sonar.schemas', record_type='deposits')) assert res.status_code == 200 - assert res.json[ + # Moderator with shared organisation + assert not res.json[ 'schema']['properties']['diffusion']['properties'].get('subdivisions') - assert 'subdivisions' in res.json[ + assert 'subdivisions' not in res.json[ 'schema']['properties']['diffusion']['propertiesOrder'] + assert not res.json[ + 'schema']['properties']['metadata']['properties'].get('collections') + assert 'collections' not in res.json[ + 'schema']['properties']['metadata']['propertiesOrder'] login_user_via_session(client, email=submitter['email']) res = client.get(url_for('sonar.schemas', record_type='deposits')) assert res.status_code == 200 assert not res.json[ 'schema']['properties']['diffusion']['properties'].get('subdivisions') - assert not 'subdivisions' in res.json[ + assert 'subdivisions' not in res.json[ + 'schema']['properties']['diffusion']['propertiesOrder'] + assert not res.json[ + 'schema']['properties']['metadata']['properties'].get('collections') + assert 'collections' not in res.json[ + 'schema']['properties']['metadata']['propertiesOrder'] + + # Moderator with dedicated organisation + login_user_via_session(client, email=moderator_dedicated['email']) + res = client.get(url_for('sonar.schemas', record_type='deposits')) + assert res.status_code == 200 + assert res.json[ + 'schema']['properties']['metadata']['properties'].get('collections') + assert 'collections' in res.json[ + 'schema']['properties']['metadata']['propertiesOrder'] + assert res.json[ + 'schema']['properties']['diffusion']['properties'].get('subdivisions') + assert 'subdivisions' in res.json[ 'schema']['properties']['diffusion']['propertiesOrder']