From 990909a8eec5210f463bf712444f705cc343da66 Mon Sep 17 00:00:00 2001 From: Alexander Watzinger Date: Sat, 9 Sep 2023 12:57:47 +0200 Subject: [PATCH 01/32] Raise version --- config/default.py | 2 +- openatlas/views/changelog.py | 1 + sphinx/source/conf.py | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/config/default.py b/config/default.py index 501d2f758..1903906c1 100644 --- a/config/default.py +++ b/config/default.py @@ -3,7 +3,7 @@ from config.database_versions import DATABASE_VERSIONS -VERSION = '7.16.0' +VERSION = '7.17.0' DATABASE_VERSION = DATABASE_VERSIONS[0] DEMO_MODE = False # If activated some options are disabled, login is prefilled diff --git a/openatlas/views/changelog.py b/openatlas/views/changelog.py index 1a80f425c..6adda6c48 100644 --- a/openatlas/views/changelog.py +++ b/openatlas/views/changelog.py @@ -15,6 +15,7 @@ def index_changelog() -> str: versions = { + '7.17.0': ['TBA', {}], '7.16.0': ['2023-09-09', { 'feature': { '2022': 'Additional database export option (dump)', diff --git a/sphinx/source/conf.py b/sphinx/source/conf.py index 6a204939e..3cd7e1006 100644 --- a/sphinx/source/conf.py +++ b/sphinx/source/conf.py @@ -3,8 +3,8 @@ from typing import List # pylint: disable=invalid-name -version = '7.16.0' -release = '7.16.0' +version = '7.17.0' +release = '7.17.0' templates_path = ['_templates'] source_suffix = '.rst' master_doc = 'index' From 8291e294b85721c5d41edd45238a76df859c3df9 Mon Sep 17 00:00:00 2001 From: Alexander Watzinger Date: Tue, 19 Sep 2023 16:41:06 +0200 Subject: [PATCH 02/32] External reference systems for hierarchies --- install/data_test.sql | 4 ++++ openatlas/display/base_display.py | 9 ++++----- openatlas/display/util.py | 1 + openatlas/forms/add_fields.py | 2 -- openatlas/templates/entity/view.html | 2 +- openatlas/templates/type/index.html | 3 +++ openatlas/views/type.py | 3 +++ tests/test_hierarchy.py | 4 +++- 8 files changed, 19 insertions(+), 9 deletions(-) diff --git a/install/data_test.sql b/install/data_test.sql index d0a2597bb..f457ce32b 100644 --- a/install/data_test.sql +++ b/install/data_test.sql @@ -22,3 +22,7 @@ INSERT INTO web.i18n (name, language, text) VALUES ('citation_example', 'en', 'c -- Log entry for none existing entity INSERT INTO web.user_log (user_id, entity_id, action) VALUES (2, 6666, 'insert'); + +-- Needed to test external reference systems for hierarchies +INSERT INTO web.reference_system_openatlas_class (reference_system_id, openatlas_class_name) VALUES + ((SELECT entity_id FROM web.reference_system WHERE name='Wikidata'), 'type'); diff --git a/openatlas/display/base_display.py b/openatlas/display/base_display.py index 46c61c1f4..2c45cd518 100644 --- a/openatlas/display/base_display.py +++ b/openatlas/display/base_display.py @@ -10,10 +10,10 @@ from openatlas import app from openatlas.display.tab import Tab from openatlas.display.util import ( - bookmark_toggle, button, description, edit_link, ext_references, - format_date, format_entity_date, get_appearance, get_base_table_data, - get_system_data, is_authorized, link, manual, profile_image_table_link, - remove_link, get_chart_data) + bookmark_toggle, button, description, edit_link, format_date, + format_entity_date, get_appearance, get_base_table_data, get_system_data, + is_authorized, link, manual, profile_image_table_link, remove_link, + get_chart_data) from openatlas.models.entity import Entity from openatlas.models.gis import Gis from openatlas.models.link import Link @@ -101,7 +101,6 @@ def add_info_tab_content(self) -> None: overlays=self.overlays, chart_data=self.get_chart_data(), description_html=self.description_html(), - ext_references=ext_references(self.entity.reference_systems), problematic_type_id=self.problematic_type) def description_html(self) -> str: diff --git a/openatlas/display/util.py b/openatlas/display/util.py index a01b8f5f3..7ab463d7c 100644 --- a/openatlas/display/util.py +++ b/openatlas/display/util.py @@ -54,6 +54,7 @@ def edit_link(url: str) -> Optional[str]: return link(_('edit'), url) if is_authorized('contributor') else None +@app.template_filter() def ext_references(links: list[Link]) -> str: if not links: return '' diff --git a/openatlas/forms/add_fields.py b/openatlas/forms/add_fields.py index 4692335c5..ccf606b73 100644 --- a/openatlas/forms/add_fields.py +++ b/openatlas/forms/add_fields.py @@ -18,8 +18,6 @@ def add_reference_systems(manager: Any) -> None: - if hasattr(manager.form_class, 'classes'): - return # Skip hierarchies precisions = [('', '')] + [ (str(g.types[id_].id), g.types[id_].name) for id_ in Type.get_hierarchy('External reference match').subs] diff --git a/openatlas/templates/entity/view.html b/openatlas/templates/entity/view.html index e5db7182a..05b48f6d9 100644 --- a/openatlas/templates/entity/view.html +++ b/openatlas/templates/entity/view.html @@ -17,7 +17,7 @@
- {{ ext_references|safe }} + {{ entity.reference_systems|ext_references|safe }} {{ description_html|safe }} {% if gis_data %} diff --git a/openatlas/templates/type/index.html b/openatlas/templates/type/index.html index 22e206b62..61fd800a8 100644 --- a/openatlas/templates/type/index.html +++ b/openatlas/templates/type/index.html @@ -128,6 +128,9 @@ {% if not type_.subs %}

{{ _("this type has no subs and won't show in forms")|uc_first }}.

{% endif %} + {% if type_.reference_systems %} +

{{ type_.reference_systems|ext_references|safe }}

+ {% endif %} {% if type_.description %}
{{ _('description')|uc_first }} diff --git a/openatlas/views/type.py b/openatlas/views/type.py index cb1ed71df..e9c306453 100644 --- a/openatlas/views/type.py +++ b/openatlas/views/type.py @@ -54,6 +54,9 @@ def type_index() -> str: 'forms/tree_select_item.html', name=sanitize(type_.name), data=walk_tree(type_.subs)) + for link_ in type_.get_links('P67', inverse=True): + if link_.domain.class_.view == 'reference_system': + type_.reference_systems.append(link_) return render_template( 'type/index.html', buttons=[manual('entity/type')], diff --git a/tests/test_hierarchy.py b/tests/test_hierarchy.py index 0a5e92acc..e88a27fa5 100644 --- a/tests/test_hierarchy.py +++ b/tests/test_hierarchy.py @@ -1,6 +1,6 @@ from typing import Any -from flask import url_for +from flask import url_for, g from openatlas import app from tests.base import TestBaseCase, get_hierarchy @@ -29,6 +29,8 @@ def test_hierarchy(self) -> None: assert b'The name is already in use' in rv.data hierarchy = get_hierarchy('Geronimo') + data[f'reference_system_id_{g.wikidata.id}'] \ + = ['Q123', self.precision_type.subs[0]] data['classes'] = ['acquisition'] data['entity_id'] = hierarchy.id rv = self.app.post( From d677d40857b4ca317ea420e7998f1daee212e09c Mon Sep 17 00:00:00 2001 From: Alexander Watzinger Date: Tue, 19 Sep 2023 16:46:16 +0200 Subject: [PATCH 03/32] Update changelog --- openatlas/views/changelog.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openatlas/views/changelog.py b/openatlas/views/changelog.py index 6adda6c48..1269ff318 100644 --- a/openatlas/views/changelog.py +++ b/openatlas/views/changelog.py @@ -15,7 +15,9 @@ def index_changelog() -> str: versions = { - '7.17.0': ['TBA', {}], + '7.17.0': ['TBA', { + 'feature': { + '2026': 'External reference systems for type hierarchies'}}], '7.16.0': ['2023-09-09', { 'feature': { '2022': 'Additional database export option (dump)', From 1e103960bd50c18d4192fb32b4ef3f709167d573 Mon Sep 17 00:00:00 2001 From: Alexander Watzinger Date: Wed, 20 Sep 2023 14:33:21 +0200 Subject: [PATCH 04/32] Fix order of add_dynamic buttons --- openatlas/forms/field.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openatlas/forms/field.py b/openatlas/forms/field.py index 5ede9e1a9..138ed3051 100644 --- a/openatlas/forms/field.py +++ b/openatlas/forms/field.py @@ -250,6 +250,7 @@ def __init__( self.related_tables = related_tables or [] self.add_dynamical = \ (add_dynamic or []) if is_authorized('editor') else [] + self.add_dynamical.reverse() # Reverse needed (CSS .float-end) widget = TableSelect() From a94daa4e1b36dfec3db25efa7b3ac195aa74e6b1 Mon Sep 17 00:00:00 2001 From: BernhardKoschicek Date: Fri, 22 Sep 2023 09:26:22 +0200 Subject: [PATCH 05/32] ext references for vocabs import hierarchies --- openatlas/api/import_scripts/vocabs.py | 16 +++++++++++----- openatlas/views/vocabs.py | 11 +++++------ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/openatlas/api/import_scripts/vocabs.py b/openatlas/api/import_scripts/vocabs.py index 9ef1cb6cf..48b1efc47 100644 --- a/openatlas/api/import_scripts/vocabs.py +++ b/openatlas/api/import_scripts/vocabs.py @@ -37,6 +37,9 @@ def fetch_top_groups( hierarchy, 'custom', form_data['classes'], form_data['multiple']) + exact_match_id = get_exact_match().id + name = group[0].rsplit('/', 1)[-1] + ref.link('P67', hierarchy, name, type_id=exact_match_id) import_member( group[0], id_, @@ -44,8 +47,9 @@ def fetch_top_groups( ref, hierarchy) count.append(group[0]) - if Type.check_hierarchy_exists(group[1]): - duplicates.append(group[0]) + if (Type.check_hierarchy_exists(group[1]) + and group[0] in form_data['top_concepts']): + duplicates.append(group[1]) return count, duplicates @@ -55,7 +59,6 @@ def import_member( lang: str, ref: ReferenceSystem, super_: Optional[Entity], ) -> bool: - exact_match_id = get_exact_match().id req = vocabs_requests(id_, 'groupMembers', {'uri': uri, 'lang': lang}) child = None for member in req['members']: @@ -63,7 +66,7 @@ def import_member( if super_: child = Entity.insert('type', member['prefLabel']) child.link('P127', super_) - ref.link('P67', child, name, type_id=exact_match_id) + ref.link('P67', child, name, type_id=get_exact_match().id) if member['hasMembers']: import_member(member['uri'], id_, lang, ref, child) return True @@ -88,6 +91,9 @@ def fetch_top_level( hierarchy, 'custom', form_data['classes'], form_data['multiple']) + exact_match_id = get_exact_match().id + name = entry['uri'].rsplit('/', 1)[-1] + ref.link('P67', hierarchy, name, type_id=exact_match_id) entry['subs'] = import_children( entry['uri'], id_, @@ -96,7 +102,7 @@ def fetch_top_level( hierarchy) count.append(entry) if Type.check_hierarchy_exists(entry['label']): - duplicates.append(entry) + duplicates.append(entry['label']) return count, duplicates diff --git a/openatlas/views/vocabs.py b/openatlas/views/vocabs.py index d9656ea65..b4e6d5793 100644 --- a/openatlas/views/vocabs.py +++ b/openatlas/views/vocabs.py @@ -160,20 +160,19 @@ class ImportVocabsHierarchyForm(FlaskForm): 'classes': form.classes.data, 'multiple': form.multiple.data, 'language': form.language.data} - try: results = import_vocabs_data(id_, form_data, details, category) count = len(results[0]) Transaction.commit() g.logger.log('info', 'import', f'import: {count} top concepts') - for duplicate in results[1]: - g.logger.log( - 'notice', - 'import', - f'Did not import {duplicate["label"]}, duplicate.') import_str = f"{_('import of')}: {count} {_('top concepts')}" if results[1]: import_str += f'. {_("Check log for not imported concepts")}' + for duplicate in results[1]: + g.logger.log( + 'info', + 'import', + f'Did not import "{duplicate}", duplicate.') flash(import_str, 'info') except Exception as e: # pragma: no cover Transaction.rollback() From 2a648c91fb52f6612e4851c2c35d21f83ee62559 Mon Sep 17 00:00:00 2001 From: Alexander Watzinger Date: Fri, 22 Sep 2023 14:35:28 +0200 Subject: [PATCH 06/32] Resolving/reducing imports at localization --- openatlas/__init__.py | 5 ++-- openatlas/display/util.py | 5 +--- openatlas/models/cidoc_class.py | 22 ++++++----------- openatlas/models/cidoc_property.py | 38 ++++++++++-------------------- 4 files changed, 24 insertions(+), 46 deletions(-) diff --git a/openatlas/__init__.py b/openatlas/__init__.py index 97438a874..92a75bf56 100644 --- a/openatlas/__init__.py +++ b/openatlas/__init__.py @@ -29,6 +29,7 @@ file, hierarchy, index, imports, link, login, model, note, overlay, profile, search, sql, type as type_, user, vocabs) + @babel.localeselector def get_locale() -> str: if 'language' in session: @@ -55,8 +56,8 @@ def before_request() -> None: g.cursor = g.db.cursor(cursor_factory=extras.DictCursor) g.settings = Settings.get_settings() session['language'] = get_locale() - g.cidoc_classes = CidocClass.get_all() - g.properties = CidocProperty.get_all() + g.cidoc_classes = CidocClass.get_all(session['language']) + g.properties = CidocProperty.get_all(session['language']) g.classes = OpenatlasClass.get_all() g.types = Type.get_all() g.reference_systems = ReferenceSystem.get_all() diff --git a/openatlas/display/util.py b/openatlas/display/util.py index 7ab463d7c..fa89332d5 100644 --- a/openatlas/display/util.py +++ b/openatlas/display/util.py @@ -739,10 +739,7 @@ def datetime64_to_timestamp(date: Optional[numpy.datetime64]) -> Optional[str]: def get_entities_linked_to_type_recursive( id_: int, data: list[Entity]) -> list[Entity]: - for entity in g.types[id_].get_linked_entities( - ['P2', 'P89'], - inverse=True, - types=True): + for entity in g.types[id_].get_linked_entities(['P2', 'P89'], True, True): data.append(entity) for sub_id in g.types[id_].subs: get_entities_linked_to_type_recursive(sub_id, data) diff --git a/openatlas/models/cidoc_class.py b/openatlas/models/cidoc_class.py index 1f4c95a08..fa8c683b4 100644 --- a/openatlas/models/cidoc_class.py +++ b/openatlas/models/cidoc_class.py @@ -11,7 +11,7 @@ class CidocClass: def __init__(self, data: dict[str, Any]) -> None: - self._name = data['name'] + self.name = data['name'] self.code = data['code'] self.id = data['id'] self.comment = data['comment'] @@ -20,25 +20,17 @@ def __init__(self, data: dict[str, Any]) -> None: self.sub: list[CidocClass] = [] self.super: list[CidocClass] = [] - @property - def name(self) -> str: - return self.get_i18n() - - def get_i18n(self) -> str: - from openatlas import get_locale - name = getattr(self, '_name') - if get_locale() in self.i18n: - name = self.i18n[get_locale()] - elif g.settings['default_language'] in self.i18n: - name = self.i18n[g.settings['default_language']] - return name - @staticmethod - def get_all() -> dict[str, CidocClass]: + def get_all(language: str) -> dict[str, CidocClass]: classes = {row['code']: CidocClass(row) for row in Db.get_classes()} for row in Db.get_hierarchy(): classes[row['super_code']].sub.append(row['sub_code']) classes[row['sub_code']].super.append(row['super_code']) for row in Db.get_translations(app.config['LANGUAGES']): classes[row['class_code']].i18n[row['language_code']] = row['text'] + for class_ in classes.values(): + if language in class_.i18n: + class_.name = class_.i18n[language] + elif g.settings['default_language'] in class_.i18n: + class_.name = class_.i18n[g.settings['default_language']] return classes diff --git a/openatlas/models/cidoc_property.py b/openatlas/models/cidoc_property.py index 341a70ff7..f859218f6 100644 --- a/openatlas/models/cidoc_property.py +++ b/openatlas/models/cidoc_property.py @@ -12,8 +12,8 @@ class CidocProperty: def __init__(self, data: dict[str, Any]) -> None: self.id = data['id'] - self._name = data['name'] - self._name_inverse = data['name_inverse'] + self.name = data['name'] + self.name_inverse = data['name_inverse'] self.code = data['code'] self.comment = data['comment'] self.domain_class_code = data['domain_class_code'] @@ -24,28 +24,6 @@ def __init__(self, data: dict[str, Any]) -> None: self.i18n: dict[str, str] = {} self.i18n_inverse: dict[str, str] = {} - @property - def name(self) -> str: - from openatlas import get_locale - locale_session = get_locale() - name = getattr(self, '_name') - if locale_session in self.i18n: - name = self.i18n[locale_session] - elif g.settings['default_language'] in self.i18n: - name = self.i18n[g.settings['default_language']] - return name - - @property - def name_inverse(self) -> str: - from openatlas import get_locale - locale_session = get_locale() - name = getattr(self, '_name_inverse') - if locale_session in self.i18n_inverse: - name = self.i18n_inverse[locale_session] - elif g.settings['default_language'] in self.i18n_inverse: - name = self.i18n_inverse[g.settings['default_language']] - return name - def find_object(self, attr: str, class_id: int) -> bool: valid_domain_id = getattr(self, attr) if valid_domain_id == class_id: @@ -70,7 +48,7 @@ def find_subs( return False @staticmethod - def get_all() -> dict[str, CidocProperty]: + def get_all(language: str) -> dict[str, CidocProperty]: properties = { row['code']: CidocProperty(row) for row in Db.get_properties()} for row in Db.get_hierarchy(): @@ -81,4 +59,14 @@ def get_all() -> dict[str, CidocProperty]: row['text'] properties[row['property_code']].i18n_inverse[ row['language_code']] = row['text_inverse'] + for property_ in properties.values(): + default = g.settings['default_language'] + if language in property_.i18n: + property_.name = property_.i18n[language] + elif default in property_.i18n: + property_.name = property_.i18n[default] + if language in property_.i18n_inverse: + property_.name_inverse = property_.i18n_inverse[language] + elif default in property_.i18n_inverse: + property_.name_inverse = property_.i18n_inverse[default] return properties From 01314d0d5417278ddc8a8d88c7d97e5d6f0cc7cd Mon Sep 17 00:00:00 2001 From: Alexander Watzinger Date: Fri, 22 Sep 2023 15:38:20 +0200 Subject: [PATCH 07/32] Re-arranging imports --- openatlas/display/util.py | 2 +- openatlas/models/imports.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openatlas/display/util.py b/openatlas/display/util.py index fa89332d5..a89a01596 100644 --- a/openatlas/display/util.py +++ b/openatlas/display/util.py @@ -26,7 +26,6 @@ from openatlas.models.cidoc_class import CidocClass from openatlas.models.cidoc_property import CidocProperty from openatlas.models.content import get_translation -from openatlas.models.imports import Project if TYPE_CHECKING: # pragma: no cover from openatlas.models.entity import Entity @@ -505,6 +504,7 @@ def link( external: bool = False) -> str: from openatlas.models.entity import Entity from openatlas.models.user import User + from openatlas.models.imports import Project html = '' if isinstance(object_, (str, LazyString)): js = f'onclick="{js}"' if js else '' diff --git a/openatlas/models/imports.py b/openatlas/models/imports.py index fe100e5e6..111ef6b28 100644 --- a/openatlas/models/imports.py +++ b/openatlas/models/imports.py @@ -4,6 +4,7 @@ from flask_login import current_user from openatlas.database.imports import Import as Db +from openatlas.display.util import sanitize class Project: @@ -52,7 +53,6 @@ def check_duplicates(class_: str, names: list[str]) -> list[str]: @staticmethod def update_project(project: Project) -> None: - from openatlas.display.util import sanitize Db.update_project( project.id, project.name, From ea137787fefbddd099416f83f9d31931ffd97418 Mon Sep 17 00:00:00 2001 From: Alexander Watzinger Date: Fri, 22 Sep 2023 15:53:58 +0200 Subject: [PATCH 08/32] Re-arrange imports for get_link_entitites_recursive --- openatlas/database/entity.py | 23 +++++++++++++++++++++++ openatlas/database/link.py | 23 ----------------------- openatlas/models/entity.py | 6 ++---- openatlas/models/link.py | 11 ----------- 4 files changed, 25 insertions(+), 38 deletions(-) diff --git a/openatlas/database/entity.py b/openatlas/database/entity.py index 64add3ccf..c95fe45e1 100644 --- a/openatlas/database/entity.py +++ b/openatlas/database/entity.py @@ -394,3 +394,26 @@ def get_roots( row['start_node']: { 'id': row['top_level'], 'name': row['name']} for row in g.cursor.fetchall()} + + @staticmethod + def get_linked_entities_recursive( + id_: int, + code: str, + inverse: bool) -> list[int]: + first = 'domain_id' if inverse else 'range_id' + second = 'range_id' if inverse else 'domain_id' + g.cursor.execute( + f""" + WITH RECURSIVE items AS ( + SELECT {first} + FROM model.link + WHERE {second} = %(id_)s AND property_code = %(code)s + UNION + SELECT l.{first} FROM model.link l + INNER JOIN items i ON + l.{second} = i.{first} + AND l.property_code = %(code)s + ) SELECT {first} FROM items; + """, + {'id_': id_, 'code': code}) + return [row[first] for row in g.cursor.fetchall()] diff --git a/openatlas/database/link.py b/openatlas/database/link.py index acd29e70a..da20453ca 100644 --- a/openatlas/database/link.py +++ b/openatlas/database/link.py @@ -51,29 +51,6 @@ def get_linked_entities(id_: int, codes: list[str]) -> list[int]: {'id_': id_, 'codes': tuple(codes)}) return [row['result_id'] for row in g.cursor.fetchall()] - @staticmethod - def get_linked_entities_recursive( - id_: int, - code: str, - inverse: bool) -> list[int]: - first = 'domain_id' if inverse else 'range_id' - second = 'range_id' if inverse else 'domain_id' - g.cursor.execute( - f""" - WITH RECURSIVE items AS ( - SELECT {first} - FROM model.link - WHERE {second} = %(id_)s AND property_code = %(code)s - UNION - SELECT l.{first} FROM model.link l - INNER JOIN items i ON - l.{second} = i.{first} - AND l.property_code = %(code)s - ) SELECT {first} FROM items; - """, - {'id_': id_, 'code': code}) - return [row[first] for row in g.cursor.fetchall()] - @staticmethod def get_linked_entities_inverse(id_: int, codes: list[str]) -> list[int]: g.cursor.execute( diff --git a/openatlas/models/entity.py b/openatlas/models/entity.py index 6bf6cd472..59b95587f 100644 --- a/openatlas/models/entity.py +++ b/openatlas/models/entity.py @@ -110,10 +110,8 @@ def get_linked_entities_recursive( code: str, inverse: bool = False, types: bool = False) -> list[Entity]: - return Link.get_linked_entities_recursive( - self.id, - code, - inverse=inverse, + return Entity.get_by_ids( + Db.get_linked_entities_recursive(self.id, code, inverse), types=types) def link(self, diff --git a/openatlas/models/link.py b/openatlas/models/link.py index 51e3e1d24..ba93a663c 100644 --- a/openatlas/models/link.py +++ b/openatlas/models/link.py @@ -102,17 +102,6 @@ def get_linked_entities( else Db.get_linked_entities(id_, codes), types=types) - @staticmethod - def get_linked_entities_recursive( - id_: int, - code: str, - inverse: bool = False, - types: bool = False) -> list[Entity]: - from openatlas.models.entity import Entity - return Entity.get_by_ids( - Db.get_linked_entities_recursive(id_, code, inverse), - types=types) - @staticmethod def get_linked_entity_safe( id_: int, From c7ee88bd4fa369ff0c6dbe5feaa47f8e6a7b746f Mon Sep 17 00:00:00 2001 From: Alexander Watzinger Date: Fri, 22 Sep 2023 16:22:15 +0200 Subject: [PATCH 09/32] Removing imports at tests --- openatlas/models/link.py | 9 +++++---- tests/test_actor.py | 3 +-- tests/test_involvement.py | 29 ++++++++++++++--------------- tests/test_relation.py | 3 +-- 4 files changed, 21 insertions(+), 23 deletions(-) diff --git a/openatlas/models/link.py b/openatlas/models/link.py index ba93a663c..4476bd90e 100644 --- a/openatlas/models/link.py +++ b/openatlas/models/link.py @@ -137,10 +137,11 @@ def get_links( in Entity.get_by_ids(entity_ids, types=True)} links = [] for row in result: - links.append(Link( - row, - domain=linked_entities[row['domain_id']], - range_=linked_entities[row['range_id']])) + links.append( + Link( + row, + domain=linked_entities[row['domain_id']], + range_=linked_entities[row['range_id']])) return links @staticmethod diff --git a/tests/test_actor.py b/tests/test_actor.py index 81c19a58e..3c5350af1 100644 --- a/tests/test_actor.py +++ b/tests/test_actor.py @@ -3,7 +3,6 @@ from flask import url_for from openatlas import app -from openatlas.models.link import Link from tests.base import TestBaseCase, get_hierarchy, insert @@ -144,7 +143,7 @@ def test_actor(self) -> None: with app.test_request_context(): app.preprocess_request() # type: ignore - link_ = Link.get_links(group.id, 'P107')[0] + link_ = group.get_links('P107')[0] rv = self.app.get( url_for('link_update', id_=link_.id, origin_id=group.id)) diff --git a/tests/test_involvement.py b/tests/test_involvement.py index d0dd11dda..9e3202306 100644 --- a/tests/test_involvement.py +++ b/tests/test_involvement.py @@ -1,9 +1,6 @@ -from typing import Any - from flask import url_for from openatlas import app -from openatlas.models.link import Link from tests.base import TestBaseCase, insert @@ -14,16 +11,18 @@ def test_involvement(self) -> None: with app.test_request_context(): app.preprocess_request() # type: ignore actor = insert('person', 'Captain Miller') + event = insert('acquisition', 'Event Horizon') - rv: Any = self.app.post( - url_for('insert', class_='acquisition'), + rv = self.app.post( + url_for('update', id_=event.id), data={ - 'name': 'Event Horizon', - 'begin_year_from': '949', - 'begin_month_from': '10', - 'begin_day_from': '8', - 'end_year_from': '1951'}) - event_id = int(rv.location.split('/')[-1]) + 'name': 'Event Horizon', + 'begin_year_from': '949', + 'begin_month_from': '10', + 'begin_day_from': '8', + 'end_year_from': '1951'}, + follow_redirects=True) + assert b'Event Horizon' in rv.data rv = self.app.post( url_for( @@ -31,7 +30,7 @@ def test_involvement(self) -> None: type_='involvement', origin_id=actor.id), data={ - 'event': str([event_id]), + 'event': str([event.id]), 'activity': 'P11', 'begin_year_from': '950', 'end_year_from': '1950'}, @@ -42,7 +41,7 @@ def test_involvement(self) -> None: url_for( 'insert_relation', type_='involvement', - origin_id=event_id), + origin_id=event.id), data={ 'actor': str([actor.id]), 'continue_': 'yes', @@ -50,12 +49,12 @@ def test_involvement(self) -> None: follow_redirects=True) assert b'Event Horizon' in rv.data - rv = self.app.get(url_for('view', id_=event_id)) + rv = self.app.get(url_for('view', id_=event.id)) assert b'Event Horizon' in rv.data with app.test_request_context(): app.preprocess_request() # type: ignore - link_ = Link.get_links(event_id, 'P22')[0] + link_ = event.get_links('P22')[0] rv = self.app.post( url_for('link_update', id_=link_.id, origin_id=actor.id), diff --git a/tests/test_relation.py b/tests/test_relation.py index e322a3a43..80c7be55c 100644 --- a/tests/test_relation.py +++ b/tests/test_relation.py @@ -1,7 +1,6 @@ from flask import url_for from openatlas import app -from openatlas.models.link import Link from tests.base import TestBaseCase, get_hierarchy, insert @@ -50,7 +49,7 @@ def test_relation(self) -> None: with app.test_request_context(): app.preprocess_request() # type: ignore - link_ = Link.get_links(actor.id, 'OA7')[0] + link_ = actor.get_links('OA7')[0] rv = self.app.post( url_for('type_move_entities', id_=sub_id), From c070bf30fdad2db49ce2ede68a900ceca4df54dc Mon Sep 17 00:00:00 2001 From: Alexander Watzinger Date: Fri, 22 Sep 2023 17:07:52 +0200 Subject: [PATCH 10/32] Re-arrange imports for get_links_of_entities --- openatlas/api/resources/model_mapper.py | 19 ++++++------ openatlas/database/entity.py | 40 +++++++++++++++++++++++++ openatlas/database/link.py | 40 ------------------------- openatlas/models/entity.py | 26 +++++++++++++++- openatlas/models/link.py | 26 ---------------- openatlas/views/entity.py | 9 +++--- 6 files changed, 79 insertions(+), 81 deletions(-) diff --git a/openatlas/api/resources/model_mapper.py b/openatlas/api/resources/model_mapper.py index 00e5ac209..712939b55 100644 --- a/openatlas/api/resources/model_mapper.py +++ b/openatlas/api/resources/model_mapper.py @@ -2,8 +2,9 @@ from flask import g -from openatlas.api.resources.error import EntityDoesNotExistError, \ - InvalidCidocClassCodeError, InvalidViewClassError, InvalidSystemClassError +from openatlas.api.resources.error import ( + EntityDoesNotExistError, InvalidCidocClassCodeError, InvalidViewClassError, + InvalidSystemClassError) from openatlas.models.entity import Entity from openatlas.models.link import Link @@ -28,12 +29,12 @@ def get_overview_counts() -> dict[str, int]: return Entity.get_overview_counts() -def get_by_cidoc_classes(class_codes: list[str]) -> list[Entity]: - class_codes = list(g.cidoc_classes) \ - if 'all' in class_codes else class_codes - if not all(cc in g.cidoc_classes for cc in class_codes): +def get_by_cidoc_classes(codes: list[str]) -> list[Entity]: + if 'all' in codes: + codes = list(g.cidoc_classes) + elif not set(codes).issubset(g.cidoc_classes): raise InvalidCidocClassCodeError - return Entity.get_by_cidoc_class(class_codes, types=True, aliases=True) + return Entity.get_by_cidoc_class(codes, types=True, aliases=True) def get_entities_by_view_classes(codes: list[str]) -> list[Entity]: @@ -57,14 +58,14 @@ def get_all_links_of_entities( entities: Union[int, list[int]], codes: Union[str, list[str], None] = None) -> list[Link]: codes = list(g.properties) if not codes else codes - return Link.get_links(entities, codes) + return Entity.get_links_of_entities(entities, codes) def get_all_links_of_entities_inverse( entities: Union[int, list[int]], codes: Optional[Union[str, list[str]]] = None) -> list[Link]: codes = list(g.properties) if not codes else codes - return Link.get_links(entities, codes, inverse=True) + return Entity.get_links_of_entities(entities, codes, inverse=True) def flatten_list_and_remove_duplicates(list_: list[Any]) -> list[Any]: diff --git a/openatlas/database/entity.py b/openatlas/database/entity.py index c95fe45e1..93f5a0e58 100644 --- a/openatlas/database/entity.py +++ b/openatlas/database/entity.py @@ -417,3 +417,43 @@ def get_linked_entities_recursive( """, {'id_': id_, 'code': code}) return [row[first] for row in g.cursor.fetchall()] + + @staticmethod + def get_links_of_entities( + entities: Union[int, list[int]], + codes: Union[str, list[str], None], + inverse: bool = False) -> list[dict[str, Any]]: + sql = f""" + SELECT + l.id, l.property_code, + l.domain_id, + l.range_id, + l.description, + l.created, + l.modified, + e.name, + l.type_id, + COALESCE(to_char(l.begin_from, 'yyyy-mm-dd hh24:mi:ss BC'), '') + AS begin_from, l.begin_comment, + COALESCE(to_char(l.begin_to, 'yyyy-mm-dd hh24:mi:ss BC'), '') + AS begin_to, + COALESCE(to_char(l.end_from, 'yyyy-mm-dd hh24:mi:ss BC'), '') + AS end_from, l.end_comment, + COALESCE(to_char(l.end_to, 'yyyy-mm-dd hh24:mi:ss BC'), '') + AS end_to + FROM model.link l + JOIN model.entity e + ON l.{'domain' if inverse else 'range'}_id = e.id """ + if codes: + codes = codes if isinstance(codes, list) else [codes] + sql += ' AND l.property_code IN %(codes)s ' + sql += f""" + WHERE l.{'range' if inverse else 'domain'}_id IN %(entities)s + GROUP BY l.id, e.name + ORDER BY e.name;""" + g.cursor.execute( + sql, { + 'entities': tuple( + entities if isinstance(entities, list) else [entities]), + 'codes': tuple(codes) if codes else ''}) + return [dict(row) for row in g.cursor.fetchall()] diff --git a/openatlas/database/link.py b/openatlas/database/link.py index da20453ca..11b60df26 100644 --- a/openatlas/database/link.py +++ b/openatlas/database/link.py @@ -62,46 +62,6 @@ def get_linked_entities_inverse(id_: int, codes: list[str]) -> list[int]: {'id_': id_, 'codes': tuple(codes)}) return [row['result_id'] for row in g.cursor.fetchall()] - @staticmethod - def get_links( - entities: Union[int, list[int]], - codes: Union[str, list[str], None], - inverse: bool = False) -> list[dict[str, Any]]: - sql = f""" - SELECT - l.id, l.property_code, - l.domain_id, - l.range_id, - l.description, - l.created, - l.modified, - e.name, - l.type_id, - COALESCE(to_char(l.begin_from, 'yyyy-mm-dd hh24:mi:ss BC'), '') - AS begin_from, l.begin_comment, - COALESCE(to_char(l.begin_to, 'yyyy-mm-dd hh24:mi:ss BC'), '') - AS begin_to, - COALESCE(to_char(l.end_from, 'yyyy-mm-dd hh24:mi:ss BC'), '') - AS end_from, l.end_comment, - COALESCE(to_char(l.end_to, 'yyyy-mm-dd hh24:mi:ss BC'), '') - AS end_to - FROM model.link l - JOIN model.entity e - ON l.{'domain' if inverse else 'range'}_id = e.id """ - if codes: - codes = codes if isinstance(codes, list) else [codes] - sql += ' AND l.property_code IN %(codes)s ' - sql += f""" - WHERE l.{'range' if inverse else 'domain'}_id IN %(entities)s - GROUP BY l.id, e.name - ORDER BY e.name;""" - g.cursor.execute( - sql, { - 'entities': tuple( - entities if isinstance(entities, list) else [entities]), - 'codes': tuple(codes) if codes else ''}) - return [dict(row) for row in g.cursor.fetchall()] - @staticmethod def delete_by_codes( entity_id: int, diff --git a/openatlas/models/entity.py b/openatlas/models/entity.py index 59b95587f..ea61cfd4b 100644 --- a/openatlas/models/entity.py +++ b/openatlas/models/entity.py @@ -165,7 +165,7 @@ def get_links( self, codes: Union[str, list[str]], inverse: bool = False) -> list[Link]: - return Link.get_links(self.id, codes, inverse) + return Entity.get_links_of_entities(self.id, codes, inverse) def delete(self) -> None: Entity.delete_(self.id) @@ -483,3 +483,27 @@ def get_roots( ids: list[int], inverse: bool = False) -> dict[int, Any]: return Db.get_roots(property_code, ids, inverse) + + @staticmethod + def get_links_of_entities( + entities: Union[int, list[int]], + codes: Union[str, list[str], None] = None, + inverse: bool = False) -> list[Link]: + entity_ids = set() + result = Db.get_links_of_entities( + entities, + codes if isinstance(codes, list) else [str(codes)], + inverse) + for row in result: + entity_ids.add(row['domain_id']) + entity_ids.add(row['range_id']) + linked_entities = { + e.id: e for e in Entity.get_by_ids(entity_ids, types=True)} + links = [] + for row in result: + links.append( + Link( + row, + domain=linked_entities[row['domain_id']], + range_=linked_entities[row['range_id']])) + return links diff --git a/openatlas/models/link.py b/openatlas/models/link.py index 4476bd90e..b15f147da 100644 --- a/openatlas/models/link.py +++ b/openatlas/models/link.py @@ -118,32 +118,6 @@ def get_linked_entity_safe( abort(418, f'Missing linked {code} for {id_}') return entity - @staticmethod - def get_links( - entities: Union[int, list[int]], - codes: Union[str, list[str], None] = None, - inverse: bool = False) -> list[Link]: - from openatlas.models.entity import Entity - entity_ids = set() - result = Db.get_links( - entities, - codes if isinstance(codes, list) else [str(codes)], - inverse) - for row in result: - entity_ids.add(row['domain_id']) - entity_ids.add(row['range_id']) - linked_entities = { - entity.id: entity for entity - in Entity.get_by_ids(entity_ids, types=True)} - links = [] - for row in result: - links.append( - Link( - row, - domain=linked_entities[row['domain_id']], - range_=linked_entities[row['range_id']])) - return links - @staticmethod def delete_by_codes( entity: Entity, diff --git a/openatlas/views/entity.py b/openatlas/views/entity.py index 786d8b2e8..26501f16a 100644 --- a/openatlas/views/entity.py +++ b/openatlas/views/entity.py @@ -123,12 +123,11 @@ def update(id_: int, copy: Optional[str] = None) -> Union[str, Response]: if entity.class_.view in ['artifact', 'place']: manager.entity.image_id = manager.entity.get_profile_image_id() if not manager.entity.image_id: - for link_ in manager.entity.get_links('P67', inverse=True): - domain = link_.domain - if domain.class_.view == 'file' \ - and get_base_table_data(domain)[3] \ + for l in manager.entity.get_links('P67', inverse=True): + if l.domain.class_.view == 'file' \ + and get_base_table_data(l.domain)[3] \ in app.config['DISPLAY_FILE_EXTENSIONS']: - manager.entity.image_id = domain.id + manager.entity.image_id = l.domain.id break return render_template( 'entity/update.html', From 215922c4617ae8655f062fa0b8ae5341251bac77 Mon Sep 17 00:00:00 2001 From: Alexander Watzinger Date: Fri, 22 Sep 2023 17:12:01 +0200 Subject: [PATCH 11/32] Pylint checks --- install/upgrade/database_upgrade.py | 1 + openatlas/database/link.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/install/upgrade/database_upgrade.py b/install/upgrade/database_upgrade.py index 21c1f9213..b69968dac 100644 --- a/install/upgrade/database_upgrade.py +++ b/install/upgrade/database_upgrade.py @@ -21,6 +21,7 @@ sys.path.insert(0, str(Path(__file__).parent.parent.parent)) +# pylint: disable=wrong-import-position from config.database_versions import DATABASE_VERSIONS from config.default import ( DATABASE_PASS, VERSION, DATABASE_VERSION, DATABASE_NAME, DATABASE_USER, diff --git a/openatlas/database/link.py b/openatlas/database/link.py index 11b60df26..a5aeecf9e 100644 --- a/openatlas/database/link.py +++ b/openatlas/database/link.py @@ -1,4 +1,4 @@ -from typing import Any, Union +from typing import Any from flask import g From 89f65be255be90776ea38a52551d344c4718c544 Mon Sep 17 00:00:00 2001 From: BernhardKoschicek Date: Mon, 25 Sep 2023 15:15:48 +0200 Subject: [PATCH 12/32] fixed bug with csv export and added more detailed tests --- openatlas/api/resources/resolve_endpoints.py | 4 +- tests/test_api.py | 39 ++++++++++++++------ 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/openatlas/api/resources/resolve_endpoints.py b/openatlas/api/resources/resolve_endpoints.py index 2102e88fa..a853cc2c6 100644 --- a/openatlas/api/resources/resolve_endpoints.py +++ b/openatlas/api/resources/resolve_endpoints.py @@ -104,9 +104,9 @@ def resolve_entity( parser: dict[str, Any]) \ -> Union[Response, dict[str, Any], tuple[Any, int]]: if parser['export'] == 'csv': - export_entities_csv(entity, entity.name) + return export_entities_csv(entity, entity.name) if parser['export'] == 'csvNetwork': - export_csv_for_network_analysis([entity], parser) + return export_csv_for_network_analysis([entity], parser) result = get_entity_formatted(entity, parser) if parser['format'] in app.config['RDF_FORMATS']: # pragma: nocover return Response( diff --git a/tests/test_api.py b/tests/test_api.py index d97f3b0be..8fded4bd4 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -99,19 +99,25 @@ def test_api(self) -> None: assert self.get_geom_properties(rv, 'objectName') assert self.get_geom_properties(rv, 'shapeType') - for rv in [ - self.app.get( - url_for('api_03.export_database', format_='xml')), - self.app.get( - url_for('api_03.export_database', format_='json')), - self.app.get( - url_for('api_03.export_database', format_='csv'))]: - assert b'Shire' in rv.data + rv = self.app.get( + url_for('api_03.export_database', format_='xml')) + assert b'Shire' in rv.data + assert 'application/xml' in rv.headers.get('Content-Type') + + rv = self.app.get( + url_for('api_03.export_database', format_='json')) + assert b'Shire' in rv.data + assert 'application/json' in rv.headers.get('Content-Type') + + rv = self.app.get(url_for('api_03.export_database', format_='csv')) + assert b'Shire' in rv.data + assert 'application/zip' in rv.headers.get('Content-Type') # ---Entity Endpoints--- # Test Entity rv = self.app.get( url_for('api_03.entity', id_=place.id, download=True)) + assert 'application/json' in rv.headers.get('Content-Type') rv = rv.get_json()['features'][0] assert self.get_bool(rv, '@id') assert self.get_bool(rv, 'type', 'Feature') @@ -159,6 +165,7 @@ def test_api(self) -> None: # Test entity in GeoJSON format rv = self.app.get(url_for( 'api_03.entity', id_=place.id, format='geojson')) + assert 'application/json' in rv.headers.get('Content-Type') rv = rv.get_json()['features'][0] assert self.get_bool(rv['geometry'], 'type') assert self.get_bool(rv['geometry'], 'coordinates') @@ -176,6 +183,7 @@ def test_api(self) -> None: rv = self.app.get(url_for( 'api_03.entity', id_=place.id, format='geojson-v2')) + assert 'application/json' in rv.headers.get('Content-Type') rv = rv.get_json()['features'][0] assert self.get_bool(rv['geometry'], 'type') assert self.get_bool( @@ -195,6 +203,7 @@ def test_api(self) -> None: # Test entity in Linked Open Usable Data rv = self.app.get( url_for('api_03.entity', id_=place.id, format='loud')) + assert 'application/json' in rv.headers.get('Content-Type') rv = rv.get_json() assert bool(rv['type'] == 'PhysicalThing') assert bool(rv['_label'] == 'Shire') @@ -228,15 +237,19 @@ def test_api(self) -> None: for rv in [ self.app.get( url_for('api_03.entity', id_=place.id, export='csv')), - self.app.get(url_for( - 'api_03.entity', id_=place.id, export='csvNetwork')), self.app.get(url_for( 'api_03.query', entities=location.id, cidoc_classes='E18', view_classes='artifact', system_classes='person', - export='csv')), + export='csv'))]: + assert b'Shire' in rv.data + assert 'text/csv' in rv.headers.get('Content-Type') + + for rv in [ + self.app.get(url_for( + 'api_03.entity', id_=place.id, export='csvNetwork')), self.app.get(url_for( 'api_03.query', entities=location.id, @@ -245,6 +258,7 @@ def test_api(self) -> None: system_classes='person', export='csvNetwork'))]: assert b'Shire' in rv.data + assert 'application/zip' in rv.headers.get('Content-Type') # Test Entities endpoints for rv in [ @@ -296,6 +310,7 @@ def test_api(self) -> None: column='system_class', download=True, actor=place.id))]: + assert 'application/json' in rv.headers.get('Content-Type') rv = rv.get_json() rv_results = rv['results'][0]['features'][0] rv_page = rv['pagination'] @@ -675,6 +690,7 @@ def test_api(self) -> None: self.app.get(url_for('api_03.subunits', id_=place.id)), self.app.get( url_for('api_03.subunits', id_=place.id, download=True))]: + assert 'application/json' in rv.headers.get('Content-Type') rv = rv.get_json()[str(place.id)] for item in rv: if item['id'] == place.id: @@ -739,6 +755,7 @@ def test_api(self) -> None: centroid=True, limit=0))]: assert b'(autogenerated)' in rv.data + assert 'application/json' in rv.headers.get('Content-Type') # Test Error Handling for rv in [ From 8c886769ebaa030a872bdaa56f0227416cf47a62 Mon Sep 17 00:00:00 2001 From: BernhardKoschicek Date: Fri, 29 Sep 2023 14:18:26 +0200 Subject: [PATCH 13/32] impemented and documented --- openatlas/api/endpoints/display_image.py | 38 +- openatlas/api/resources/parser.py | 7 + openatlas/api/resources/templates.py | 15 + openatlas/api/routes.py | 6 +- openatlas/api/swagger.json | 3912 ++++++++++++---------- 5 files changed, 2260 insertions(+), 1718 deletions(-) diff --git a/openatlas/api/endpoints/display_image.py b/openatlas/api/endpoints/display_image.py index 57dd85035..86d7f154d 100644 --- a/openatlas/api/endpoints/display_image.py +++ b/openatlas/api/endpoints/display_image.py @@ -1,14 +1,17 @@ from pathlib import Path as Pathlib_path +from typing import Any -from flask import Response, send_file -from flask_restful import Resource +from flask import Response, send_file, url_for +from flask_restful import Resource, marshal from openatlas import app from openatlas.api.resources.error import DisplayFileNotFoundError, \ NoLicenseError -from openatlas.api.resources.parser import image +from openatlas.api.resources.parser import image, files +from openatlas.api.resources.templates import licensed_file_template from openatlas.api.resources.util import get_license_name -from openatlas.api.resources.model_mapper import get_entity_by_id +from openatlas.api.resources.model_mapper import get_entity_by_id, \ + get_entities_by_system_classes, get_entities_by_ids from openatlas.display.util import get_file_path @@ -26,3 +29,30 @@ def get(filename: str) -> Response: if not filepath: raise DisplayFileNotFoundError return send_file(filepath, as_attachment=bool(parser['download'])) + + +class LicensedFileOverview(Resource): + @staticmethod + def get() -> tuple[Any, int]: + parser = files.parse_args() + if parser['file_id']: + entities = get_entities_by_ids(parser['file_id']) + else: + entities = get_entities_by_system_classes(['file']) + files_dict = {} + for entity in entities: + if license_ := get_license_name(entity): + if path := get_file_path(entity): + files_dict[path.stem] = { + 'extension': path.suffix, + 'display': url_for( + 'api.display', + filename=path.stem, + _external=True), + 'thumbnail': url_for( + 'api.display', + image_size='thumbnail', + filename=path.stem, + _external=True), + 'license': license_} + return marshal(files_dict, licensed_file_template(entities)), 200 diff --git a/openatlas/api/resources/parser.py b/openatlas/api/resources/parser.py index 16ea7d41e..3f58a312e 100644 --- a/openatlas/api/resources/parser.py +++ b/openatlas/api/resources/parser.py @@ -155,3 +155,10 @@ help="{error_msg}", case_sensitive=False, choices=list(size for size in app.config['IMAGE_SIZE'])) + +files = default.copy() +files.add_argument( + 'file_id', + type=int, + help="{error_msg}", + action='append') diff --git a/openatlas/api/resources/templates.py b/openatlas/api/resources/templates.py index cc9b07236..ec47da766 100644 --- a/openatlas/api/resources/templates.py +++ b/openatlas/api/resources/templates.py @@ -4,6 +4,8 @@ from flask_restful import fields from flask_restful.fields import Integer, List, Nested, String +from openatlas.models.entity import Entity + def geojson_template() -> dict[str, Any]: types = { @@ -304,3 +306,16 @@ def content_template() -> dict[str, Type[String]]: 'legalNotice': fields.String, 'siteName': fields.String, 'imageSizes': fields.Raw} + + +def licensed_file_template(entities: list[Entity]) -> dict[str, Any]: + file = { + 'display': fields.String, + 'thumbnail': fields.String, + 'extension': fields.String, + 'license': fields.String} + + dict_: dict[str, Any] = defaultdict() + for entity in entities: + dict_[str(entity.id)] = fields.Nested(file) + return dict_ diff --git a/openatlas/api/routes.py b/openatlas/api/routes.py index 7228bbfc3..cf399de22 100644 --- a/openatlas/api/routes.py +++ b/openatlas/api/routes.py @@ -4,7 +4,7 @@ GetContent, SystemClassCount from openatlas.api.endpoints.special import GetGeometricEntities, \ ExportDatabase, GetSubunits -from openatlas.api.endpoints.display_image import DisplayImage +from openatlas.api.endpoints.display_image import DisplayImage, LicensedFileOverview from openatlas.api.endpoints.entities import GetByCidocClass, \ GetBySystemClass, GetByViewClass, GetEntitiesLinkedToEntity, GetEntity, \ GetLatest, GetQuery, GetTypeEntities, GetTypeEntitiesAll @@ -93,3 +93,7 @@ def add_routes_v03(api: Api) -> None: DisplayImage, '/display/', endpoint='display') + api.add_resource( + LicensedFileOverview, + '/licensed_file_overview/', + endpoint='licensed_file_overview') diff --git a/openatlas/api/swagger.json b/openatlas/api/swagger.json index ad1423acb..6432d174f 100644 --- a/openatlas/api/swagger.json +++ b/openatlas/api/swagger.json @@ -1,1217 +1,1639 @@ { - "openapi" : "3.0.2", - "info" : { - "title" : "OpenAtlas API", - "description" : "An API that allows user to access data from an OpenAtlas instance.", - "version" : "0.4.1", - "contact" : { - "name" : "OpenAtlas", - "url" : "https://openatlas.eu", - "email" : "bernhard.koschicek-krombholz@oeaw.ac.at" + "openapi": "3.0.2", + "info": { + "title": "OpenAtlas API", + "description": "An API that allows user to access data from an OpenAtlas instance.", + "version": "0.4.1", + "contact": { + "name": "OpenAtlas", + "url": "https://openatlas.eu", + "email": "bernhard.koschicek-krombholz@oeaw.ac.at" }, - "license" : { - "name" : "GPL-2.0", - "url" : "https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html" + "license": { + "name": "GPL-2.0", + "url": "https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html" } }, - "servers" : [ { - "url" : "https://demo.openatlas.eu/api/{version}", - "description" : "Demo Server", - "variables" : { - "version" : { - "default" : "0.3", - "enum" : [ "0.3" ] + "servers": [ + { + "url": "https://demo.openatlas.eu/api/{version}", + "description": "Demo Server", + "variables": { + "version": { + "default": "0.3", + "enum": [ + "0.3" + ] + } } - } - }, { - "url" : "https://demo-dev.openatlas.eu/api/{version}", - "description" : "Demo Dev Server", - "variables" : { - "version" : { - "default" : "0.3", - "enum" : [ "0.3" ] + }, + { + "url": "https://demo-dev.openatlas.eu/api/{version}", + "description": "Demo Dev Server", + "variables": { + "version": { + "default": "0.3", + "enum": [ + "0.3" + ] + } } - } - }, { - "url" : "http://localhost:5000/api/{version}", - "description" : "Used directly in an OpenAtlas instance", - "variables" : { - "version" : { - "default" : "0.3", - "enum" : [ "0.3" ] + }, + { + "url": "http://localhost:5000/api/{version}", + "description": "Used directly in an OpenAtlas instance", + "variables": { + "version": { + "default": "0.3", + "enum": [ + "0.3" + ] + } } } - } ], - "externalDocs" : { - "description" : "OpenAtlas Manual", - "url" : "https://manual.openatlas.eu/" + ], + "externalDocs": { + "description": "OpenAtlas Manual", + "url": "https://manual.openatlas.eu/" }, - "tags" : [ { - "name" : "Entity Endpoint", - "description" : "Endpoint provide information about one entity in the OpenAtlas instance. The requested information is provided in Linked Places format (LPF). Alternatively, GeoJSON or RDFs, derived from the LPF data, can be accessed." - }, { - "name" : "Entity Query Endpoint", - "description" : "Endpoint provide information about one entity in the OpenAtlas instance. The requested information is provided in Linked Places format (LPF). Alternatively, GeoJSON or RDFs, derived from the LPF data, can be accessed. Combine several or all entities endpoints in one query." - }, { - "name" : "Entities Endpoint", - "description" : "Endpoints provide information about entities in the OpenAtlas instance. The requested information is provided in Linked Places format (LPF). Alternatively, GeoJSON or RDFs, derived from the LPF data, can be accessed." - }, { - "name" : "Type Endpoints", - "description" : "Provide information about Types of an OpenAtlas instance. The results are in JSON and in a custom format." - }, { - "name" : "Administrative Endpoints", - "description" : "Provide metadata of the OpenAtlas instance for presentation sites." - }, { - "name" : "Special Endpoints", - "description" : "Provides project-specific formats." - }, { - "name" : "Image Endpoints", - "description" : "Provides image files" - } ], - "paths" : { - "/entity/{entityId}" : { - "get" : { - "tags" : [ "Entity Endpoint" ], - "description" : "Retrieves all information about a single entity", - "summary" : "Get entity by ID", - "operationId" : "GetEntity", - "parameters" : [ { - "$ref" : "#/components/parameters/entityId" - }, { - "$ref" : "#/components/parameters/download" - }, { - "$ref" : "#/components/parameters/show" - }, { - "$ref" : "#/components/parameters/format" - }, { - "$ref" : "#/components/parameters/export" - } ], - "responses" : { - "200" : { - "description" : "/entity response", - "content" : { - "application/ld+json" : { - "schema" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/LinkedPlacesModel" - }, { - "$ref" : "#/components/schemas/GeoJSONModel" - } ] + "tags": [ + { + "name": "Entity Endpoint", + "description": "Endpoint provide information about one entity in the OpenAtlas instance. The requested information is provided in Linked Places format (LPF). Alternatively, GeoJSON or RDFs, derived from the LPF data, can be accessed." + }, + { + "name": "Entity Query Endpoint", + "description": "Endpoint provide information about one entity in the OpenAtlas instance. The requested information is provided in Linked Places format (LPF). Alternatively, GeoJSON or RDFs, derived from the LPF data, can be accessed. Combine several or all entities endpoints in one query." + }, + { + "name": "Entities Endpoint", + "description": "Endpoints provide information about entities in the OpenAtlas instance. The requested information is provided in Linked Places format (LPF). Alternatively, GeoJSON or RDFs, derived from the LPF data, can be accessed." + }, + { + "name": "Type Endpoints", + "description": "Provide information about Types of an OpenAtlas instance. The results are in JSON and in a custom format." + }, + { + "name": "Administrative Endpoints", + "description": "Provide metadata of the OpenAtlas instance for presentation sites." + }, + { + "name": "Special Endpoints", + "description": "Provides project-specific formats." + }, + { + "name": "Image Endpoints", + "description": "Provides image files" + } + ], + "paths": { + "/entity/{entityId}": { + "get": { + "tags": [ + "Entity Endpoint" + ], + "description": "Retrieves all information about a single entity", + "summary": "Get entity by ID", + "operationId": "GetEntity", + "parameters": [ + { + "$ref": "#/components/parameters/entityId" + }, + { + "$ref": "#/components/parameters/download" + }, + { + "$ref": "#/components/parameters/show" + }, + { + "$ref": "#/components/parameters/format" + }, + { + "$ref": "#/components/parameters/export" + } + ], + "responses": { + "200": { + "description": "/entity response", + "content": { + "application/ld+json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/LinkedPlacesModel" + }, + { + "$ref": "#/components/schemas/GeoJSONModel" + } + ] } } } }, - "404" : { - "description" : "Something went wrong. Please consult the error message." + "404": { + "description": "Something went wrong. Please consult the error message." } } } }, - "/query/" : { - "get" : { - "tags" : [ "Entities Endpoint", "Entity Query Endpoint" ], - "description" : "Retrieves a list with entity ID, CIDOC CRM code, system class, or menu item. Combine up to four of the Entities Endpoints in a single query. Each request has to be a new parameter.", - "summary" : "Combine several or all entities endpoints in one query", - "operationId" : "GetQuery", - "parameters" : [ { - "$ref" : "#/components/parameters/entities" - }, { - "$ref" : "#/components/parameters/view_classes" - }, { - "$ref" : "#/components/parameters/system_classes" - }, { - "$ref" : "#/components/parameters/cidoc_classes" - }, { - "$ref" : "#/components/parameters/download" - }, { - "$ref" : "#/components/parameters/count" - }, { - "$ref" : "#/components/parameters/show" - }, { - "$ref" : "#/components/parameters/format" - }, { - "$ref" : "#/components/parameters/export" - }, { - "$ref" : "#/components/parameters/column" - }, { - "$ref" : "#/components/parameters/sort" - }, { - "$ref" : "#/components/parameters/search" - }, { - "$ref" : "#/components/parameters/first" - }, { - "$ref" : "#/components/parameters/last" - }, { - "$ref" : "#/components/parameters/page" - }, { - "$ref" : "#/components/parameters/limit" - }, { - "$ref" : "#/components/parameters/type_id" - }, { - "$ref" : "#/components/parameters/relation_type" - } ], - "responses" : { - "200" : { - "description" : "Results of query", - "content" : { - "application/ld+json" : { - "schema" : { - "$ref" : "#/components/schemas/EntitiesOutputModel" + "/query/": { + "get": { + "tags": [ + "Entities Endpoint", + "Entity Query Endpoint" + ], + "description": "Retrieves a list with entity ID, CIDOC CRM code, system class, or menu item. Combine up to four of the Entities Endpoints in a single query. Each request has to be a new parameter.", + "summary": "Combine several or all entities endpoints in one query", + "operationId": "GetQuery", + "parameters": [ + { + "$ref": "#/components/parameters/entities" + }, + { + "$ref": "#/components/parameters/view_classes" + }, + { + "$ref": "#/components/parameters/system_classes" + }, + { + "$ref": "#/components/parameters/cidoc_classes" + }, + { + "$ref": "#/components/parameters/download" + }, + { + "$ref": "#/components/parameters/count" + }, + { + "$ref": "#/components/parameters/show" + }, + { + "$ref": "#/components/parameters/format" + }, + { + "$ref": "#/components/parameters/export" + }, + { + "$ref": "#/components/parameters/column" + }, + { + "$ref": "#/components/parameters/sort" + }, + { + "$ref": "#/components/parameters/search" + }, + { + "$ref": "#/components/parameters/first" + }, + { + "$ref": "#/components/parameters/last" + }, + { + "$ref": "#/components/parameters/page" + }, + { + "$ref": "#/components/parameters/limit" + }, + { + "$ref": "#/components/parameters/type_id" + }, + { + "$ref": "#/components/parameters/relation_type" + } + ], + "responses": { + "200": { + "description": "Results of query", + "content": { + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/EntitiesOutputModel" } } } }, - "404" : { - "description" : "Something went wrong. Please consult the error message." + "404": { + "description": "Something went wrong. Please consult the error message." } } } }, - "/system_class/{system_class}" : { - "get" : { - "tags" : [ "Entities Endpoint" ], - "description" : "Retrieves a list of entities, based on their OpenAtlas class name.", - "operationId" : "GetBySystemClass", - "parameters" : [ { - "$ref" : "#/components/parameters/system_class" - }, { - "$ref" : "#/components/parameters/download" - }, { - "$ref" : "#/components/parameters/count" - }, { - "$ref" : "#/components/parameters/show" - }, { - "$ref" : "#/components/parameters/format" - }, { - "$ref" : "#/components/parameters/export" - }, { - "$ref" : "#/components/parameters/column" - }, { - "$ref" : "#/components/parameters/sort" - }, { - "$ref" : "#/components/parameters/search" - }, { - "$ref" : "#/components/parameters/first" - }, { - "$ref" : "#/components/parameters/last" - }, { - "$ref" : "#/components/parameters/page" - }, { - "$ref" : "#/components/parameters/limit" - }, { - "$ref" : "#/components/parameters/type_id" - }, { - "$ref" : "#/components/parameters/relation_type" - } ], - "responses" : { - "200" : { - "description" : "Results of system class", - "content" : { - "application/ld+json" : { - "schema" : { - "$ref" : "#/components/schemas/EntitiesOutputModel" + "/system_class/{system_class}": { + "get": { + "tags": [ + "Entities Endpoint" + ], + "description": "Retrieves a list of entities, based on their OpenAtlas class name.", + "operationId": "GetBySystemClass", + "parameters": [ + { + "$ref": "#/components/parameters/system_class" + }, + { + "$ref": "#/components/parameters/download" + }, + { + "$ref": "#/components/parameters/count" + }, + { + "$ref": "#/components/parameters/show" + }, + { + "$ref": "#/components/parameters/format" + }, + { + "$ref": "#/components/parameters/export" + }, + { + "$ref": "#/components/parameters/column" + }, + { + "$ref": "#/components/parameters/sort" + }, + { + "$ref": "#/components/parameters/search" + }, + { + "$ref": "#/components/parameters/first" + }, + { + "$ref": "#/components/parameters/last" + }, + { + "$ref": "#/components/parameters/page" + }, + { + "$ref": "#/components/parameters/limit" + }, + { + "$ref": "#/components/parameters/type_id" + }, + { + "$ref": "#/components/parameters/relation_type" + } + ], + "responses": { + "200": { + "description": "Results of system class", + "content": { + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/EntitiesOutputModel" } } } }, - "404" : { - "description" : "Something went wrong. Please consult the error message." + "404": { + "description": "Something went wrong. Please consult the error message." } } } }, - "/view_class/{view_class}" : { - "get" : { - "tags" : [ "Entities Endpoint" ], - "description" : "Retrieves a list of entities based on their OpenAtlas menu items.", - "operationId" : "GetByViewClass", - "parameters" : [ { - "$ref" : "#/components/parameters/view_class" - }, { - "$ref" : "#/components/parameters/download" - }, { - "$ref" : "#/components/parameters/count" - }, { - "$ref" : "#/components/parameters/show" - }, { - "$ref" : "#/components/parameters/format" - }, { - "$ref" : "#/components/parameters/export" - }, { - "$ref" : "#/components/parameters/column" - }, { - "$ref" : "#/components/parameters/sort" - }, { - "$ref" : "#/components/parameters/search" - }, { - "$ref" : "#/components/parameters/first" - }, { - "$ref" : "#/components/parameters/last" - }, { - "$ref" : "#/components/parameters/page" - }, { - "$ref" : "#/components/parameters/limit" - }, { - "$ref" : "#/components/parameters/type_id" - }, { - "$ref" : "#/components/parameters/relation_type" - } ], - "responses" : { - "200" : { - "description" : "Results of view class", - "content" : { - "application/ld+json" : { - "schema" : { - "$ref" : "#/components/schemas/EntitiesOutputModel" + "/view_class/{view_class}": { + "get": { + "tags": [ + "Entities Endpoint" + ], + "description": "Retrieves a list of entities based on their OpenAtlas menu items.", + "operationId": "GetByViewClass", + "parameters": [ + { + "$ref": "#/components/parameters/view_class" + }, + { + "$ref": "#/components/parameters/download" + }, + { + "$ref": "#/components/parameters/count" + }, + { + "$ref": "#/components/parameters/show" + }, + { + "$ref": "#/components/parameters/format" + }, + { + "$ref": "#/components/parameters/export" + }, + { + "$ref": "#/components/parameters/column" + }, + { + "$ref": "#/components/parameters/sort" + }, + { + "$ref": "#/components/parameters/search" + }, + { + "$ref": "#/components/parameters/first" + }, + { + "$ref": "#/components/parameters/last" + }, + { + "$ref": "#/components/parameters/page" + }, + { + "$ref": "#/components/parameters/limit" + }, + { + "$ref": "#/components/parameters/type_id" + }, + { + "$ref": "#/components/parameters/relation_type" + } + ], + "responses": { + "200": { + "description": "Results of view class", + "content": { + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/EntitiesOutputModel" } } } }, - "404" : { - "description" : "Something went wrong. Please consult the error message." + "404": { + "description": "Something went wrong. Please consult the error message." } } } }, - "/cidoc_class/{cidoc_class}" : { - "get" : { - "tags" : [ "Entities Endpoint" ], - "description" : "Retrieve a list of entities, based on their CIDOC CRM class code.", - "operationId" : "GetByCidocClass", - "parameters" : [ { - "$ref" : "#/components/parameters/cidoc_class" - }, { - "$ref" : "#/components/parameters/download" - }, { - "$ref" : "#/components/parameters/count" - }, { - "$ref" : "#/components/parameters/show" - }, { - "$ref" : "#/components/parameters/format" - }, { - "$ref" : "#/components/parameters/export" - }, { - "$ref" : "#/components/parameters/column" - }, { - "$ref" : "#/components/parameters/sort" - }, { - "$ref" : "#/components/parameters/search" - }, { - "$ref" : "#/components/parameters/first" - }, { - "$ref" : "#/components/parameters/last" - }, { - "$ref" : "#/components/parameters/page" - }, { - "$ref" : "#/components/parameters/limit" - }, { - "$ref" : "#/components/parameters/type_id" - }, { - "$ref" : "#/components/parameters/relation_type" - } ], - "responses" : { - "200" : { - "description" : "Results of CIDOC class", - "content" : { - "application/ld+json" : { - "schema" : { - "$ref" : "#/components/schemas/EntitiesOutputModel" + "/cidoc_class/{cidoc_class}": { + "get": { + "tags": [ + "Entities Endpoint" + ], + "description": "Retrieve a list of entities, based on their CIDOC CRM class code.", + "operationId": "GetByCidocClass", + "parameters": [ + { + "$ref": "#/components/parameters/cidoc_class" + }, + { + "$ref": "#/components/parameters/download" + }, + { + "$ref": "#/components/parameters/count" + }, + { + "$ref": "#/components/parameters/show" + }, + { + "$ref": "#/components/parameters/format" + }, + { + "$ref": "#/components/parameters/export" + }, + { + "$ref": "#/components/parameters/column" + }, + { + "$ref": "#/components/parameters/sort" + }, + { + "$ref": "#/components/parameters/search" + }, + { + "$ref": "#/components/parameters/first" + }, + { + "$ref": "#/components/parameters/last" + }, + { + "$ref": "#/components/parameters/page" + }, + { + "$ref": "#/components/parameters/limit" + }, + { + "$ref": "#/components/parameters/type_id" + }, + { + "$ref": "#/components/parameters/relation_type" + } + ], + "responses": { + "200": { + "description": "Results of CIDOC class", + "content": { + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/EntitiesOutputModel" } } } }, - "404" : { - "description" : "Something went wrong. Please consult the error message." + "404": { + "description": "Something went wrong. Please consult the error message." } } } }, - "/latest/{limit}" : { - "get" : { - "tags" : [ "Entities Endpoint" ], - "description" : "Retrieve the last entered entities. n represents the amount of entities retrieved (between 1 and 100). The pagination information is always null.", - "operationId" : "GetLatest", - "parameters" : [ { - "in" : "path", - "name" : "limit", - "required" : true, - "schema" : { - "type" : "integer", - "maximum" : 100, - "minimum" : 1 - } - }, { - "$ref" : "#/components/parameters/download" - }, { - "$ref" : "#/components/parameters/show" - }, { - "$ref" : "#/components/parameters/format" - }, { - "$ref" : "#/components/parameters/export" - }, { - "$ref" : "#/components/parameters/column" - }, { - "$ref" : "#/components/parameters/sort" - }, { - "$ref" : "#/components/parameters/search" - }, { - "$ref" : "#/components/parameters/type_id" - }, { - "$ref" : "#/components/parameters/relation_type" - } ], - "responses" : { - "200" : { - "description" : "Last entered entities.", - "content" : { - "application/ld+json" : { - "schema" : { - "$ref" : "#/components/schemas/EntitiesOutputModel" + "/latest/{limit}": { + "get": { + "tags": [ + "Entities Endpoint" + ], + "description": "Retrieve the last entered entities. n represents the amount of entities retrieved (between 1 and 100). The pagination information is always null.", + "operationId": "GetLatest", + "parameters": [ + { + "in": "path", + "name": "limit", + "required": true, + "schema": { + "type": "integer", + "maximum": 100, + "minimum": 1 + } + }, + { + "$ref": "#/components/parameters/download" + }, + { + "$ref": "#/components/parameters/show" + }, + { + "$ref": "#/components/parameters/format" + }, + { + "$ref": "#/components/parameters/export" + }, + { + "$ref": "#/components/parameters/column" + }, + { + "$ref": "#/components/parameters/sort" + }, + { + "$ref": "#/components/parameters/search" + }, + { + "$ref": "#/components/parameters/type_id" + }, + { + "$ref": "#/components/parameters/relation_type" + } + ], + "responses": { + "200": { + "description": "Last entered entities.", + "content": { + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/EntitiesOutputModel" } } } }, - "404" : { - "description" : "Something went wrong. Please consult the error message." + "404": { + "description": "Something went wrong. Please consult the error message." } } } }, - "/type_entities/{entityId}" : { - "get" : { - "tags" : [ "Entities Endpoint" ], - "description" : "Used to retrieve a list of entities, based on their OpenAtlas type ID. For an endpoint that lists all available types click confer Types Endpoints", - "operationId" : "GetTypeEntities", - "parameters" : [ { - "$ref" : "#/components/parameters/entityId" - }, { - "$ref" : "#/components/parameters/download" - }, { - "$ref" : "#/components/parameters/count" - }, { - "$ref" : "#/components/parameters/show" - }, { - "$ref" : "#/components/parameters/format" - }, { - "$ref" : "#/components/parameters/export" - }, { - "$ref" : "#/components/parameters/column" - }, { - "$ref" : "#/components/parameters/sort" - }, { - "$ref" : "#/components/parameters/search" - }, { - "$ref" : "#/components/parameters/first" - }, { - "$ref" : "#/components/parameters/last" - }, { - "$ref" : "#/components/parameters/page" - }, { - "$ref" : "#/components/parameters/limit" - }, { - "$ref" : "#/components/parameters/type_id" - }, { - "$ref" : "#/components/parameters/relation_type" - } ], - "responses" : { - "200" : { - "description" : "Results of type entities", - "content" : { - "application/ld+json" : { - "schema" : { - "$ref" : "#/components/schemas/EntitiesOutputModel" + "/type_entities/{entityId}": { + "get": { + "tags": [ + "Entities Endpoint" + ], + "description": "Used to retrieve a list of entities, based on their OpenAtlas type ID. For an endpoint that lists all available types click confer Types Endpoints", + "operationId": "GetTypeEntities", + "parameters": [ + { + "$ref": "#/components/parameters/entityId" + }, + { + "$ref": "#/components/parameters/download" + }, + { + "$ref": "#/components/parameters/count" + }, + { + "$ref": "#/components/parameters/show" + }, + { + "$ref": "#/components/parameters/format" + }, + { + "$ref": "#/components/parameters/export" + }, + { + "$ref": "#/components/parameters/column" + }, + { + "$ref": "#/components/parameters/sort" + }, + { + "$ref": "#/components/parameters/search" + }, + { + "$ref": "#/components/parameters/first" + }, + { + "$ref": "#/components/parameters/last" + }, + { + "$ref": "#/components/parameters/page" + }, + { + "$ref": "#/components/parameters/limit" + }, + { + "$ref": "#/components/parameters/type_id" + }, + { + "$ref": "#/components/parameters/relation_type" + } + ], + "responses": { + "200": { + "description": "Results of type entities", + "content": { + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/EntitiesOutputModel" } } } }, - "404" : { - "description" : "Something went wrong. Please consult the error message." + "404": { + "description": "Something went wrong. Please consult the error message." } } } }, - "/type_entities_all/{entityId}" : { - "get" : { - "tags" : [ "Entities Endpoint" ], - "description" : "Used to retrieve a list of entities, based on their OpenAtlas type ID including all connected subtypes.. For an endpoint that lists all available types click confer Type Endpoints", - "operationId" : "GetTypeEntitiesAll", - "parameters" : [ { - "$ref" : "#/components/parameters/entityId" - }, { - "$ref" : "#/components/parameters/download" - }, { - "$ref" : "#/components/parameters/count" - }, { - "$ref" : "#/components/parameters/show" - }, { - "$ref" : "#/components/parameters/format" - }, { - "$ref" : "#/components/parameters/export" - }, { - "$ref" : "#/components/parameters/column" - }, { - "$ref" : "#/components/parameters/sort" - }, { - "$ref" : "#/components/parameters/search" - }, { - "$ref" : "#/components/parameters/first" - }, { - "$ref" : "#/components/parameters/last" - }, { - "$ref" : "#/components/parameters/page" - }, { - "$ref" : "#/components/parameters/limit" - }, { - "$ref" : "#/components/parameters/type_id" - }, { - "$ref" : "#/components/parameters/relation_type" - } ], - "responses" : { - "200" : { - "description" : "Results of type entities all", - "content" : { - "application/ld+json" : { - "schema" : { - "$ref" : "#/components/schemas/EntitiesOutputModel" + "/type_entities_all/{entityId}": { + "get": { + "tags": [ + "Entities Endpoint" + ], + "description": "Used to retrieve a list of entities, based on their OpenAtlas type ID including all connected subtypes.. For an endpoint that lists all available types click confer Type Endpoints", + "operationId": "GetTypeEntitiesAll", + "parameters": [ + { + "$ref": "#/components/parameters/entityId" + }, + { + "$ref": "#/components/parameters/download" + }, + { + "$ref": "#/components/parameters/count" + }, + { + "$ref": "#/components/parameters/show" + }, + { + "$ref": "#/components/parameters/format" + }, + { + "$ref": "#/components/parameters/export" + }, + { + "$ref": "#/components/parameters/column" + }, + { + "$ref": "#/components/parameters/sort" + }, + { + "$ref": "#/components/parameters/search" + }, + { + "$ref": "#/components/parameters/first" + }, + { + "$ref": "#/components/parameters/last" + }, + { + "$ref": "#/components/parameters/page" + }, + { + "$ref": "#/components/parameters/limit" + }, + { + "$ref": "#/components/parameters/type_id" + }, + { + "$ref": "#/components/parameters/relation_type" + } + ], + "responses": { + "200": { + "description": "Results of type entities all", + "content": { + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/EntitiesOutputModel" } } } }, - "404" : { - "description" : "Something went wrong. Please consult the error message." + "404": { + "description": "Something went wrong. Please consult the error message." } } } }, - "/entities_linked_to_entity/{entityId}" : { - "get" : { - "tags" : [ "Entities Endpoint" ], - "description" : "Retrieves a list of entities linked to the entity with the stated ID.", - "operationId" : "GetEntitiesLinkedToEntity", - "parameters" : [ { - "$ref" : "#/components/parameters/entityId" - }, { - "$ref" : "#/components/parameters/download" - }, { - "$ref" : "#/components/parameters/count" - }, { - "$ref" : "#/components/parameters/show" - }, { - "$ref" : "#/components/parameters/format" - }, { - "$ref" : "#/components/parameters/export" - }, { - "$ref" : "#/components/parameters/column" - }, { - "$ref" : "#/components/parameters/sort" - }, { - "$ref" : "#/components/parameters/search" - }, { - "$ref" : "#/components/parameters/first" - }, { - "$ref" : "#/components/parameters/last" - }, { - "$ref" : "#/components/parameters/page" - }, { - "$ref" : "#/components/parameters/limit" - }, { - "$ref" : "#/components/parameters/type_id" - }, { - "$ref" : "#/components/parameters/relation_type" - } ], - "responses" : { - "200" : { - "description" : "Results of entities linked to entity", - "content" : { - "application/ld+json" : { - "schema" : { - "$ref" : "#/components/schemas/EntitiesOutputModel" + "/entities_linked_to_entity/{entityId}": { + "get": { + "tags": [ + "Entities Endpoint" + ], + "description": "Retrieves a list of entities linked to the entity with the stated ID.", + "operationId": "GetEntitiesLinkedToEntity", + "parameters": [ + { + "$ref": "#/components/parameters/entityId" + }, + { + "$ref": "#/components/parameters/download" + }, + { + "$ref": "#/components/parameters/count" + }, + { + "$ref": "#/components/parameters/show" + }, + { + "$ref": "#/components/parameters/format" + }, + { + "$ref": "#/components/parameters/export" + }, + { + "$ref": "#/components/parameters/column" + }, + { + "$ref": "#/components/parameters/sort" + }, + { + "$ref": "#/components/parameters/search" + }, + { + "$ref": "#/components/parameters/first" + }, + { + "$ref": "#/components/parameters/last" + }, + { + "$ref": "#/components/parameters/page" + }, + { + "$ref": "#/components/parameters/limit" + }, + { + "$ref": "#/components/parameters/type_id" + }, + { + "$ref": "#/components/parameters/relation_type" + } + ], + "responses": { + "200": { + "description": "Results of entities linked to entity", + "content": { + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/EntitiesOutputModel" } } } }, - "404" : { - "description" : "Something went wrong. Please consult the error message." + "404": { + "description": "Something went wrong. Please consult the error message." } } } }, - "/type_overview/" : { - "get" : { - "tags" : [ "Type Endpoints" ], - "description" : "Retrieves a list of all OpenAtlas types sorted by custom, places, standard and value", - "operationId" : "GetTypeOverview", - "parameters" : [ { - "$ref" : "#/components/parameters/download" - } ], - "responses" : { - "200" : { - "description" : "List of all OpenAtlas types", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/TypeOverviewModel" + "/type_overview/": { + "get": { + "tags": [ + "Type Endpoints" + ], + "description": "Retrieves a list of all OpenAtlas types sorted by custom, places, standard and value", + "operationId": "GetTypeOverview", + "parameters": [ + { + "$ref": "#/components/parameters/download" + } + ], + "responses": { + "200": { + "description": "List of all OpenAtlas types", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TypeOverviewModel" } } } }, - "404" : { - "description" : "Something went wrong. Please consult the error message." + "404": { + "description": "Something went wrong. Please consult the error message." } } } }, - "/type_tree/" : { - "get" : { - "tags" : [ "Type Endpoints" ], - "description" : "Retrieves a list of all OpenAtlas types, including their information sorted by their IDs", - "operationId" : "GetTypeTree", - "parameters" : [ { - "$ref" : "#/components/parameters/download" - } ], - "responses" : { - "200" : { - "description" : "List of all OpenAtlas types", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/TypeTreeModel" + "/type_tree/": { + "get": { + "tags": [ + "Type Endpoints" + ], + "description": "Retrieves a list of all OpenAtlas types, including their information sorted by their IDs", + "operationId": "GetTypeTree", + "parameters": [ + { + "$ref": "#/components/parameters/download" + } + ], + "responses": { + "200": { + "description": "List of all OpenAtlas types", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TypeTreeModel" } } } }, - "404" : { - "description" : "Something went wrong. Please consult the error message." + "404": { + "description": "Something went wrong. Please consult the error message." } } } }, - "/type_by_view_class/" : { - "get" : { - "tags" : [ "Type Endpoints" ], - "description" : "Retrieves a list of all system types", - "operationId" : "GetTypeByViewClass", - "parameters" : [ { - "$ref" : "#/components/parameters/download" - } ], - "responses" : { - "200" : { - "description" : "List of all OpenAtlas types", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/TypesByViewClassModel" + "/type_by_view_class/": { + "get": { + "tags": [ + "Type Endpoints" + ], + "description": "Retrieves a list of all system types", + "operationId": "GetTypeByViewClass", + "parameters": [ + { + "$ref": "#/components/parameters/download" + } + ], + "responses": { + "200": { + "description": "List of all OpenAtlas types", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TypesByViewClassModel" } } } }, - "404" : { - "description" : "Something went wrong. Please consult the error message." + "404": { + "description": "Something went wrong. Please consult the error message." } } } }, - "/classes/" : { - "get" : { - "tags" : [ "Administrative Endpoints" ], - "description" : "Retrieves a list of all available classes, their CIDOC CRM mapping, their view, which icon can be used, if alias and references systems are allowed and which standard type it has.", - "operationId" : "ClassMapping", - "responses" : { - "200" : { - "description" : "List of all classes for presentation sites", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ClassesModel" + "/classes/": { + "get": { + "tags": [ + "Administrative Endpoints" + ], + "description": "Retrieves a list of all available classes, their CIDOC CRM mapping, their view, which icon can be used, if alias and references systems are allowed and which standard type it has.", + "operationId": "ClassMapping", + "responses": { + "200": { + "description": "List of all classes for presentation sites", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClassesModel" } } } }, - "404" : { - "description" : "Something went wrong. Please consult the error message." + "404": { + "description": "Something went wrong. Please consult the error message." } } } }, - "/content/" : { - "get" : { - "tags" : [ "Administrative Endpoints" ], - "description" : "Retrieves a detailed list of information on available frontend content in an OpenAtlas instance - intro, legal notice, contact, and size of processed image", - "operationId" : "GetContent", - "parameters" : [ { - "$ref" : "#/components/parameters/lang" - }, { - "$ref" : "#/components/parameters/download" - } ], - "responses" : { - "200" : { - "description" : "OpenAtlas Content", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ContentModel" + "/content/": { + "get": { + "tags": [ + "Administrative Endpoints" + ], + "description": "Retrieves a detailed list of information on available frontend content in an OpenAtlas instance - intro, legal notice, contact, and size of processed image", + "operationId": "GetContent", + "parameters": [ + { + "$ref": "#/components/parameters/lang" + }, + { + "$ref": "#/components/parameters/download" + } + ], + "responses": { + "200": { + "description": "OpenAtlas Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentModel" } } } }, - "404" : { - "description" : "Something went wrong. Please consult the error message." + "404": { + "description": "Something went wrong. Please consult the error message." } } } }, - "/system_class_count/" : { - "get" : { - "tags" : [ "Administrative Endpoints" ], - "description" : "Retrieves a detailed list of the numbers of entries connected to a system class", - "operationId" : "SystemClassCount", - "responses" : { - "200" : { - "description" : "System class count", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/SystemClassCountModel" + "/system_class_count/": { + "get": { + "tags": [ + "Administrative Endpoints" + ], + "description": "Retrieves a detailed list of the numbers of entries connected to a system class", + "operationId": "SystemClassCount", + "responses": { + "200": { + "description": "System class count", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SystemClassCountModel" } } } }, - "404" : { - "description" : "Something went wrong. Please consult the error message." + "404": { + "description": "Something went wrong. Please consult the error message." } } } }, - "/subunits/" : { - "get" : { - "tags" : [ "Special Endpoints" ], - "description" : "Displays all subunits of a place in a special format as used by the THANADOS project. Can only be used for “places”. As format only XML can be chosen", - "operationId" : "GetSubunits", - "parameters" : [ { - "$ref" : "#/components/parameters/format" - }, { - "$ref" : "#/components/parameters/download" - }, { - "$ref" : "#/components/parameters/count" - } ], - "responses" : { - "200" : { - "description" : "One Place with all subunits", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/SubunitsModel" + "/subunits/": { + "get": { + "tags": [ + "Special Endpoints" + ], + "description": "Displays all subunits of a place in a special format as used by the THANADOS project. Can only be used for “places”. As format only XML can be chosen", + "operationId": "GetSubunits", + "parameters": [ + { + "$ref": "#/components/parameters/format" + }, + { + "$ref": "#/components/parameters/download" + }, + { + "$ref": "#/components/parameters/count" + } + ], + "responses": { + "200": { + "description": "One Place with all subunits", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubunitsModel" } } } }, - "404" : { - "description" : "Something went wrong. Please consult the error message." + "404": { + "description": "Something went wrong. Please consult the error message." } } } }, - "/geometric_entities/" : { - "get" : { - "tags" : [ "Special Endpoints" ], - "description" : "Retrieve a GeoJSON of all chosen geometries in an OpenAtlas instance", - "operationId" : "GetGeometricEntities", - "parameters" : [ { - "$ref" : "#/components/parameters/geometry" - }, { - "$ref" : "#/components/parameters/download" - }, { - "$ref" : "#/components/parameters/count" - } ], - "responses" : { - "200" : { - "description" : "All geometric entities", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/GeometricEntitiesModel" + "/geometric_entities/": { + "get": { + "tags": [ + "Special Endpoints" + ], + "description": "Retrieve a GeoJSON of all chosen geometries in an OpenAtlas instance", + "operationId": "GetGeometricEntities", + "parameters": [ + { + "$ref": "#/components/parameters/geometry" + }, + { + "$ref": "#/components/parameters/download" + }, + { + "$ref": "#/components/parameters/count" + } + ], + "responses": { + "200": { + "description": "All geometric entities", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GeometricEntitiesModel" } } } }, - "404" : { - "description" : "Something went wrong. Please consult the error message." + "404": { + "description": "Something went wrong. Please consult the error message." } } } }, - "/export_database/{format}" : { - "get" : { - "tags" : [ "Special Endpoints" ], - "description" : "Downloads all information in an OpenAtlas instance as CSV, XML, or JSON.", - "operationId" : "ExportDatabase", - "parameters" : [ { - "in" : "path", - "name" : "format", - "required" : true, - "schema" : { - "type" : "string", - "enum" : [ "json", "csv", "xml" ] - }, - "example" : "json" - } ], - "responses" : { - "200" : { - "description" : "Downloads complete database", - "content" : { - "application/json" : { - "schema" : { - "type" : "string", - "format" : "binary" + "/export_database/{format}": { + "get": { + "tags": [ + "Special Endpoints" + ], + "description": "Downloads all information in an OpenAtlas instance as CSV, XML, or JSON.", + "operationId": "ExportDatabase", + "parameters": [ + { + "in": "path", + "name": "format", + "required": true, + "schema": { + "type": "string", + "enum": [ + "json", + "csv", + "xml" + ] + }, + "example": "json" + } + ], + "responses": { + "200": { + "description": "Downloads complete database", + "content": { + "application/json": { + "schema": { + "type": "string", + "format": "binary" } } } }, - "404" : { - "description" : "Something went wrong. Please consult the error message." + "404": { + "description": "Something went wrong. Please consult the error message." } } } }, - "/display/{filename}" : { - "get" : { - "tags" : [ "Image Endpoints" ], - "description" : "Retrieves the respective image if it has a licence.", - "operationId" : "DisplayImage", - "parameters" : [ { - "in" : "path", - "name" : "filename", - "required" : true, - "schema" : { - "type" : "string" - } - }, { - "in": "query", - "name": "image_size", - "required": false, - "schema": { - "type": "string", - "enum": [ - "thumbnail", - "table"] - } - }], - "responses" : { - "200" : { - "description" : "Retrieves the respective image if it has a licence", - "content" : { - "image/jpeg" : { - "schema" : { - "type" : "string", - "format" : "binary" + "/display/{filename}": { + "get": { + "tags": [ + "Image Endpoints" + ], + "description": "Retrieves the respective image if it has a licence.", + "operationId": "DisplayImage", + "parameters": [ + { + "in": "path", + "name": "filename", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "image_size", + "required": false, + "schema": { + "type": "string", + "enum": [ + "thumbnail", + "table" + ] + } + } + ], + "responses": { + "200": { + "description": "Retrieves the respective image if it has a licence", + "content": { + "image/jpeg": { + "schema": { + "type": "string", + "format": "binary" } }, - "image/png" : { - "schema" : { - "type" : "string", - "format" : "binary" + "image/png": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Something went wrong. Please consult the error message." + } + } + } + }, + "/licensed_file_overview/": { + "get": { + "tags": [ + "Image Endpoints" + ], + "description": "Retrieves a list of display URL, thumbnail URL, extension and license of all files which exists and have a licence. With the paramater \"file_id\", only the given IDs where retrieved", + "operationId": "LicensedFileOverview", + "parameters": [ + { + "in": "query", + "name": "file_id", + "required": false, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Retrieves a list of display URL, thumbnail URL, extension and license of all files which exists and have a licence.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LicensedFileOverviewModel" } } } }, - "404" : { - "description" : "Something went wrong. Please consult the error message." + "404": { + "description": "Something went wrong. Please consult the error message." } } } } }, - "components" : { - "parameters" : { - "entityId" : { - "name" : "entityId", - "in" : "path", - "description" : "Specific entity ID", - "required" : true, - "schema" : { - "type" : "integer" + "components": { + "parameters": { + "entityId": { + "name": "entityId", + "in": "path", + "description": "Specific entity ID", + "required": true, + "schema": { + "type": "integer" }, - "example" : 40 + "example": 40 }, - "cidoc_class" : { - "name" : "cidoc_class", - "description" : "CIDOC class to be requested", - "required" : true, - "in" : "path", - "schema" : { - "enum" : [ "E5", "E7", "E8", "E9", "E12", "E18", "E20", "E21", "E22", "E31", "E32", "E33", "E41", "E53", "E54", "E55", "E65","E74" ] + "cidoc_class": { + "name": "cidoc_class", + "description": "CIDOC class to be requested", + "required": true, + "in": "path", + "schema": { + "enum": [ + "E5", + "E7", + "E8", + "E9", + "E12", + "E18", + "E20", + "E21", + "E22", + "E31", + "E32", + "E33", + "E41", + "E53", + "E54", + "E55", + "E65", + "E74" + ] }, - "example" : "E18" + "example": "E18" }, - "view_class" : { - "name" : "view_class", - "description" : "View class to be requested", - "required" : true, - "in" : "path", - "schema" : { - "enum" : [ "all", "actor", "artifact", "event", "place", "reference", "source", "artifact", "type", "file", "source_translation", "reference_system" ] + "view_class": { + "name": "view_class", + "description": "View class to be requested", + "required": true, + "in": "path", + "schema": { + "enum": [ + "all", + "actor", + "artifact", + "event", + "place", + "reference", + "source", + "artifact", + "type", + "file", + "source_translation", + "reference_system" + ] }, - "example" : "actor" + "example": "actor" }, - "system_class" : { - "name" : "system_class", - "description" : "System class to be requested", - "required" : true, - "in" : "path", - "schema" : { - "enum" : [ "all", "acquisition", "activity", "administrative_unit", "appellation", "artifact", "bibliography", "creation", "edition", "event", "external_reference", "feature", "file", "group", "human_remains", "move", "object_location", "person", "place", "production", "reference_system", "source", "source_translation", "stratigraphic_unit", "type", "tools"] + "system_class": { + "name": "system_class", + "description": "System class to be requested", + "required": true, + "in": "path", + "schema": { + "enum": [ + "all", + "acquisition", + "activity", + "administrative_unit", + "appellation", + "artifact", + "bibliography", + "creation", + "edition", + "event", + "external_reference", + "feature", + "file", + "group", + "human_remains", + "move", + "object_location", + "person", + "place", + "production", + "reference_system", + "source", + "source_translation", + "stratigraphic_unit", + "type", + "tools" + ] }, - "example" : "acquisition" + "example": "acquisition" }, - "download" : { - "name" : "download", - "description" : "Download results", - "in" : "query", - "schema" : { - "type" : "boolean" + "download": { + "name": "download", + "description": "Download results", + "in": "query", + "schema": { + "type": "boolean" } }, - "count" : { - "name" : "count", - "description" : "Just show count of how many entities would the result give back", - "in" : "query", - "schema" : { - "type" : "boolean" + "count": { + "name": "count", + "description": "Just show count of how many entities would the result give back", + "in": "query", + "schema": { + "type": "boolean" } }, - "lang" : { - "name" : "lang", - "description" : "Choose language", - "in" : "query", - "schema" : { - "type" : "string", - "enum" : [ "en", "de" ], - "example" : "de" + "lang": { + "name": "lang", + "description": "Choose language", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "en", + "de" + ], + "example": "de" } }, - "show" : { - "name" : "show", - "description" : "Select which keys should not be displayed. This can improve performance", - "in" : "query", - "explode" : true, - "schema" : { - "type" : "array", - "items" : { - "enum" : [ "when", "types", "relations", "names", "links", "geometry", "depictions", "geonames", "description", "none" ] + "show": { + "name": "show", + "description": "Select which keys should not be displayed. This can improve performance", + "in": "query", + "explode": true, + "schema": { + "type": "array", + "items": { + "enum": [ + "when", + "types", + "relations", + "names", + "links", + "geometry", + "depictions", + "geonames", + "description", + "none" + ] } } }, - "sort" : { - "name" : "sort", - "description" : "Sorting result ascending or descending of the given column. Default value is asc.", - "in" : "query", - "schema" : { - "type" : "string", - "enum" : [ "asc", "desc" ] + "sort": { + "name": "sort", + "description": "Sorting result ascending or descending of the given column. Default value is asc.", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ] }, - "example" : "asc" + "example": "asc" }, - "column" : { - "name" : "column", - "description" : "Choose one column to sort the results by. Default value is name.", - "in" : "query", - "schema" : { - "type" : "string", - "enum" : [ "id", "name", "cidoc_class", "system_class", "begin_from", "begin_to", "end_from", "end_to" ] + "column": { + "name": "column", + "description": "Choose one column to sort the results by. Default value is name.", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "id", + "name", + "cidoc_class", + "system_class", + "begin_from", + "begin_to", + "end_from", + "end_to" + ] }, - "example" : "name" + "example": "name" }, - "search" : { - "name" : "search", - "description" : "Search query for specific results.", - "in" : "query", - "schema" : { - "type" : "array", - "items" : { - "type" : "string" + "search": { + "name": "search", + "description": "Search query for specific results.", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string" } }, - "explode" : true + "explode": true }, - "limit" : { - "name" : "limit", - "description" : "Limits the entities displayed. Influences the performance of the request. Default value is 20. 0 means all available entities will be displayed.", - "in" : "query", - "schema" : { - "type" : "integer" + "limit": { + "name": "limit", + "description": "Limits the entities displayed. Influences the performance of the request. Default value is 20. 0 means all available entities will be displayed.", + "in": "query", + "schema": { + "type": "integer" } }, - "first" : { - "name" : "first", - "description" : "Begin results at the given entity id.", - "in" : "query", - "schema" : { - "type" : "integer" + "first": { + "name": "first", + "description": "Begin results at the given entity id.", + "in": "query", + "schema": { + "type": "integer" } }, - "last" : { - "name" : "last", - "description" : "Begin results after the given entity id.", - "in" : "query", - "schema" : { - "type" : "integer" + "last": { + "name": "last", + "description": "Begin results after the given entity id.", + "in": "query", + "schema": { + "type": "integer" } }, - "page" : { - "name" : "page", - "description" : "Jump to page number.", - "in" : "query", - "schema" : { - "type" : "integer" + "page": { + "name": "page", + "description": "Jump to page number.", + "in": "query", + "schema": { + "type": "integer" } }, - "export" : { - "name" : "export", - "description" : "Export the entities into either a simple CSV representation or a zip file of CSV's especially designed for network analyses.", - "in" : "query", - "schema" : { - "type" : "string", - "enum" : [ "csv", "csvNetwork" ] + "export": { + "name": "export", + "description": "Export the entities into either a simple CSV representation or a zip file of CSV's especially designed for network analyses.", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "csv", + "csvNetwork" + ] } }, - "format" : { - "name" : "format", - "description" : "Choose the format for the results.", - "in" : "query", - "schema" : { - "type" : "string", - "enum" : [ "lp", "geojson", "geojson-v2", "pretty-xml", "n3", "turtle", "nt", "xml" ] + "format": { + "name": "format", + "description": "Choose the format for the results.", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "lp", + "geojson", + "geojson-v2", + "pretty-xml", + "n3", + "turtle", + "nt", + "xml" + ] }, - "example" : "lp" + "example": "lp" }, - "type_id" : { - "name" : "type_id", - "description" : "Show only entities with the given type id.", - "in" : "query", - "schema" : { - "type" : "array", - "items" : { - "type" : "integer" + "type_id": { + "name": "type_id", + "description": "Show only entities with the given type id.", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "integer" } }, - "explode" : true + "explode": true }, - "relation_type" : { - "name" : "relation_type", - "description" : "Displays only connections connected by the selected CIDOC CRM code.", - "in" : "query", - "schema" : { - "type" : "array", - "items" : { - "type" : "string" + "relation_type": { + "name": "relation_type", + "description": "Displays only connections connected by the selected CIDOC CRM code.", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string" } }, - "explode" : true + "explode": true }, - "geometry" : { - "name" : "geometry", - "description" : "Filters which geometries will be received. Default is gisAll", - "in" : "query", - "schema" : { - "type" : "array", - "items" : { - "enum" : [ "gisAll", "gisPointAll", "gisPointSupers", "gisPointSubs", "gisPointSibling", "gisLineAll", "gisPolygonAll" ] + "geometry": { + "name": "geometry", + "description": "Filters which geometries will be received. Default is gisAll", + "in": "query", + "schema": { + "type": "array", + "items": { + "enum": [ + "gisAll", + "gisPointAll", + "gisPointSupers", + "gisPointSubs", + "gisPointSibling", + "gisLineAll", + "gisPolygonAll" + ] } }, - "explode" : true + "explode": true }, - "entities" : { - "name" : "entities", - "description" : "Entity ids which will be requested", - "in" : "query", - "schema" : { - "type" : "array", - "items" : { - "type" : "integer" + "entities": { + "name": "entities", + "description": "Entity ids which will be requested", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "integer" } }, - "explode" : true + "explode": true }, - "cidoc_classes" : { - "name" : "cidoc_classes", - "description" : "CIDOC classes to be requested", - "in" : "query", - "schema" : { - "type" : "array", - "items" : { - "enum" : [ "E6", "E7", "E8", "E9", "E12", "E18", "E20", "E21", "E22", "E31", "E32", "E33", "E41", "E53", "E54", "E55", "E74" ] + "cidoc_classes": { + "name": "cidoc_classes", + "description": "CIDOC classes to be requested", + "in": "query", + "schema": { + "type": "array", + "items": { + "enum": [ + "E6", + "E7", + "E8", + "E9", + "E12", + "E18", + "E20", + "E21", + "E22", + "E31", + "E32", + "E33", + "E41", + "E53", + "E54", + "E55", + "E74" + ] } }, - "explode" : true, - "example" : "E18" + "explode": true, + "example": "E18" }, - "view_classes" : { - "name" : "view_classes", - "description" : "View classes to be requested", - "in" : "query", - "schema" : { - "type" : "array", - "items" : { - "enum" : [ "all", "actor", "artifact", "event", "place", "reference", "source", "artifact", "type", "file", "source_translation", "reference_system" ] + "view_classes": { + "name": "view_classes", + "description": "View classes to be requested", + "in": "query", + "schema": { + "type": "array", + "items": { + "enum": [ + "all", + "actor", + "artifact", + "event", + "place", + "reference", + "source", + "artifact", + "type", + "file", + "source_translation", + "reference_system" + ] } }, - "explode" : true, - "example" : "actor" + "explode": true, + "example": "actor" }, - "system_classes" : { - "name" : "system_classes", - "description" : "System classes to be requested", - "in" : "query", - "schema" : { - "type" : "array", - "items" : { - "enum" : [ "all", "acquisition", "activity", "administrative_unit", "appellation", "artifact", "bibliography", "creation", "edition", "event", "external_reference", "feature", "file", "group", "human_remains", "move", "object_location", "person", "place", "production", "reference_system", "source", "source_translation", "stratigraphic_unit", "type", "tools"] + "system_classes": { + "name": "system_classes", + "description": "System classes to be requested", + "in": "query", + "schema": { + "type": "array", + "items": { + "enum": [ + "all", + "acquisition", + "activity", + "administrative_unit", + "appellation", + "artifact", + "bibliography", + "creation", + "edition", + "event", + "external_reference", + "feature", + "file", + "group", + "human_remains", + "move", + "object_location", + "person", + "place", + "production", + "reference_system", + "source", + "source_translation", + "stratigraphic_unit", + "type", + "tools" + ] } } }, - "image_size" : { - "name" : "image_size", - "description" : "Select which size of the image you want to display. Values are fixed but can be changed for each OpenAtlas instance. Thumbnail is 200px and table 100px.", - "in" : "query", - "schema" : { - "type" : "string", - "enum" : [ "thumbnail", "table" ] + "image_size": { + "name": "image_size", + "description": "Select which size of the image you want to display. Values are fixed but can be changed for each OpenAtlas instance. Thumbnail is 200px and table 100px.", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "thumbnail", + "table" + ] }, - "example" : "table" + "example": "table" } }, - "schemas" : { - "EntitiesOutputModel" : { - "type" : "object", - "properties" : { - "pagination" : { - "$ref" : "#/components/schemas/PaginationModel" - }, - "results" : { - "type" : "array", - "items" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/LinkedPlacesModel" - }, { - "$ref" : "#/components/schemas/GeoJSONModel" - } ] + "schemas": { + "EntitiesOutputModel": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/PaginationModel" + }, + "results": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/LinkedPlacesModel" + }, + { + "$ref": "#/components/schemas/GeoJSONModel" + } + ] } } } }, - "PaginationModel" : { - "type" : "object", - "properties" : { - "entities" : { - "type" : "integer" - }, - "entitiesPerPage" : { - "type" : "integer" - }, - "index" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/PaginationIndexModel" + "PaginationModel": { + "type": "object", + "properties": { + "entities": { + "type": "integer" + }, + "entitiesPerPage": { + "type": "integer" + }, + "index": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PaginationIndexModel" } }, - "totalPages" : { - "type" : "integer" + "totalPages": { + "type": "integer" } } }, - "PaginationIndexModel" : { - "type" : "object", - "properties" : { - "page" : { - "type" : "integer" - }, - "startId" : { - "type" : "integer" + "PaginationIndexModel": { + "type": "object", + "properties": { + "page": { + "type": "integer" + }, + "startId": { + "type": "integer" } } }, - "LinkedPlacesModel" : { - "properties" : { - "@context" : { - "type" : "string" - }, - "type" : { - "type" : "string" - }, - "features" : { - "type" : "array", - "items" : { - "type" : "object", - "properties" : { - "@id" : { - "type" : "string" + "LinkedPlacesModel": { + "properties": { + "@context": { + "type": "string" + }, + "type": { + "type": "string" + }, + "features": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@id": { + "type": "string" }, - "type" : { - "type" : "string" + "type": { + "type": "string" }, - "crmClass" : { - "type" : "string" + "crmClass": { + "type": "string" }, - "systemClass" : { - "type" : "string" + "systemClass": { + "type": "string" }, - "properties" : { - "type" : "object", - "properties" : { - "title" : { - "type" : "string" + "properties": { + "type": "object", + "properties": { + "title": { + "type": "string" } } }, - "descriptions" : { - "type" : "array", - "items" : { - "type" : "object", - "properties" : { - "value" : { - "type" : "string" + "descriptions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string" } } } }, - "when" : { - "type" : "object", - "properties" : { - "timespans" : { - "type" : "array", - "items" : { - "type" : "object", - "properties" : { - "start" : { - "type" : "object", - "properties" : { - "earliest" : { - "type" : "string", - "format" : "nullable" + "when": { + "type": "object", + "properties": { + "timespans": { + "type": "array", + "items": { + "type": "object", + "properties": { + "start": { + "type": "object", + "properties": { + "earliest": { + "type": "string", + "format": "nullable" }, - "latest" : { - "type" : "string", - "format" : "nullable" + "latest": { + "type": "string", + "format": "nullable" }, - "comment" : { - "type" : "string", - "format" : "nullable" + "comment": { + "type": "string", + "format": "nullable" } } }, - "end" : { - "type" : "object", - "properties" : { - "earliest" : { - "type" : "string", - "format" : "nullable" + "end": { + "type": "object", + "properties": { + "earliest": { + "type": "string", + "format": "nullable" }, - "latest" : { - "type" : "string", - "format" : "nullable" + "latest": { + "type": "string", + "format": "nullable" }, - "comment" : { - "type" : "string", - "format" : "nullable" + "comment": { + "type": "string", + "format": "nullable" } } } @@ -1220,99 +1642,99 @@ } } }, - "types" : { - "type" : "array", - "items" : { - "type" : "object", - "properties" : { - "identifier" : { - "type" : "string" + "types": { + "type": "array", + "items": { + "type": "object", + "properties": { + "identifier": { + "type": "string" }, - "label" : { - "type" : "string" + "label": { + "type": "string" }, - "descriptions" : { - "type" : "string", - "format" : "nullable" + "descriptions": { + "type": "string", + "format": "nullable" }, - "hierarchy" : { - "type" : "string" + "hierarchy": { + "type": "string" }, - "value" : { - "type" : "number", - "format" : "float" + "value": { + "type": "number", + "format": "float" }, - "unit" : { - "type" : "string", - "format" : "nullable" + "unit": { + "type": "string", + "format": "nullable" } } } }, - "relations" : { - "type" : "array", - "items" : { - "type" : "object", - "properties" : { - "label" : { - "type" : "string" + "relations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string" }, - "relationTo" : { - "type" : "string" + "relationTo": { + "type": "string" }, - "relationType" : { - "type" : "string" + "relationType": { + "type": "string" }, - "relationSystemClass" : { - "type" : "string" + "relationSystemClass": { + "type": "string" }, - "relationDescription" : { - "type" : "string", - "format" : "nullable" + "relationDescription": { + "type": "string", + "format": "nullable" }, - "type" : { - "type" : "string", - "format" : "nullable" + "type": { + "type": "string", + "format": "nullable" }, - "when" : { - "type" : "object", - "properties" : { - "timespans" : { - "type" : "array", - "items" : { - "type" : "object", - "properties" : { - "start" : { - "type" : "object", - "properties" : { - "earliest" : { - "type" : "string", - "format" : "nullable" + "when": { + "type": "object", + "properties": { + "timespans": { + "type": "array", + "items": { + "type": "object", + "properties": { + "start": { + "type": "object", + "properties": { + "earliest": { + "type": "string", + "format": "nullable" }, - "latest" : { - "type" : "string", - "format" : "nullable" + "latest": { + "type": "string", + "format": "nullable" }, - "comment" : { - "type" : "string", - "format" : "nullable" + "comment": { + "type": "string", + "format": "nullable" } } }, - "end" : { - "type" : "object", - "properties" : { - "earliest" : { - "type" : "string", - "format" : "nullable" + "end": { + "type": "object", + "properties": { + "earliest": { + "type": "string", + "format": "nullable" }, - "latest" : { - "type" : "string", - "format" : "nullable" + "latest": { + "type": "string", + "format": "nullable" }, - "comment" : { - "type" : "string", - "format" : "nullable" + "comment": { + "type": "string", + "format": "nullable" } } } @@ -1324,107 +1746,119 @@ } } }, - "names" : { - "type" : "string", - "format" : "nullable" + "names": { + "type": "string", + "format": "nullable" }, - "links" : { - "type" : "string", - "format" : "nullable" + "links": { + "type": "string", + "format": "nullable" }, - "depictions" : { - "type" : "string", - "format" : "nullable" + "depictions": { + "type": "string", + "format": "nullable" }, - "geometry" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Polygon" - }, { - "$ref" : "#/components/schemas/Point" - }, { - "$ref" : "#/components/schemas/LineString" - }, { - "$ref" : "#/components/schemas/GeometryCollection" - } ] + "geometry": { + "oneOf": [ + { + "$ref": "#/components/schemas/Polygon" + }, + { + "$ref": "#/components/schemas/Point" + }, + { + "$ref": "#/components/schemas/LineString" + }, + { + "$ref": "#/components/schemas/GeometryCollection" + } + ] } } } } } }, - "GeoJSONModel" : { - "type" : "object", - "properties" : { - "type" : { - "type" : "string", - "enum" : [ "FeatureCollection" ] - }, - "features" : { - "type" : "array", - "items" : { - "type" : "object", - "properties" : { - "type" : { - "type" : "string" + "GeoJSONModel": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "FeatureCollection" + ] + }, + "features": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string" }, - "geometry" : { - "oneOf" : [ { - "$ref" : "#/components/schemas/Polygon" - }, { - "$ref" : "#/components/schemas/Point" - }, { - "$ref" : "#/components/schemas/LineString" - }, { - "$ref" : "#/components/schemas/GeometryCollection" - } ] + "geometry": { + "oneOf": [ + { + "$ref": "#/components/schemas/Polygon" + }, + { + "$ref": "#/components/schemas/Point" + }, + { + "$ref": "#/components/schemas/LineString" + }, + { + "$ref": "#/components/schemas/GeometryCollection" + } + ] }, - "properties" : { - "type" : "object", - "properties" : { - "@id" : { - "type" : "integer" + "properties": { + "type": "object", + "properties": { + "@id": { + "type": "integer" }, - "systemClass" : { - "type" : "string" + "systemClass": { + "type": "string" }, - "name" : { - "type" : "string" + "name": { + "type": "string" }, - "description" : { - "type" : "string" + "description": { + "type": "string" }, - "begin_earliest" : { - "type" : "string" + "begin_earliest": { + "type": "string" }, - "begin_latest" : { - "type" : "string", - "format" : "nullable" + "begin_latest": { + "type": "string", + "format": "nullable" }, - "begin_comment" : { - "type" : "string", - "format" : "nullable" + "begin_comment": { + "type": "string", + "format": "nullable" }, - "end_earliest" : { - "type" : "string" + "end_earliest": { + "type": "string" }, - "end_latest" : { - "type" : "string", - "format" : "nullable" + "end_latest": { + "type": "string", + "format": "nullable" }, - "end_comment" : { - "type" : "string", - "format" : "nullable" + "end_comment": { + "type": "string", + "format": "nullable" }, - "types" : { - "type" : "array", - "items" : { - "type" : "object", - "properties" : { - "typeName" : { - "type" : "string" + "types": { + "type": "array", + "items": { + "type": "object", + "properties": { + "typeName": { + "type": "string" }, - "typeId" : { - "type" : "integer" + "typeId": { + "type": "integer" } } } @@ -1436,231 +1870,261 @@ } } }, - "Point" : { - "type" : "object", - "required" : [ "type", "coordinates" ], - "properties" : { - "type" : { - "type" : "string", - "enum" : [ "Point" ] + "Point": { + "type": "object", + "required": [ + "type", + "coordinates" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "Point" + ] }, - "coordinates" : { - "$ref" : "#/components/schemas/Position" + "coordinates": { + "$ref": "#/components/schemas/Position" }, - "title" : { - "type" : "string" + "title": { + "type": "string" }, - "description" : { - "type" : "string" + "description": { + "type": "string" }, - "shapeType" : { - "type" : "string", - "enum" : [ "centerpoint" ] + "shapeType": { + "type": "string", + "enum": [ + "centerpoint" + ] } } }, - "Position" : { - "type" : "array", - "minItems" : 2, - "maxItems" : 3, - "items" : { - "type" : "number" + "Position": { + "type": "array", + "minItems": 2, + "maxItems": 3, + "items": { + "type": "number" } }, - "LineString" : { - "type" : "object", - "required" : [ "type", "coordinates" ], - "properties" : { - "type" : { - "type" : "string", - "enum" : [ "LineString" ] + "LineString": { + "type": "object", + "required": [ + "type", + "coordinates" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "LineString" + ] }, - "coordinates" : { - "$ref" : "#/components/schemas/LineStringCoordinates" + "coordinates": { + "$ref": "#/components/schemas/LineStringCoordinates" }, - "title" : { - "type" : "string" + "title": { + "type": "string" }, - "description" : { - "type" : "string" + "description": { + "type": "string" }, - "shapeType" : { - "type" : "string", - "enum" : [ "polyline" ] + "shapeType": { + "type": "string", + "enum": [ + "polyline" + ] } } }, - "LineStringCoordinates" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/Position" + "LineStringCoordinates": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Position" }, - "minItems" : 2 + "minItems": 2 }, - "LinearRing" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/Position" + "LinearRing": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Position" }, - "minItems" : 4 + "minItems": 4 }, - "Polygon" : { - "type" : "object", - "required" : [ "type", "coordinates" ], - "properties" : { - "type" : { - "type" : "string", - "enum" : [ "Polygon" ] + "Polygon": { + "type": "object", + "required": [ + "type", + "coordinates" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "Polygon" + ] }, - "coordinates" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/LinearRing" + "coordinates": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LinearRing" } }, - "title" : { - "type" : "string" + "title": { + "type": "string" }, - "description" : { - "type" : "string" + "description": { + "type": "string" }, - "shapeType" : { - "type" : "string", - "enum" : [ "area", "shape" ] + "shapeType": { + "type": "string", + "enum": [ + "area", + "shape" + ] } } }, - "GeometryCollection" : { - "type" : "object", - "properties" : { - "type" : { - "type" : "string", - "enum" : [ "GeometryCollection" ] - }, - "geometries" : { - "type" : "array", - "items" : { - "anyOf" : [ { - "$ref" : "#/components/schemas/Polygon" - }, { - "$ref" : "#/components/schemas/Point" - }, { - "$ref" : "#/components/schemas/LineString" - } ] + "GeometryCollection": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "GeometryCollection" + ] + }, + "geometries": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/Polygon" + }, + { + "$ref": "#/components/schemas/Point" + }, + { + "$ref": "#/components/schemas/LineString" + } + ] } } }, - "required" : [ "type" ], - "discriminator" : { - "propertyName" : "type" + "required": [ + "type" + ], + "discriminator": { + "propertyName": "type" } }, - "TypeOverviewEntryModel" : { - "type" : "object", - "properties" : { - "id" : { - "type" : "integer", - "format" : "int32" - }, - "name" : { - "type" : "string" - }, - "viewClass" : { - "type" : "array", - "items" : { - "type" : "string" + "TypeOverviewEntryModel": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "viewClass": { + "type": "array", + "items": { + "type": "string" } }, - "children" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypeOverviewEntryModel" + "children": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypeOverviewEntryModel" } } } }, - "TypeOverviewModel" : { - "type" : "object", - "properties" : { - "standard" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypeOverviewEntryModel" + "TypeOverviewModel": { + "type": "object", + "properties": { + "standard": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypeOverviewEntryModel" } }, - "place" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypeOverviewEntryModel" + "place": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypeOverviewEntryModel" } }, - "custom" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypeOverviewEntryModel" + "custom": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypeOverviewEntryModel" } }, - "value" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypeOverviewEntryModel" + "value": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypeOverviewEntryModel" } }, - "system" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypeOverviewEntryModel" + "system": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypeOverviewEntryModel" } } } }, - "TypeTreeModel" : { - "type" : "object", - "properties" : { - "type_tree" : { - "type" : "object", - "properties" : { - "type_ids" : { - "type" : "object", - "properties" : { - "id" : { - "type" : "integer" + "TypeTreeModel": { + "type": "object", + "properties": { + "type_tree": { + "type": "object", + "properties": { + "type_ids": { + "type": "object", + "properties": { + "id": { + "type": "integer" }, - "name" : { - "type" : "string" + "name": { + "type": "string" }, - "description" : { - "type" : "string" + "description": { + "type": "string" }, - "origin_id" : { - "type" : "integer" + "origin_id": { + "type": "integer" }, - "first" : { - "type" : "integer" + "first": { + "type": "integer" }, - "last" : { - "type" : "integer" + "last": { + "type": "integer" }, - "root" : { - "type" : "array", - "items" : { - "type" : "integer" + "root": { + "type": "array", + "items": { + "type": "integer" } }, - "subs" : { - "type" : "array", - "items" : { - "type" : "integer" + "subs": { + "type": "array", + "items": { + "type": "integer" } }, - "count" : { - "type" : "integer" + "count": { + "type": "integer" }, - "count_subs" : { - "type" : "integer" + "count_subs": { + "type": "integer" }, - "category" : { - "type" : "string" + "category": { + "type": "string" } } } @@ -1668,545 +2132,545 @@ } } }, - "TypeViewClassChildren" : { - "type" : "object", - "properties" : { - "id" : { - "type" : "string" - }, - "label" : { - "type" : "string" - }, - "url" : { - "type" : "string" - }, - "children" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypeViewClassChildren" + "TypeViewClassChildren": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "url": { + "type": "string" + }, + "children": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypeViewClassChildren" } } } }, - "TypesByViewClassEntry" : { - "properties" : { - "children" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypeViewClassChildren" + "TypesByViewClassEntry": { + "properties": { + "children": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypeViewClassChildren" } }, - "id" : { - "type" : "integer" + "id": { + "type": "integer" }, - "name" : { - "type" : "string" + "name": { + "type": "string" }, - "category" : { - "type" : "string" + "category": { + "type": "string" } }, - "type" : "object" + "type": "object" }, - "TypesByViewClassModel" : { - "type" : "object", - "properties" : { - "acquisition" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypesByViewClassEntry" + "TypesByViewClassModel": { + "type": "object", + "properties": { + "acquisition": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypesByViewClassEntry" } }, - "activity" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypesByViewClassEntry" + "activity": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypesByViewClassEntry" } }, - "actor_actor_relation" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypesByViewClassEntry" + "actor_actor_relation": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypesByViewClassEntry" } }, - "actor_function" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypesByViewClassEntry" + "actor_function": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypesByViewClassEntry" } }, - "artifact" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypesByViewClassEntry" + "artifact": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypesByViewClassEntry" } }, - "bibliography" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypesByViewClassEntry" + "bibliography": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypesByViewClassEntry" } }, - "creation" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypesByViewClassEntry" + "creation": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypesByViewClassEntry" } }, - "edition" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypesByViewClassEntry" + "edition": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypesByViewClassEntry" } }, - "event" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypesByViewClassEntry" + "event": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypesByViewClassEntry" } }, - "external_reference" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypesByViewClassEntry" + "external_reference": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypesByViewClassEntry" } }, - "feature" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypesByViewClassEntry" + "feature": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypesByViewClassEntry" } }, - "file" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypesByViewClassEntry" + "file": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypesByViewClassEntry" } }, - "group" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypesByViewClassEntry" + "group": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypesByViewClassEntry" } }, - "human_remains" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypesByViewClassEntry" + "human_remains": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypesByViewClassEntry" } }, - "involvement" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypesByViewClassEntry" + "involvement": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypesByViewClassEntry" } }, - "move" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypesByViewClassEntry" + "move": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypesByViewClassEntry" } }, - "person" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypesByViewClassEntry" + "person": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypesByViewClassEntry" } }, - "place" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypesByViewClassEntry" + "place": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypesByViewClassEntry" } }, - "production" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypesByViewClassEntry" + "production": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypesByViewClassEntry" } }, - "source" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypesByViewClassEntry" + "source": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypesByViewClassEntry" } }, - "source_translation" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypesByViewClassEntry" + "source_translation": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypesByViewClassEntry" } }, - "stratigraphic_unit" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/TypesByViewClassEntry" + "stratigraphic_unit": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypesByViewClassEntry" } } } }, - "ClassesModel" : { - "type" : "array", - "items" : { - "type" : "object", - "properties" : { - "systemClass" : { - "type" : "string" + "ClassesModel": { + "type": "array", + "items": { + "type": "object", + "properties": { + "systemClass": { + "type": "string" }, - "crmClass" : { - "type" : "string" + "crmClass": { + "type": "string" }, - "view" : { - "type" : "string" + "view": { + "type": "string" }, - "icon" : { - "type" : "string" + "icon": { + "type": "string" }, - "en" : { - "type" : "string" + "en": { + "type": "string" } } } }, - "ContentModel" : { - "type" : "object", - "properties" : { - "intro" : { - "type" : "string" - }, - "contact" : { - "type" : "string" - }, - "legalNotice" : { - "type" : "string" - }, - "siteName" : { - "type" : "string" - }, - "imageSizes" : { - "type" : "object", - "properties" : { - "thumbnail" : { - "type" : "string" + "ContentModel": { + "type": "object", + "properties": { + "intro": { + "type": "string" + }, + "contact": { + "type": "string" + }, + "legalNotice": { + "type": "string" + }, + "siteName": { + "type": "string" + }, + "imageSizes": { + "type": "object", + "properties": { + "thumbnail": { + "type": "string" }, - "table" : { - "type" : "string" + "table": { + "type": "string" } } } } }, - "SystemClassCountModel" : { - "type" : "object", - "properties" : { - "move" : { - "type" : "integer", - "format" : "int32" - }, - "bibliography" : { - "type" : "integer", - "format" : "int32" - }, - "person" : { - "type" : "integer", - "format" : "int32" - }, - "acquisition" : { - "type" : "integer", - "format" : "int32" - }, - "reference_system" : { - "type" : "integer", - "format" : "int32" - }, - "feature" : { - "type" : "integer", - "format" : "int32" - }, - "file" : { - "type" : "integer", - "format" : "int32" - }, - "activity" : { - "type" : "integer", - "format" : "int32" - }, - "type" : { - "type" : "integer", - "format" : "int32" - }, - "administrative_unit" : { - "type" : "integer", - "format" : "int32" - }, - "artifact" : { - "type" : "integer", - "format" : "int32" - }, - "source_translation" : { - "type" : "integer", - "format" : "int32" - }, - "place" : { - "type" : "integer", - "format" : "int32" - }, - "stratigraphic_unit" : { - "type" : "integer", - "format" : "int32" - }, - "edition" : { - "type" : "integer", - "format" : "int32" - }, - "group" : { - "type" : "integer", - "format" : "int32" - }, - "source" : { - "type" : "integer", - "format" : "int32" + "SystemClassCountModel": { + "type": "object", + "properties": { + "move": { + "type": "integer", + "format": "int32" + }, + "bibliography": { + "type": "integer", + "format": "int32" + }, + "person": { + "type": "integer", + "format": "int32" + }, + "acquisition": { + "type": "integer", + "format": "int32" + }, + "reference_system": { + "type": "integer", + "format": "int32" + }, + "feature": { + "type": "integer", + "format": "int32" + }, + "file": { + "type": "integer", + "format": "int32" + }, + "activity": { + "type": "integer", + "format": "int32" + }, + "type": { + "type": "integer", + "format": "int32" + }, + "administrative_unit": { + "type": "integer", + "format": "int32" + }, + "artifact": { + "type": "integer", + "format": "int32" + }, + "source_translation": { + "type": "integer", + "format": "int32" + }, + "place": { + "type": "integer", + "format": "int32" + }, + "stratigraphic_unit": { + "type": "integer", + "format": "int32" + }, + "edition": { + "type": "integer", + "format": "int32" + }, + "group": { + "type": "integer", + "format": "int32" + }, + "source": { + "type": "integer", + "format": "int32" } } }, - "SubunitsModel" : { - "type" : "array", - "items" : { - "type" : "object", - "properties" : { - "id" : { - "type" : "integer", - "format" : "int32" + "SubunitsModel": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" }, - "parentId" : { - "type" : "integer", - "format" : "int32" + "parentId": { + "type": "integer", + "format": "int32" }, - "rootId" : { - "type" : "integer", - "format" : "int32" + "rootId": { + "type": "integer", + "format": "int32" }, - "openatlasClassName" : { - "type" : "string" + "openatlasClassName": { + "type": "string" }, - "crmClass" : { - "type" : "string" + "crmClass": { + "type": "string" }, - "created" : { - "type" : "string" + "created": { + "type": "string" }, - "modified" : { - "type" : "string" + "modified": { + "type": "string" }, - "latestModRec" : { - "type" : "string" + "latestModRec": { + "type": "string" }, - "geometry" : { - "type" : "object", - "properties" : { - "type" : { - "type" : "string" + "geometry": { + "type": "object", + "properties": { + "type": { + "type": "string" }, - "coordinates" : { - "type" : "array", - "items" : { - "type" : "number" + "coordinates": { + "type": "array", + "items": { + "type": "number" } }, - "title" : { - "type" : "string" + "title": { + "type": "string" }, - "description" : { - "type" : "string" + "description": { + "type": "string" }, - "shapeType" : { - "type" : "string" + "shapeType": { + "type": "string" } } }, - "children" : { - "type" : "array", - "items" : { - "type" : "integer", - "format" : "int32" + "children": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" } }, - "properties" : { - "type" : "object", - "properties" : { - "name" : { - "type" : "string" + "properties": { + "type": "object", + "properties": { + "name": { + "type": "string" }, - "aliases" : { - "type" : "string", - "format" : "nullable" + "aliases": { + "type": "string", + "format": "nullable" }, - "description" : { - "type" : "string" + "description": { + "type": "string" }, - "standardType" : { - "type" : "object", - "properties" : { - "name" : { - "type" : "string" + "standardType": { + "type": "object", + "properties": { + "name": { + "type": "string" }, - "id" : { - "type" : "integer", - "format" : "int32" + "id": { + "type": "integer", + "format": "int32" }, - "rootId" : { - "type" : "integer", - "format" : "int32" + "rootId": { + "type": "integer", + "format": "int32" }, - "path" : { - "type" : "string" + "path": { + "type": "string" }, - "externalReferences" : { - "type" : "array", - "items" : { - "type" : "object", - "properties" : { - "type" : { - "type" : "string" + "externalReferences": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string" }, - "identifier" : { - "type" : "string" + "identifier": { + "type": "string" }, - "referenceSystem" : { - "type" : "string" + "referenceSystem": { + "type": "string" }, - "resolverURL" : { - "type" : "string" + "resolverURL": { + "type": "string" }, - "referenceURL" : { - "type" : "string" + "referenceURL": { + "type": "string" }, - "id" : { - "type" : "string" + "id": { + "type": "string" } } } } } }, - "timespan" : { - "type" : "object", - "properties" : { - "earliestBegin" : { - "type" : "string" + "timespan": { + "type": "object", + "properties": { + "earliestBegin": { + "type": "string" }, - "latestBegin" : { - "type" : "string" + "latestBegin": { + "type": "string" }, - "earliestEnd" : { - "type" : "string" + "earliestEnd": { + "type": "string" }, - "latestEnd" : { - "type" : "string" + "latestEnd": { + "type": "string" } } }, - "externalReferences" : { - "type" : "array", - "items" : { - "type" : "object", - "properties" : { - "type" : { - "type" : "string" + "externalReferences": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string" }, - "identifier" : { - "type" : "string" + "identifier": { + "type": "string" }, - "referenceSystem" : { - "type" : "string" + "referenceSystem": { + "type": "string" }, - "resolverURL" : { - "type" : "string" + "resolverURL": { + "type": "string" }, - "referenceURL" : { - "type" : "string" + "referenceURL": { + "type": "string" }, - "id" : { - "type" : "string" + "id": { + "type": "string" } } } }, - "references" : { - "type" : "array", - "items" : { - "type" : "object", - "properties" : { - "id" : { - "type" : "integer", - "format" : "int32" + "references": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" }, - "abbreviation" : { - "type" : "string" + "abbreviation": { + "type": "string" }, - "title" : { - "type" : "string" + "title": { + "type": "string" }, - "pages" : { - "type" : "string", - "format" : "nullable" + "pages": { + "type": "string", + "format": "nullable" } } } }, - "files" : { - "type" : "string", - "format" : "nullable" + "files": { + "type": "string", + "format": "nullable" }, - "types" : { - "type" : "array", - "items" : { - "type" : "object", - "properties" : { - "id" : { - "type" : "integer", - "format" : "int32" + "types": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" }, - "rootId" : { - "type" : "integer", - "format" : "int32" + "rootId": { + "type": "integer", + "format": "int32" }, - "name" : { - "type" : "string" + "name": { + "type": "string" }, - "path" : { - "type" : "string" + "path": { + "type": "string" }, - "value" : { - "type" : "string", - "format" : "nullable" + "value": { + "type": "string", + "format": "nullable" }, - "unit" : { - "type" : "string", - "format" : "nullable" + "unit": { + "type": "string", + "format": "nullable" }, - "externalReferences" : { - "type" : "array", - "items" : { - "type" : "object", - "properties" : { - "type" : { - "type" : "string" + "externalReferences": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string" }, - "identifier" : { - "type" : "string" + "identifier": { + "type": "string" }, - "referenceSystem" : { - "type" : "string" + "referenceSystem": { + "type": "string" }, - "resolverURL" : { - "type" : "string" + "resolverURL": { + "type": "string" }, - "referenceURL" : { - "type" : "string" + "referenceURL": { + "type": "string" }, - "id" : { - "type" : "string" + "id": { + "type": "string" } } } @@ -2219,66 +2683,66 @@ } } }, - "GeometricEntitiesModel" : { - "type" : "object", - "properties" : { - "type" : { - "type" : "string" - }, - "features" : { - "type" : "array", - "items" : { - "type" : "object", - "properties" : { - "type" : { - "type" : "string" + "GeometricEntitiesModel": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "features": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string" }, - "geometry" : { - "type" : "object", - "properties" : { - "coordinates" : { - "type" : "array", - "items" : { - "type" : "number" + "geometry": { + "type": "object", + "properties": { + "coordinates": { + "type": "array", + "items": { + "type": "number" } }, - "type" : { - "type" : "string" + "type": { + "type": "string" } } }, - "properties" : { - "type" : "object", - "properties" : { - "id" : { - "type" : "integer", - "format" : "int32" + "properties": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" }, - "name" : { - "type" : "string" + "name": { + "type": "string" }, - "description" : { - "type" : "string" + "description": { + "type": "string" }, - "locationId" : { - "type" : "integer", - "format" : "int32" + "locationId": { + "type": "integer", + "format": "int32" }, - "objectId" : { - "type" : "integer", - "format" : "int32" + "objectId": { + "type": "integer", + "format": "int32" }, - "objectDescription" : { - "type" : "string" + "objectDescription": { + "type": "string" }, - "objectName" : { - "type" : "string" + "objectName": { + "type": "string" }, - "objectType" : { - "type" : "string" + "objectType": { + "type": "string" }, - "shapeType" : { - "type" : "string" + "shapeType": { + "type": "string" } } } @@ -2286,6 +2750,28 @@ } } } + }, + "LicensedFileOverviewModel": { + "type": "object", + "properties": { + "id": { + "type": "object", + "properties": { + "display": { + "type": "string" + }, + "thumbnail": { + "type": "string" + }, + "extension": { + "type": "string" + }, + "license": { + "type": "string" + } + } + } + } } } } From 3f7498b6a51205a66d9c7ab0c93c82c5c779ccfc Mon Sep 17 00:00:00 2001 From: BernhardKoschicek Date: Fri, 29 Sep 2023 14:27:21 +0200 Subject: [PATCH 14/32] added 2078 to changelog --- openatlas/views/changelog.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/openatlas/views/changelog.py b/openatlas/views/changelog.py index 0f224034d..9ba0fa917 100644 --- a/openatlas/views/changelog.py +++ b/openatlas/views/changelog.py @@ -17,7 +17,10 @@ def index_changelog() -> str: versions = { '7.17.0': ['TBA', { 'feature': { - '2026': 'External reference systems for type hierarchies'}}], + '2026': 'External reference systems for type hierarchies'}, + 'fix': { + '2078': 'API: CSV export not working' + }}], '7.16.1': ['2023-09-20', { 'fix': { '2069': 'Broken buttons for preceding event'}}], @@ -56,7 +59,7 @@ def index_changelog() -> str: '1930': 'CIDOC CRM link checker: keep form values after submit', '2023': 'Autocomplete at Wikidata is too short'}}], '7.13.1': ['2023-05-09', { - 'fix': {'2014': "Former network URL isn't working anymore"}}], + 'fix': {'2014': "Former network URL isn't working anymore"}}], '7.13.0': ['2023-05-06', { 'feature': { '1952': 'E11 Modification', @@ -148,7 +151,7 @@ def index_changelog() -> str: '7.8.1': ['2022-12-08', { 'fix': { '1911': 'Problem when adding members to groups'}}], - '7.8.0': ['2022-11-18', { + '7.8.0': ['2022-11-18', { 'feature': { '1400': 'Make specific types required at data entry', '1647': 'Composition of artifacts and human remains', @@ -179,10 +182,10 @@ def index_changelog() -> str: '7.6.2': ['2022-09-29', { 'fix': { '1822': 'Missing types at edit'}}], - '7.6.1': ['2022-08-25', { + '7.6.1': ['2022-08-25', { 'fix': { '1794': 'Bug when editing types connected to artifacts'}}], - '7.6.0': ['2022-08-25', { + '7.6.0': ['2022-08-25', { 'feature': { '1788': 'Forms: filter invalid table options', '1781': 'Import for bibliographies and editions', From 75d644ad14aabe34b81c34798b9d60da9ca157dc Mon Sep 17 00:00:00 2001 From: BernhardKoschicek Date: Fri, 29 Sep 2023 15:13:03 +0200 Subject: [PATCH 15/32] made tests --- tests/test_api.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test_api.py b/tests/test_api.py index 8fded4bd4..bb772a24e 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -757,6 +757,13 @@ def test_api(self) -> None: assert b'(autogenerated)' in rv.data assert 'application/json' in rv.headers.get('Content-Type') + # Image Endpoints + rv = self.app.get(url_for('api_03.licensed_file_overview')) + assert '152' in rv.get_json() + rv = self.app.get(url_for( + 'api_03.licensed_file_overview'), file_id=154) + assert '154' in rv.get_json() + # Test Error Handling for rv in [ self.app.get(url_for('api_03.entity', id_=233423424)), From d57b1bb4e65f6e9e1fb01466d0478a9b561ece0e Mon Sep 17 00:00:00 2001 From: BernhardKoschicek Date: Fri, 29 Sep 2023 16:07:02 +0200 Subject: [PATCH 16/32] fixed test --- openatlas/api/endpoints/type.py | 7 +++++-- tests/test_api.py | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/openatlas/api/endpoints/type.py b/openatlas/api/endpoints/type.py index 5908ad7fd..7a0260a2f 100644 --- a/openatlas/api/endpoints/type.py +++ b/openatlas/api/endpoints/type.py @@ -1,7 +1,7 @@ from collections import defaultdict from typing import Any, Union -from flask import Response, g, url_for +from flask import Response, g, url_for, jsonify from flask_restful import Resource, marshal from openatlas.api.resources.parser import default, entity_ @@ -79,9 +79,12 @@ def get_type_overview() -> dict[str, dict[Entity, str]]: class GetTypeTree(Resource): @staticmethod def get() -> Union[tuple[Resource, int], Response]: + parser = entity_.parse_args() type_tree = {'typeTree': GetTypeTree.get_type_tree()} - if entity_.parse_args()['download']: + if parser['download']: return download(type_tree, type_tree_template(), 'type_tree') + if parser['count'] == 'true': + return jsonify(len(type_tree['typeTree'])) return marshal(type_tree, type_tree_template()), 200 @staticmethod diff --git a/tests/test_api.py b/tests/test_api.py index bb772a24e..0e3c208de 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -761,7 +761,7 @@ def test_api(self) -> None: rv = self.app.get(url_for('api_03.licensed_file_overview')) assert '152' in rv.get_json() rv = self.app.get(url_for( - 'api_03.licensed_file_overview'), file_id=154) + 'api_03.licensed_file_overview', file_id='154')) assert '154' in rv.get_json() # Test Error Handling From 8ca0eb4265ccc40ced0380e9ccdd88a7894a3ac8 Mon Sep 17 00:00:00 2001 From: BernhardKoschicek Date: Fri, 29 Sep 2023 16:16:40 +0200 Subject: [PATCH 17/32] manual --- sphinx/source/technical/api_parameters_03.rst | 14 ++++++++++++ sphinx/source/technical/api_version_03.rst | 22 ++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/sphinx/source/technical/api_parameters_03.rst b/sphinx/source/technical/api_parameters_03.rst index fafee44bd..f0a43fad0 100644 --- a/sphinx/source/technical/api_parameters_03.rst +++ b/sphinx/source/technical/api_parameters_03.rst @@ -92,6 +92,20 @@ API parameters 0.3 - | csv | csvNetwork +.. _file_id-para-0.3: + +.. list-table:: **file_id** + :widths: 10 80 + :stub-columns: 1 + + * - Format + - integer + * - Description + - ID of a file. This parameter can be used multiple times to query more IDs. + * - Values + - e.g. 89 + + .. _first-para-0.3: .. list-table:: **first** diff --git a/sphinx/source/technical/api_version_03.rst b/sphinx/source/technical/api_version_03.rst index a85ae47a8..34c035bc6 100644 --- a/sphinx/source/technical/api_version_03.rst +++ b/sphinx/source/technical/api_version_03.rst @@ -352,7 +352,7 @@ Retrieves a detailed GeoJSON list of all chosen geometries in an OpenAtlas insta https://demo.openatlas.eu/api/0.3/geometric_entities/ Subunits -"""""""""""""""""" +"""""""" .. code:: @@ -369,6 +369,9 @@ Displays all subunits of a place in a special format used by the `THANADOS Date: Fri, 29 Sep 2023 16:18:50 +0200 Subject: [PATCH 18/32] added 2083 --- openatlas/views/changelog.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openatlas/views/changelog.py b/openatlas/views/changelog.py index 9ba0fa917..561d609bf 100644 --- a/openatlas/views/changelog.py +++ b/openatlas/views/changelog.py @@ -17,7 +17,8 @@ def index_changelog() -> str: versions = { '7.17.0': ['TBA', { 'feature': { - '2026': 'External reference systems for type hierarchies'}, + '2026': 'External reference systems for type hierarchies', + '2083': 'API: List of images'}, 'fix': { '2078': 'API: CSV export not working' }}], From fd28bf60e075f125f84c37b56ced97660b337775 Mon Sep 17 00:00:00 2001 From: bkoschicek Date: Tue, 3 Oct 2023 13:47:34 +0200 Subject: [PATCH 19/32] fixed subunits endpoint in swagger --- openatlas/api/swagger.json | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/openatlas/api/swagger.json b/openatlas/api/swagger.json index 6432d174f..6b88f92f4 100644 --- a/openatlas/api/swagger.json +++ b/openatlas/api/swagger.json @@ -874,7 +874,7 @@ } } }, - "/subunits/": { + "/subunits/{entityId}": { "get": { "tags": [ "Special Endpoints" @@ -883,13 +883,10 @@ "operationId": "GetSubunits", "parameters": [ { - "$ref": "#/components/parameters/format" + "$ref": "#/components/parameters/entityId" }, { "$ref": "#/components/parameters/download" - }, - { - "$ref": "#/components/parameters/count" } ], "responses": { From ada73087ecb6d4920fefa239b7f0ee8159d68dab Mon Sep 17 00:00:00 2001 From: bkoschicek Date: Tue, 3 Oct 2023 14:18:38 +0200 Subject: [PATCH 20/32] fixed geometries endpoint 'gisAll' --- openatlas/api/resources/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openatlas/api/resources/util.py b/openatlas/api/resources/util.py index 2ccd98b0d..7c1590ad3 100644 --- a/openatlas/api/resources/util.py +++ b/openatlas/api/resources/util.py @@ -235,7 +235,7 @@ def get_geometries(parser: dict[str, Any]) -> list[dict[str, Any]]: all_geoms = Gis.get_all() out = [] for item in choices \ - if parser['geometry'] == 'gisAll' else parser['geometry']: + if 'gisAll' in parser['geometry'] else parser['geometry']: for geom in json.loads(all_geoms[item]): out.append(geom) return out From 289e40b144c32aa1fed6651fbb45990803f98377 Mon Sep 17 00:00:00 2001 From: Alexander Watzinger Date: Tue, 3 Oct 2023 14:42:17 +0200 Subject: [PATCH 21/32] Minor API fix --- openatlas/api/resources/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openatlas/api/resources/util.py b/openatlas/api/resources/util.py index 7c1590ad3..f11aa114d 100644 --- a/openatlas/api/resources/util.py +++ b/openatlas/api/resources/util.py @@ -166,7 +166,7 @@ def get_reference_systems( links_inverse: list[Link]) -> list[dict[str, Any]]: ref = [] for link_ in links_inverse: - if not isinstance(link_.domain, ReferenceSystem): + if not isinstance(link_.domain, ReferenceSystem) or not link_.type: continue system = g.reference_systems[link_.domain.id] ref.append({ From 83a2b6f59ad0a71e8abfd6fc629d4a7473f7134b Mon Sep 17 00:00:00 2001 From: bkoschicek Date: Tue, 3 Oct 2023 17:05:59 +0200 Subject: [PATCH 22/32] refactored g.file_stats to g.files --- openatlas/__init__.py | 21 ++++++--------------- openatlas/display/display.py | 6 ++---- openatlas/display/image_processing.py | 9 ++++----- openatlas/display/util.py | 12 ++++-------- openatlas/models/entity.py | 13 ++++++++++--- openatlas/views/admin.py | 11 +++++------ openatlas/views/entity_index.py | 8 +++----- 7 files changed, 34 insertions(+), 46 deletions(-) diff --git a/openatlas/__init__.py b/openatlas/__init__.py index 92a75bf56..b5599c352 100644 --- a/openatlas/__init__.py +++ b/openatlas/__init__.py @@ -1,6 +1,5 @@ import locale -from pathlib import Path -from typing import Any, Optional +from typing import Optional from flask import Flask, Response, g, request, session from flask_babel import Babel @@ -50,6 +49,7 @@ def before_request() -> None: if request.path.startswith('/static'): return # Avoid files overhead if not using Apache with static alias + g.logger = Logger() g.db = open_connection(app.config) g.db.autocommit = True @@ -64,8 +64,10 @@ def before_request() -> None: g.view_class_mapping = view_class_mapping g.class_view_mapping = OpenatlasClass.get_class_view_mapping() g.table_headers = OpenatlasClass.get_table_headers() - g.file_stats = get_file_stats() - + g.files = {} + for file_ in app.config['UPLOAD_DIR'].iterdir(): + if file_.stem.isdigit(): + g.files[int(file_.stem)] = file_ # Set max file upload in MB app.config['MAX_CONTENT_LENGTH'] = \ g.settings['file_upload_max_size'] * 1024 * 1024 @@ -91,14 +93,3 @@ def apply_caching(response: Response) -> Response: @app.teardown_request def teardown_request(_exception: Optional[Exception]) -> None: close_connection() - - -def get_file_stats( - path: Path = app.config['UPLOAD_DIR']) -> dict[int, dict[str, Any]]: - stats: dict[int, dict[str, Any]] = {} - for file_ in filter(lambda x: x.stem.isdigit(), path.iterdir()): - stats[int(file_.stem)] = { - 'ext': file_.suffix, - 'size': convert_size(file_.stat().st_size), - 'date': file_.stat().st_ctime} - return stats diff --git a/openatlas/display/display.py b/openatlas/display/display.py index ac2727700..88f6236e8 100644 --- a/openatlas/display/display.py +++ b/openatlas/display/display.py @@ -65,10 +65,8 @@ class FileDisplay(BaseDisplay): def add_data(self) -> None: super().add_data() - self.data[_('size')] = g.file_stats[self.entity.id]['size'] \ - if self.entity.id in g.file_stats else 'N/A' - self.data[_('extension')] = g.file_stats[self.entity.id]['ext'] \ - if self.entity.id in g.file_stats else 'N/A' + self.data[_('size')] = self.entity.get_file_size() + self.data[_('extension')] = self.entity.get_file_extension() def add_button_others(self) -> None: if path := get_file_path(self.entity.id): diff --git a/openatlas/display/image_processing.py b/openatlas/display/image_processing.py index 8cea34e5b..25ee3ab3a 100644 --- a/openatlas/display/image_processing.py +++ b/openatlas/display/image_processing.py @@ -91,14 +91,13 @@ def delete_orphaned_resized_images() -> None: path = Path(app.config['RESIZED_IMAGES']) / size for file in path.glob('**/*'): file_name = file.name.rsplit('.', 1)[0].lower() - if not file_name.isdigit() or int(file_name) not in g.file_stats: + if not file_name.isdigit() or int(file_name) not in g.files: file.unlink() # pragma: no cover def create_resized_images() -> None: from openatlas.models.entity import Entity for entity in Entity.get_by_class('file'): - if entity.id in g.file_stats \ - and g.file_stats[entity.id]['ext'] \ - in app.config['ALLOWED_IMAGE_EXT']: - resize_image(f"{entity.id}{g.file_stats[entity.id]['ext']}") + if entity.id in g.files: + if entity.get_file_extension() in app.config['ALLOWED_IMAGE_EXT']: + resize_image(f"{entity.id}{entity.get_file_extension()}") diff --git a/openatlas/display/util.py b/openatlas/display/util.py index a89a01596..7419897d1 100644 --- a/openatlas/display/util.py +++ b/openatlas/display/util.py @@ -338,12 +338,8 @@ def get_base_table_data(entity: Entity, show_links: bool = True) -> list[Any]: if entity.class_.standard_type_id: data.append(entity.standard_type.name if entity.standard_type else '') if entity.class_.name == 'file': - data.append( - g.file_stats[entity.id]['size'] - if entity.id in g.file_stats else 'N/A') - data.append( - g.file_stats[entity.id]['ext'] - if entity.id in g.file_stats else 'N/A') + data.append(entity.get_file_size()) + data.append(entity.get_file_extension()) if entity.class_.view in ['actor', 'artifact', 'event', 'place']: data.append(entity.first) data.append(entity.last) @@ -466,9 +462,9 @@ def get_file_path( entity: Union[int, Entity], size: Optional[str] = None) -> Optional[Path]: id_ = entity if isinstance(entity, int) else entity.id - if id_ not in g.file_stats: + if id_ not in g.files: return None - ext = g.file_stats[id_]['ext'] + ext = g.files[id_].suffix if size: if ext in app.config['NONE_DISPLAY_EXT']: ext = app.config['PROCESSED_EXT'] # pragma: no cover diff --git a/openatlas/models/entity.py b/openatlas/models/entity.py index ea61cfd4b..286358b9b 100644 --- a/openatlas/models/entity.py +++ b/openatlas/models/entity.py @@ -12,7 +12,7 @@ from openatlas.database.entity import Entity as Db from openatlas.display.util import ( datetime64_to_timestamp, format_date_part, sanitize, - timestamp_to_datetime64) + timestamp_to_datetime64, convert_size) from openatlas.models.link import Link if TYPE_CHECKING: # pragma: no cover @@ -331,6 +331,13 @@ def get_structure_for_insert(self) -> dict[str, list[Entity]]: self.get_linked_entities_recursive('P46', inverse=True) + [self]} + def get_file_size(self) -> str: + return convert_size(g.files[self.id].stat().st_size) \ + if self.id in g.files else 'N/A' + + def get_file_extension(self) -> str: + return g.files[self.id].suffix if self.id in g.files else 'N/A' + @staticmethod def get_invalid_dates() -> list[Entity]: return [ @@ -372,8 +379,8 @@ def get_by_view( def get_display_files() -> list[Entity]: entities = [] for row in Db.get_by_class('file', types=True): - ext = g.file_stats[row['id']]['ext'] \ - if row['id'] in g.file_stats else 'N/A' + ext = g.files[row['id']].suffix \ + if row['id'] in g.files else 'N/A' if ext in app.config['DISPLAY_FILE_EXTENSIONS']: entities.append(Entity(row)) return entities diff --git a/openatlas/views/admin.py b/openatlas/views/admin.py index 39a4be31f..15d6b785b 100644 --- a/openatlas/views/admin.py +++ b/openatlas/views/admin.py @@ -519,6 +519,7 @@ def admin_orphans() -> str: for file in app.config['UPLOAD_DIR'].iterdir(): if file.name != '.gitignore' \ and os.path.isfile(file) \ + and file.stem.isdigit() \ and int(file.stem) not in entity_file_ids: confirm = _('Delete %(name)s?', name=file.name.replace("'", '')) tabs['orphaned_files'].table.rows.append([ @@ -606,18 +607,16 @@ def admin_logo(id_: Optional[int] = None) -> Union[str, Response]: table = Table([''] + g.table_headers['file'] + ['date']) for entity in Entity.get_display_files(): date = 'N/A' - if entity.id in g.file_stats: + if entity.id in g.files: date = format_date( datetime.datetime.utcfromtimestamp( - g.file_stats[entity.id]['date'])) + g.files[entity.id].stat().st_ctime)) table.rows.append([ link(_('set'), url_for('admin_logo', id_=entity.id)), entity.name, link(entity.standard_type), - g.file_stats[entity.id]['size'] - if entity.id in g.file_stats else 'N/A', - g.file_stats[entity.id]['ext'] - if entity.id in g.file_stats else 'N/A', + entity.get_file_size(), + entity.get_file_extension(), entity.description, date]) return render_template( diff --git a/openatlas/views/entity_index.py b/openatlas/views/entity_index.py index 842df7c9d..f61bca8f2 100644 --- a/openatlas/views/entity_index.py +++ b/openatlas/views/entity_index.py @@ -10,7 +10,7 @@ from openatlas.display.table import Table from openatlas.display.util import ( button, format_date, get_base_table_data, get_file_path, is_authorized, - link, manual, required_group) + link, manual, required_group, convert_size) from openatlas.models.entity import Entity from openatlas.models.gis import Gis @@ -50,10 +50,8 @@ def get_table(view: str) -> Table: format_date(entity.created), link(entity), link(entity.standard_type), - g.file_stats[entity.id]['size'] - if entity.id in g.file_stats else 'N/A', - g.file_stats[entity.id]['ext'] - if entity.id in g.file_stats else 'N/A', + entity.get_file_size(), + entity.get_file_extension(), entity.description] if g.settings['image_processing'] \ and current_user.settings['table_show_icons']: From 7025cbce88b46549f40cba0c189688b8f5e61ba8 Mon Sep 17 00:00:00 2001 From: Alexander Watzinger Date: Tue, 3 Oct 2023 17:36:03 +0200 Subject: [PATCH 23/32] Clean up with Bernhard --- openatlas/api/resources/util.py | 20 +++---- openatlas/views/entity_index.py | 2 +- tests/test_api.py | 99 +++++++++++++++++++-------------- 3 files changed, 67 insertions(+), 54 deletions(-) diff --git a/openatlas/api/resources/util.py b/openatlas/api/resources/util.py index f11aa114d..0bd0f7d2c 100644 --- a/openatlas/api/resources/util.py +++ b/openatlas/api/resources/util.py @@ -166,16 +166,16 @@ def get_reference_systems( links_inverse: list[Link]) -> list[dict[str, Any]]: ref = [] for link_ in links_inverse: - if not isinstance(link_.domain, ReferenceSystem) or not link_.type: - continue - system = g.reference_systems[link_.domain.id] - ref.append({ - 'referenceURL': system.website_url, - 'id': link_.description, - 'resolverURL': system.resolver_url, - 'identifier': f"{system.resolver_url or ''}{link_.description}", - 'type': to_camel_case(g.types[link_.type.id].name), - 'referenceSystem': system.name}) + if isinstance(link_.domain, ReferenceSystem) and link_.type: + system = g.reference_systems[link_.domain.id] + ref.append({ + 'referenceURL': system.website_url, + 'id': link_.description, + 'resolverURL': system.resolver_url, + 'identifier': + f"{system.resolver_url or ''}{link_.description}", + 'type': to_camel_case(g.types[link_.type.id].name), + 'referenceSystem': system.name}) return ref diff --git a/openatlas/views/entity_index.py b/openatlas/views/entity_index.py index f61bca8f2..6ca2cf84f 100644 --- a/openatlas/views/entity_index.py +++ b/openatlas/views/entity_index.py @@ -10,7 +10,7 @@ from openatlas.display.table import Table from openatlas.display.util import ( button, format_date, get_base_table_data, get_file_path, is_authorized, - link, manual, required_group, convert_size) + link, manual, required_group) from openatlas.models.entity import Entity from openatlas.models.gis import Gis diff --git a/tests/test_api.py b/tests/test_api.py index 0e3c208de..6464f7857 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -419,6 +419,8 @@ def test_api(self) -> None: self.app.get( url_for('api_03.type_tree', download=True))]: assert bool(rv.get_json()['typeTree']) + rv = self.app.get(url_for('api_03.type_tree', count=True)) + assert rv.get_json() > 0 for rv in [ self.app.get(url_for( @@ -775,52 +777,62 @@ def test_api(self) -> None: rv = self.app.get(url_for('api_03.subunits', id_=actor.id)) assert 'ID is not a valid place' in rv.get_json()['title'] - rv = self.app.get(url_for( - 'api_03.query', - entities=location.id, - cidoc_classes='E18', - view_classes='artifact', - system_classes='person', - sort='desc', - column='id', - download=True, - last=place.id)) - assert 'ID is last entity' in rv.get_json()['title'] - - for rv in [ - self.app.get(url_for('api_03.query', entities=12345)), - self.app.get(url_for( - 'api_03.cidoc_class', cidoc_class='E68', last=1231)), - self.app.get(url_for( - 'api_03.view_class', - view_class='place', - search='{"typeName":[{"operator":"equal",' - '"values":["Boundary Mark", "Height", "Dimension"],' - '"logicalOperator":"and"}]}')), - self.app.get(url_for( - 'api_03.view_class', - view_class='place', - search='{"beginFrom":[{"operator":"lesserThan",' - '"values":["2000-1-1"],' - '"logicalOperator":"or"}]}')), - - self.app.get(url_for( + rv = self.app.get( + url_for( 'api_03.query', - entities=place.id, + entities=location.id, cidoc_classes='E18', view_classes='artifact', system_classes='person', - format='lp', - search='{"entityDescription":[{"operator":"like",' - '"values":["IS", "sam", "FrOdo"],' - '"logicalOperator":"and"}]}'))]: + sort='desc', + column='id', + download=True, + last=place.id)) + assert 'ID is last entity' in rv.get_json()['title'] + + for rv in [ + self.app.get(url_for('api_03.query', entities=12345)), + self.app.get( + url_for( + 'api_03.cidoc_class', + cidoc_class='E68', + last=1231)), + self.app.get( + url_for( + 'api_03.view_class', + view_class='place', + search= + '{"typeName":[{"operator":"equal",' + '"values":["Boundary Mark", "Height", "Dimension"],' + '"logicalOperator":"and"}]}')), + self.app.get( + url_for( + 'api_03.view_class', + view_class='place', + search= + '{"beginFrom":[{"operator":"lesserThan",' + '"values":["2000-1-1"],' + '"logicalOperator":"or"}]}')), + self.app.get( + url_for( + 'api_03.query', + entities=place.id, + cidoc_classes='E18', + view_classes='artifact', + system_classes='person', + format='lp', + search= + '{"entityDescription":[{"operator":"like",' + '"values":["IS", "sam", "FrOdo"],' + '"logicalOperator":"and"}]}'))]: rv = rv.get_json() assert 'No entity available' in rv['title'] - rv = self.app.get(url_for( - 'api_03.query', - system_classes='person', - type_id=boundary_mark.id)) + rv = self.app.get( + url_for( + 'api_03.query', + system_classes='person', + type_id=boundary_mark.id)) assert 'One entity ID is not a type' in rv.get_json()['title'] rv = self.app.get( @@ -873,10 +885,11 @@ def test_api(self) -> None: '"logicalOperator":"or"}]}')) assert 'Invalid search syntax' in rv.get_json()['title'] - for rv in [ - self.app.get(url_for('api_03.type_entities', id_=1234)), - self.app.get(url_for('api_03.type_entities_all', id_=1234))]: - assert 'Entity is not a type' in rv.get_json()['title'] + rv = self.app.get(url_for('api_03.type_entities', id_=1234)) + assert 'Entity is not a type' in rv.get_json()['title'] + + rv = self.app.get(url_for('api_03.type_entities_all', id_=1234)) + assert 'Entity is not a type' in rv.get_json()['title'] rv = self.app.get(url_for( 'api_03.view_class', From d5fa28419ab489875bfc1d1f8059c8de10d6b224 Mon Sep 17 00:00:00 2001 From: BernhardKoschicek Date: Wed, 4 Oct 2023 09:40:51 +0200 Subject: [PATCH 24/32] refactor DIR to PATH --- config/default.py | 16 ++++++++-------- install/upgrade/database_upgrade.py | 4 ++-- instance/example_testing.py | 2 +- openatlas/__init__.py | 2 +- openatlas/api/import_scripts/arche.py | 2 +- openatlas/display/image_processing.py | 2 +- openatlas/display/util.py | 6 +++--- openatlas/models/export.py | 2 +- openatlas/views/admin.py | 10 +++++----- openatlas/views/entity.py | 6 +++--- openatlas/views/export.py | 10 +++++----- openatlas/views/file.py | 6 +++--- openatlas/views/imports.py | 2 +- tests/test_admin.py | 2 +- tests/test_image.py | 6 +++--- 15 files changed, 39 insertions(+), 39 deletions(-) diff --git a/config/default.py b/config/default.py index 1903906c1..1a51d24f8 100644 --- a/config/default.py +++ b/config/default.py @@ -31,13 +31,13 @@ # To override them (in instance/production.py) either use them like here # or use absolute paths like e.g. pathlib.Path('/some/location/somewhere') FILES_PATH = Path(__file__).parent.parent / 'files' -EXPORT_DIR = Path(FILES_PATH) / 'export' -UPLOAD_DIR = Path(FILES_PATH) / 'uploads' -TMP_DIR = Path('/tmp') # used e.g. for processing imports and export files +EXPORT_PATH = Path(FILES_PATH) / 'export' +UPLOAD_PATH = Path(FILES_PATH) / 'uploads' +TMP_PATH = Path('/tmp') # used e.g. for processing imports and export files # Image processing -PROCESSED_IMAGE_DIR = Path(FILES_PATH) / 'processed_images' -RESIZED_IMAGES = Path(PROCESSED_IMAGE_DIR) / 'resized' +PROCESSED_IMAGE_PATH = Path(FILES_PATH) / 'processed_images' +RESIZED_IMAGES = Path(PROCESSED_IMAGE_PATH) / 'resized' IMAGE_SIZE = { 'thumbnail': '200', 'table': '100'} @@ -46,9 +46,9 @@ PROCESSED_EXT = '.jpeg' # For system checks -WRITABLE_DIRS = [ - UPLOAD_DIR, - EXPORT_DIR, +WRITABLE_PATHS = [ + UPLOAD_PATH, + EXPORT_PATH, RESIZED_IMAGES] # Security diff --git a/install/upgrade/database_upgrade.py b/install/upgrade/database_upgrade.py index b69968dac..6d6b2c37b 100644 --- a/install/upgrade/database_upgrade.py +++ b/install/upgrade/database_upgrade.py @@ -25,7 +25,7 @@ from config.database_versions import DATABASE_VERSIONS from config.default import ( DATABASE_PASS, VERSION, DATABASE_VERSION, DATABASE_NAME, DATABASE_USER, - DATABASE_HOST, DATABASE_PORT, EXPORT_DIR) + DATABASE_HOST, DATABASE_PORT, EXPORT_PATH) from instance import production from openatlas.database.connect import open_connection from openatlas.database.settings import Settings @@ -107,7 +107,7 @@ def check_database_version_supported() -> None: def backup_database() -> None: - path = EXPORT_DIR + path = EXPORT_PATH if not os.access(path, os.W_OK): finish( f'Directory for database backup not writeable ({path}). Aborting!') diff --git a/instance/example_testing.py b/instance/example_testing.py index 532fd063c..06b848fa3 100644 --- a/instance/example_testing.py +++ b/instance/example_testing.py @@ -15,4 +15,4 @@ # For Windows user # from pathlib import Path -# TMP_DIR = Path('C:\\Path\\to\\tmp') +# TMP_PATH = Path('C:\\Path\\to\\tmp') diff --git a/openatlas/__init__.py b/openatlas/__init__.py index b5599c352..7499955aa 100644 --- a/openatlas/__init__.py +++ b/openatlas/__init__.py @@ -65,7 +65,7 @@ def before_request() -> None: g.class_view_mapping = OpenatlasClass.get_class_view_mapping() g.table_headers = OpenatlasClass.get_table_headers() g.files = {} - for file_ in app.config['UPLOAD_DIR'].iterdir(): + for file_ in app.config['UPLOAD_PATH'].iterdir(): if file_.stem.isdigit(): g.files[int(file_.stem)] = file_ # Set max file upload in MB diff --git a/openatlas/api/import_scripts/arche.py b/openatlas/api/import_scripts/arche.py index b57d0febc..3149bb763 100644 --- a/openatlas/api/import_scripts/arche.py +++ b/openatlas/api/import_scripts/arche.py @@ -133,7 +133,7 @@ def import_arche_data() -> int: 'https://arche-thumbnails.acdh.oeaw.ac.at/', params={'id': ortho_photo, 'width': 1200}, # type: ignore timeout=60).content - open(str(app.config['UPLOAD_DIR'] / filename), "wb").write(thumb_req) + open(str(app.config['UPLOAD_PATH'] / filename), "wb").write(thumb_req) file.link('P67', artifact) creator = get_or_create_person( diff --git a/openatlas/display/image_processing.py b/openatlas/display/image_processing.py index 25ee3ab3a..6021960b5 100644 --- a/openatlas/display/image_processing.py +++ b/openatlas/display/image_processing.py @@ -33,7 +33,7 @@ def safe_resize_image(name: str, file_format: str, size: str) -> bool: def image_resizing(name: str, format_: str, size: str) -> bool: conf = app.config - filename = Path(conf['UPLOAD_DIR']) / f"{name}{format_}[0]" + filename = Path(conf['UPLOAD_PATH']) / f"{name}{format_}[0]" with Image(filename=filename) as src: ext = conf['PROCESSED_EXT'] \ if format_ in conf['NONE_DISPLAY_EXT'] else format_ diff --git a/openatlas/display/util.py b/openatlas/display/util.py index 7419897d1..97ce708d7 100644 --- a/openatlas/display/util.py +++ b/openatlas/display/util.py @@ -309,7 +309,7 @@ def format_name_and_aliases(entity: Entity, show_links: bool) -> str: def get_backup_file_data() -> dict[str, Any]: - path = app.config['EXPORT_DIR'] + path = app.config['EXPORT_PATH'] latest_file = None latest_file_date = None for file in [ @@ -426,7 +426,7 @@ def system_warnings(_context: str, _unneeded_string: str) -> str: warnings.append( f"Database version {app.config['DATABASE_VERSION']} is needed but " f"current version is {g.settings['database_version']}") - for path in app.config['WRITABLE_DIRS']: + for path in app.config['WRITABLE_PATHS']: if not os.access(path, os.W_OK): warnings.append( '

' + _('directory not writable') + @@ -470,7 +470,7 @@ def get_file_path( ext = app.config['PROCESSED_EXT'] # pragma: no cover path = app.config['RESIZED_IMAGES'] / size / f"{id_}{ext}" return path if os.path.exists(path) else None - return app.config['UPLOAD_DIR'] / f"{id_}{ext}" + return app.config['UPLOAD_PATH'] / f"{id_}{ext}" def format_date(value: Union[datetime, numpy.datetime64]) -> str: diff --git a/openatlas/models/export.py b/openatlas/models/export.py index 366e52418..e95736733 100644 --- a/openatlas/models/export.py +++ b/openatlas/models/export.py @@ -15,7 +15,7 @@ def current_date_for_filename() -> str: def sql_export(format_: str, postfix: Optional[str] = '') -> bool: - file = app.config['EXPORT_DIR'] \ + file = app.config['EXPORT_PATH'] \ / f'{current_date_for_filename()}_export{postfix}.{format_}' pg_dump = "pg_dump" if os.name == 'posix' \ else f'"{shutil.which("pg_dump.exe")}"' diff --git a/openatlas/views/admin.py b/openatlas/views/admin.py index 15d6b785b..dc6d9ac75 100644 --- a/openatlas/views/admin.py +++ b/openatlas/views/admin.py @@ -516,7 +516,7 @@ def admin_orphans() -> str: entity.description]) # Orphaned files with no corresponding entity - for file in app.config['UPLOAD_DIR'].iterdir(): + for file in app.config['UPLOAD_PATH'].iterdir(): if file.name != '.gitignore' \ and os.path.isfile(file) \ and file.stem.isdigit() \ @@ -573,7 +573,7 @@ def admin_orphans() -> str: def admin_file_delete(filename: str) -> Response: if filename != 'all': # Delete one file try: - (app.config['UPLOAD_DIR'] / filename).unlink() + (app.config['UPLOAD_PATH'] / filename).unlink() flash(f"{filename} {_('was deleted')}", 'info') except Exception as e: g.logger.log('error', 'file', f'deletion of {filename} failed', e) @@ -583,10 +583,10 @@ def admin_file_delete(filename: str) -> Response: # Delete all files with no corresponding entity if is_authorized('admin'): # pragma: no cover - don't test, ever entity_file_ids = [entity.id for entity in Entity.get_by_class('file')] - for f in app.config['UPLOAD_DIR'].iterdir(): + for f in app.config['UPLOAD_PATH'].iterdir(): if f.name != '.gitignore' and int(f.stem) not in entity_file_ids: try: - (app.config['UPLOAD_DIR'] / f.name).unlink() + (app.config['UPLOAD_PATH'] / f.name).unlink() except Exception as e: g.logger.log( 'error', 'file', f'deletion of {f.name} failed', e) @@ -764,7 +764,7 @@ def get_disk_space_info() -> Optional[dict[str, Any]]: files_size = int(process.stdout.split()[0]) else: files_size = 40999999999 # pragma: no cover - stats = shutil.disk_usage(app.config['UPLOAD_DIR']) + stats = shutil.disk_usage(app.config['UPLOAD_PATH']) percent_free = 100 - math.ceil(stats.free / (stats.total / 100)) percent_files = math.ceil(files_size / (stats.total / 100)) other_files = stats.total - stats.free - files_size diff --git a/openatlas/views/entity.py b/openatlas/views/entity.py index 26501f16a..518346168 100644 --- a/openatlas/views/entity.py +++ b/openatlas/views/entity.py @@ -88,7 +88,7 @@ def insert( class_name=class_, view_name=g.classes[class_].view, gis_data=manager.place_info['gis_data'], - writable=os.access(app.config['UPLOAD_DIR'], os.W_OK), + writable=os.access(app.config['UPLOAD_PATH'], os.W_OK), overlays=manager.place_info['overlays'], title=_(g.classes[class_].view), crumbs=manager.get_crumbs()) @@ -209,7 +209,7 @@ def insert_files(manager: BaseManager) -> Union[str, Response]: filename = secure_filename(f'a{file.filename}') name = f"{manager.entity.id}.{filename.rsplit('.', 1)[1].lower()}" ext = secure_filename(file.filename).rsplit('.', 1)[1].lower() - path = app.config['UPLOAD_DIR'] / name + path = app.config['UPLOAD_PATH'] / name file.save(str(path)) if f'.{ext}' in app.config['DISPLAY_FILE_EXTENSIONS']: call(f'exiftran -ai {path}', shell=True) # Fix rotation @@ -228,7 +228,7 @@ def insert_files(manager: BaseManager) -> Union[str, Response]: except Exception as e: # pragma: no cover Transaction.rollback() for filename in filenames: - (app.config['UPLOAD_DIR'] / filename).unlink() + (app.config['UPLOAD_PATH'] / filename).unlink() g.logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') url = url_for('index', view=g.classes['file'].view) diff --git a/openatlas/views/export.py b/openatlas/views/export.py index e0bde2cc4..e51f40216 100644 --- a/openatlas/views/export.py +++ b/openatlas/views/export.py @@ -17,7 +17,7 @@ @required_group('manager') def download_sql(filename: str) -> Response: return send_from_directory( - app.config['EXPORT_DIR'], + app.config['EXPORT_PATH'], filename, as_attachment=True) @@ -25,7 +25,7 @@ def download_sql(filename: str) -> Response: @app.route('/export/execute/') @required_group('manager') def export_execute(format_: str) -> Response: - if os.access(app.config['EXPORT_DIR'], os.W_OK): + if os.access(app.config['EXPORT_PATH'], os.W_OK): if sql_export(format_): g.logger.log('info', 'database', 'SQL export') flash(_('data was exported'), 'info') @@ -38,7 +38,7 @@ def export_execute(format_: str) -> Response: @app.route('/export/sql') @required_group('manager') def export_sql() -> str: - path = app.config['EXPORT_DIR'] + path = app.config['EXPORT_PATH'] table = Table(['name', 'size'], order=[[0, 'desc']]) for file in [f for f in path.iterdir() if (path / f).is_file() and f.name != '.gitignore']: @@ -49,7 +49,7 @@ def export_sql() -> str: _('download'), url_for('download_sql', filename=file.name))] if is_authorized('admin') \ - and os.access(app.config['EXPORT_DIR'], os.W_OK): + and os.access(app.config['EXPORT_PATH'], os.W_OK): confirm = _('Delete %(name)s?', name=file.name.replace("'", '')) data.append( link( @@ -80,7 +80,7 @@ def export_sql() -> str: @required_group('admin') def delete_export(filename: str) -> Response: try: - (app.config['EXPORT_DIR'] / filename).unlink() + (app.config['EXPORT_PATH'] / filename).unlink() g.logger.log('info', 'file', 'SQL file deleted') flash(_('file deleted'), 'info') except Exception as e: diff --git a/openatlas/views/file.py b/openatlas/views/file.py index 268004cf9..eae768718 100644 --- a/openatlas/views/file.py +++ b/openatlas/views/file.py @@ -15,7 +15,7 @@ @required_group('readonly') def download_file(filename: str) -> Any: return send_from_directory( - app.config['UPLOAD_DIR'], + app.config['UPLOAD_PATH'], filename, as_attachment=True) @@ -27,12 +27,12 @@ def display_file(filename: str) -> Any: return send_from_directory( app.config['RESIZED_IMAGES'] / request.args.get('size'), filename) - return send_from_directory(app.config['UPLOAD_DIR'], filename) + return send_from_directory(app.config['UPLOAD_PATH'], filename) @app.route('/display_logo/') def display_logo(filename: str) -> Any: - return send_from_directory(app.config['UPLOAD_DIR'], filename) + return send_from_directory(app.config['UPLOAD_PATH'], filename) @app.route('/file/set_profile_image//') diff --git a/openatlas/views/imports.py b/openatlas/views/imports.py index 76b7afb9d..133edccbc 100644 --- a/openatlas/views/imports.py +++ b/openatlas/views/imports.py @@ -171,7 +171,7 @@ def import_data(project_id: int, class_: str) -> str: class_label = g.classes[class_].label if form.validate_on_submit(): file_ = request.files['file'] - file_path = app.config['TMP_DIR'] / secure_filename(file_.filename) + file_path = app.config['TMP_PATH'] / secure_filename(file_.filename) columns: dict[str, list[str]] = { 'allowed': ['name', 'id', 'description'], 'valid': [], diff --git a/tests/test_admin.py b/tests/test_admin.py index a6b177afa..1594ccd76 100644 --- a/tests/test_admin.py +++ b/tests/test_admin.py @@ -44,7 +44,7 @@ def test_admin(self) -> None: assert b'Invalid linked entity' in rv.data file_ = 'Test77.txt' - with open(Path(app.config['UPLOAD_DIR'] / file_), 'w') as _file: + with open(Path(app.config['UPLOAD_PATH'] / file_), 'w') as _file: pass rv = self.app.get( diff --git a/tests/test_image.py b/tests/test_image.py index 06e74457c..60f3a72f1 100644 --- a/tests/test_image.py +++ b/tests/test_image.py @@ -52,17 +52,17 @@ def test_image(self) -> None: copyfile( Path(app.root_path) / 'static' / 'images' / 'layout' / 'logo.png', - Path(app.config['UPLOAD_DIR'] / file_name)) + Path(app.config['UPLOAD_PATH'] / file_name)) file2 = insert('file', 'Test_File2') file2.link('P2', g.types[get_hierarchy('License').subs[0]]) copyfile( Path(app.root_path) / 'static' / 'images' / 'layout' / 'logo.png', - Path(app.config['UPLOAD_DIR'] / f'{file2.id}.jpeg')) + Path(app.config['UPLOAD_PATH'] / f'{file2.id}.jpeg')) file_json = insert('file', 'Test') copyfile( Path(app.root_path) / 'static' / 'manifest.json', - Path(app.config['UPLOAD_DIR'] / f'{file_json.id}.json')) + Path(app.config['UPLOAD_PATH'] / f'{file_json.id}.json')) safe_resize_image(file2.id, '.png', size="???") profile_image(file_pathless) From 0e257bf3d8a923ee66a5f05ef19116f023ad6972 Mon Sep 17 00:00:00 2001 From: BernhardKoschicek Date: Wed, 4 Oct 2023 09:45:54 +0200 Subject: [PATCH 25/32] refactor DIR to PATH --- tests/test_index.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_index.py b/tests/test_index.py index 21ab0dccb..863fdc007 100644 --- a/tests/test_index.py +++ b/tests/test_index.py @@ -27,7 +27,7 @@ def test_index(self) -> None: self.app.get(url_for('set_locale', language='en')) - app.config['WRITABLE_DIRS'].append(Path(app.root_path) / 'error') + app.config['WRITABLE_PATHS'].append(Path(app.root_path) / 'error') app.config['DATABASE_VERSION'] = 'error' rv = self.app.get(url_for('view', id_=666), follow_redirects=True) assert b'teapot' in rv.data From 2dd27e15a78a7cae7d2ffa45b49c2bb47246391a Mon Sep 17 00:00:00 2001 From: Alexander Watzinger Date: Wed, 4 Oct 2023 11:14:50 +0200 Subject: [PATCH 26/32] Moved log levles and property types out of __init__.py --- config/default.py | 31 +++++++------------------------ openatlas/models/logger.py | 10 ++++++++++ openatlas/models/type.py | 8 ++++++++ 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/config/default.py b/config/default.py index 1a51d24f8..901bfe5d7 100644 --- a/config/default.py +++ b/config/default.py @@ -6,13 +6,6 @@ VERSION = '7.17.0' DATABASE_VERSION = DATABASE_VERSIONS[0] DEMO_MODE = False # If activated some options are disabled, login is prefilled - -LANGUAGES = { - 'ca': 'Català', - 'de': 'Deutsch', - 'en': 'English', - 'es': 'Español', - 'fr': 'Français'} DEBUG = False DATABASE_NAME = 'openatlas' @@ -23,6 +16,13 @@ MAIL_PASSWORD = 'CHANGE ME' SECRET_KEY = 'CHANGE ME' # Used for cookies +LANGUAGES = { + 'ca': 'Català', + 'de': 'Deutsch', + 'en': 'English', + 'es': 'Español', + 'fr': 'Français'} + # Files with these extensions are can be displayed in the browser DISPLAY_FILE_EXTENSIONS = \ ['.bmp', '.gif', '.ico', '.jpeg', '.jpg', '.png', '.svg'] @@ -105,25 +105,8 @@ # Minimum required characters for table filters MIN_CHARS_JSTREE_SEARCH = 1 -LOG_LEVELS = { - 0: 'emergency', - 1: 'alert', - 2: 'critical', - 3: 'error', - 4: 'warn', - 5: 'notice', - 6: 'info', - 7: 'debug'} - CSS = { 'string_field': 'form-control form-control-sm', 'button': { 'primary': 'btn btn-outline-primary btn-sm', 'secondary': 'btn btn-outline-secondary btn-sm'}} - -# Property types work differently, e.g. no move functionality -PROPERTY_TYPES = [ - 'Actor relation', - 'Actor function', - 'External reference match', - 'Involvement'] diff --git a/openatlas/models/logger.py b/openatlas/models/logger.py index 854f597fa..6f00d12b5 100644 --- a/openatlas/models/logger.py +++ b/openatlas/models/logger.py @@ -8,6 +8,16 @@ from openatlas.models.imports import Import from openatlas.models.user import User +app.config['LOG_LEVELS'] = { + 0: 'emergency', + 1: 'alert', + 2: 'critical', + 3: 'error', + 4: 'warn', + 5: 'notice', + 6: 'info', + 7: 'debug'} + class Logger: diff --git a/openatlas/models/type.py b/openatlas/models/type.py index 9d5357bd1..c84192742 100644 --- a/openatlas/models/type.py +++ b/openatlas/models/type.py @@ -10,6 +10,14 @@ from openatlas.models.entity import Entity +# Property types work differently, e.g. no move functionality +app.config['PROPERTY_TYPES'] = [ + 'Actor relation', + 'Actor function', + 'External reference match', + 'Involvement'] + + class Type(Entity): count = 0 count_subs = 0 From 3a9038b1ad24b823431ae498e6ac8b57b937bd27 Mon Sep 17 00:00:00 2001 From: BernhardKoschicek Date: Wed, 4 Oct 2023 12:17:24 +0200 Subject: [PATCH 27/32] moved API config to separate config --- config/api_config.py | 43 ++++++++++++++++++++++++++ config/default.py | 43 -------------------------- openatlas/__init__.py | 1 + openatlas/api/formats/linked_places.py | 2 +- openatlas/api/formats/loud.py | 3 +- 5 files changed, 47 insertions(+), 45 deletions(-) create mode 100644 config/api_config.py diff --git a/config/api_config.py b/config/api_config.py new file mode 100644 index 000000000..cb8fe3c73 --- /dev/null +++ b/config/api_config.py @@ -0,0 +1,43 @@ +API_CONTEXT = { + 'LPF': 'https://raw.githubusercontent.com/LinkedPasts/linked-places/' + 'master/linkedplaces-context-v1.1.jsonld', + 'LOUD': 'https://linked.art/ns/v1/linked-art.json'} + +CORS_ALLOWANCE = '*' # Cross-Origin source (CORS) +ALLOWED_IPS = ['127.0.0.1'] +API_PROXY = '' + +RDF_FORMATS = { + 'pretty-xml': 'application/rdf+xml', + 'n3': 'text/rdf+n3', + 'turtle': 'application/x-turtle', + 'nt': 'text/plain', + 'xml': 'application/xml'} +JSON_FORMATS = { + 'lp': 'application/ld+json', + 'loud': 'application/ld+json', + 'geojson': 'application/json', + 'geojson-v2': 'application/json'} +API_FORMATS = RDF_FORMATS | JSON_FORMATS + +LOGICAL_OPERATOR: list[str] = ['and', 'or'] +STR_CATEGORIES: list[str] = [ + "entityName", "entityDescription", "entityAliases", "entityCidocClass", + "entitySystemClass", "typeName", "typeNameWithSubs", + "beginFrom", "beginTo", "endFrom", "endTo"] +INT_CATEGORIES: list[str] = [ + "entityID", "typeID", "typeIDWithSubs", "relationToID"] +SET_CATEGORIES: list[str] = ["valueTypeID"] +VALID_CATEGORIES: list[str] = [ + *STR_CATEGORIES, + *INT_CATEGORIES, + *SET_CATEGORIES] +COMPARE_OPERATORS: list[str] = [ + 'equal', 'notEqual', 'greaterThan', 'lesserThan', 'greaterThanEqual', + 'lesserThanEqual', 'like'] + +# Used to connect to ACDH-CH ARCHE systems +ARCHE = {'id': None, 'url': None} + +# Used to connect to password protected Vocabs systems +VOCABS_PASS = '' diff --git a/config/default.py b/config/default.py index 901bfe5d7..aab3fed06 100644 --- a/config/default.py +++ b/config/default.py @@ -56,49 +56,6 @@ REMEMBER_COOKIE_SECURE = True SESSION_COOKIE_SAMESITE = 'Lax' -# API -API_SCHEMA = \ - 'https://raw.githubusercontent.com/LinkedPasts/linked-places' \ - '/master/linkedplaces-context-v1.1.jsonld' -CORS_ALLOWANCE = '*' # Cross-Origin source (CORS) -ALLOWED_IPS = ['127.0.0.1'] -RDF_FORMATS = { - 'pretty-xml': 'application/rdf+xml', - 'n3': 'text/rdf+n3', - 'turtle': 'application/x-turtle', - 'nt': 'text/plain', - 'xml': 'application/xml'} -JSON_FORMATS = { - 'lp': 'application/ld+json', - 'loud': 'application/ld+json', - 'geojson': 'application/json', - 'geojson-v2': 'application/json'} -API_FORMATS = RDF_FORMATS | JSON_FORMATS - -API_PROXY = '' - -LOGICAL_OPERATOR: list[str] = ['and', 'or'] -STR_CATEGORIES: list[str] = [ - "entityName", "entityDescription", "entityAliases", "entityCidocClass", - "entitySystemClass", "typeName", "typeNameWithSubs", - "beginFrom", "beginTo", "endFrom", "endTo"] -INT_CATEGORIES: list[str] = [ - "entityID", "typeID", "typeIDWithSubs", "relationToID"] -SET_CATEGORIES: list[str] = ["valueTypeID"] -VALID_CATEGORIES: list[str] = [ - *STR_CATEGORIES, - *INT_CATEGORIES, - *SET_CATEGORIES] -COMPARE_OPERATORS: list[str] = [ - 'equal', 'notEqual', 'greaterThan', 'lesserThan', 'greaterThanEqual', - 'lesserThanEqual', 'like'] - -# Used to connect to ACDH-CH ARCHE systems -ARCHE = {'id': None, 'url': None} - -# Used to connect to password protected Vocabs systems -VOCABS_PASS = '' - # Table options TABLE_ROWS = {10: '10', 25: '25', 50: '50', 100: '100'} diff --git a/openatlas/__init__.py b/openatlas/__init__.py index 7499955aa..a100dce16 100644 --- a/openatlas/__init__.py +++ b/openatlas/__init__.py @@ -13,6 +13,7 @@ app: Flask = Flask(__name__, instance_relative_config=True) csrf = CSRFProtect(app) # Make sure all forms are CSRF protected app.config.from_object('config.default') +app.config.from_object('config.api_config') app.config.from_pyfile('production.py') app.config['WTF_CSRF_TIME_LIMIT'] = None # Set CSRF token valid for session diff --git a/openatlas/api/formats/linked_places.py b/openatlas/api/formats/linked_places.py index 80323f1ea..7d97fa269 100644 --- a/openatlas/api/formats/linked_places.py +++ b/openatlas/api/formats/linked_places.py @@ -20,7 +20,7 @@ def get_linked_places_entity( links_inverse = entity_dict['links_inverse'] return { 'type': 'FeatureCollection', - '@context': app.config['API_SCHEMA'], + '@context': app.config['API_CONTEXT']['LPF'], 'features': [replace_empty_list_values_in_dict_with_none({ '@id': url_for('view', id_=entity.id, _external=True), 'type': 'Feature', diff --git a/openatlas/api/formats/loud.py b/openatlas/api/formats/loud.py index f4eacbf30..738bcba10 100644 --- a/openatlas/api/formats/loud.py +++ b/openatlas/api/formats/loud.py @@ -3,6 +3,7 @@ from flask import url_for +from openatlas import app from openatlas.display.util import get_file_path from openatlas.models.gis import Gis from openatlas.api.resources.util import remove_spaces_dashes, date_to_str, \ @@ -93,7 +94,7 @@ def get_domain_links() -> dict[str, Any]: "_label": label, "type": "DigitalObject"}]}) - return {'@context': "https://linked.art/ns/v1/linked-art.json"} | \ + return {'@context': app.config['API_CONTEXT']['LOUD']} | \ base_entity_dict() | properties_set # type: ignore From 688a97b223662ed76fb8f537ce291ac3a998c3ad Mon Sep 17 00:00:00 2001 From: Alexander Watzinger Date: Wed, 4 Oct 2023 17:13:20 +0200 Subject: [PATCH 28/32] Modification for places --- openatlas/forms/field.py | 3 ++- openatlas/forms/manager.py | 18 ++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/openatlas/forms/field.py b/openatlas/forms/field.py index 138ed3051..68bfec08d 100644 --- a/openatlas/forms/field.py +++ b/openatlas/forms/field.py @@ -155,7 +155,8 @@ def __call__( **kwargs: Any) -> TableMultiSelect: data = field.data or [] data = ast.literal_eval(data) if isinstance(data, str) else data - class_ = field.id if field.id != 'given_place' else 'place' + class_ = field.id \ + if field.id not in ['given_place', 'modified_place'] else 'place' aliases = current_user.settings['table_show_aliases'] if class_ in ['group', 'person']: entities = Entity.get_by_class(class_, types=True, aliases=aliases) diff --git a/openatlas/forms/manager.py b/openatlas/forms/manager.py index ba87c0f8e..4de4b7bcc 100644 --- a/openatlas/forms/manager.py +++ b/openatlas/forms/manager.py @@ -389,19 +389,29 @@ class ModificationManager(EventBaseManager): def additional_fields(self) -> dict[str, Any]: return dict( super().additional_fields(), - **{'artifact': TableMultiField()}) + **{ + 'artifact': TableMultiField(), + 'modified_place': TableMultiField('place')}) def populate_update(self) -> None: super().populate_update() - self.form.artifact.data = \ - [item.id for item in self.entity.get_linked_entities('P31')] + artifact_data = [] + place_data = [] + for item in self.entity.get_linked_entities('P31'): + if item.class_.name == 'artifact': + artifact_data.append(item.id) + elif item.cidoc_class.code == 'E18': + place_data.append(item.id) + self.form.artifact.data = artifact_data + self.form.modified_place.data = place_data def process_form(self) -> None: super().process_form() self.data['links']['delete'].add('P31') if self.form.artifact.data: self.add_link('P31', self.form.artifact.data) - + if self.form.modified_place.data: + self.add_link('P31', self.form.modified_place.data) class MoveManager(EventBaseManager): From 1fd9337b8e65d58eea62f3ed4e3f77005da13092 Mon Sep 17 00:00:00 2001 From: bkoschicek Date: Mon, 9 Oct 2023 13:46:13 +0200 Subject: [PATCH 29/32] added RDF creation with LOUD --- openatlas/api/resources/resolve_endpoints.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openatlas/api/resources/resolve_endpoints.py b/openatlas/api/resources/resolve_endpoints.py index a853cc2c6..56e8169bd 100644 --- a/openatlas/api/resources/resolve_endpoints.py +++ b/openatlas/api/resources/resolve_endpoints.py @@ -185,7 +185,8 @@ def get_entities_formatted( entities_dict[link_.domain.id]['links'].append(link_) for link_ in link_parser_check_inverse(entities, parser): entities_dict[link_.range.id]['links_inverse'].append(link_) - if parser['format'] == 'loud': + if parser['format'] == 'loud' \ + or parser['format'] in app.config['RDF_FORMATS']: return [get_loud_entities(item, parse_loud_context()) for item in entities_dict.values()] return [get_linked_places_entity(item, parser) From 788a7394bc468d36fb3f92f4be42138c9e8c9be5 Mon Sep 17 00:00:00 2001 From: Alexander Watzinger Date: Tue, 10 Oct 2023 12:11:51 +0200 Subject: [PATCH 30/32] Modification for places (#2070) --- openatlas/display/base_display.py | 2 +- openatlas/display/display.py | 2 +- openatlas/views/changelog.py | 1 + tests/test_event.py | 5 ++++- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/openatlas/display/base_display.py b/openatlas/display/base_display.py index 2c45cd518..69f48829d 100644 --- a/openatlas/display/base_display.py +++ b/openatlas/display/base_display.py @@ -378,7 +378,7 @@ def add_tabs(self) -> None: and current_user.settings['module_map_overlay']: self.tabs['file'].table.header.append(_('overlay')) - for link_ in entity.get_links('P67', inverse=True): + for link_ in entity.get_links(['P31', 'P67'], inverse=True): domain = link_.domain data = get_base_table_data(domain) if domain.class_.view == 'file': diff --git a/openatlas/display/display.py b/openatlas/display/display.py index 88f6236e8..89d12c486 100644 --- a/openatlas/display/display.py +++ b/openatlas/display/display.py @@ -152,7 +152,7 @@ class ModificationDisplay(EventsDisplay): def add_data(self) -> None: super().add_data() - self.data[_('artifact')] = \ + self.data[_('object')] = \ [link(entity) for entity in self.entity.get_linked_entities('P31')] diff --git a/openatlas/views/changelog.py b/openatlas/views/changelog.py index 561d609bf..2ca6a7953 100644 --- a/openatlas/views/changelog.py +++ b/openatlas/views/changelog.py @@ -18,6 +18,7 @@ def index_changelog() -> str: '7.17.0': ['TBA', { 'feature': { '2026': 'External reference systems for type hierarchies', + '2070': 'Modification (E11) for Place (E18)', '2083': 'API: List of images'}, 'fix': { '2078': 'API: CSV export not working' diff --git a/tests/test_event.py b/tests/test_event.py index 224c6463a..ce11a30a3 100644 --- a/tests/test_event.py +++ b/tests/test_event.py @@ -111,7 +111,10 @@ def test_event(self) -> None: rv = self.app.post( url_for('insert', class_='modification'), - data={'name': 'A modification event', 'artifact': artifact.id}) + data={ + 'name': 'A modification event', + 'artifact': artifact.id, + 'modified_place': residence.id}) modification_id = rv.location.split('/')[-1] rv = self.app.get(url_for('view', id_=modification_id)) From 2bd5b31dd7638bdd3f9fa3639b7136b4580cc2c8 Mon Sep 17 00:00:00 2001 From: Alexander Watzinger Date: Tue, 10 Oct 2023 12:28:21 +0200 Subject: [PATCH 31/32] Mypy checks --- openatlas/api/formats/loud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openatlas/api/formats/loud.py b/openatlas/api/formats/loud.py index 738bcba10..9f5efdbbc 100644 --- a/openatlas/api/formats/loud.py +++ b/openatlas/api/formats/loud.py @@ -95,7 +95,7 @@ def get_domain_links() -> dict[str, Any]: "type": "DigitalObject"}]}) return {'@context': app.config['API_CONTEXT']['LOUD']} | \ - base_entity_dict() | properties_set # type: ignore + base_entity_dict() | properties_set def get_loud_timespan(entity: Entity) -> dict[str, Any]: From e24ef813d21cc21d29b3bfe9bb39b3e0f43608cc Mon Sep 17 00:00:00 2001 From: bkoschicek Date: Fri, 13 Oct 2023 14:55:10 +0200 Subject: [PATCH 32/32] github test coverage --- tests/test_api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_api.py b/tests/test_api.py index 6464f7857..a01201242 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -761,10 +761,10 @@ def test_api(self) -> None: # Image Endpoints rv = self.app.get(url_for('api_03.licensed_file_overview')) - assert '152' in rv.get_json() + assert bool(len(rv.get_json().keys()) == 3) rv = self.app.get(url_for( 'api_03.licensed_file_overview', file_id='154')) - assert '154' in rv.get_json() + assert bool(len(rv.get_json().keys()) == 1) # Test Error Handling for rv in [