dsp-tools 9.1.0.post11__py3-none-any.whl → 18.3.0.post13__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dsp_tools/__init__.py +4 -0
- dsp_tools/cli/args.py +36 -0
- dsp_tools/cli/call_action.py +51 -231
- dsp_tools/cli/call_action_files_only.py +101 -0
- dsp_tools/cli/call_action_with_network.py +207 -0
- dsp_tools/cli/create_parsers.py +156 -58
- dsp_tools/cli/entry_point.py +56 -26
- dsp_tools/cli/utils.py +87 -0
- dsp_tools/clients/CLAUDE.md +420 -0
- dsp_tools/clients/authentication_client.py +14 -0
- dsp_tools/clients/authentication_client_live.py +66 -0
- dsp_tools/{utils → clients}/connection.py +2 -18
- dsp_tools/clients/connection_live.py +233 -0
- dsp_tools/clients/fuseki_metrics.py +60 -0
- dsp_tools/clients/group_user_clients.py +35 -0
- dsp_tools/clients/group_user_clients_live.py +181 -0
- dsp_tools/clients/legal_info_client.py +23 -0
- dsp_tools/clients/legal_info_client_live.py +132 -0
- dsp_tools/clients/list_client.py +49 -0
- dsp_tools/clients/list_client_live.py +166 -0
- dsp_tools/clients/metadata_client.py +24 -0
- dsp_tools/clients/metadata_client_live.py +47 -0
- dsp_tools/clients/ontology_clients.py +49 -0
- dsp_tools/clients/ontology_create_client_live.py +166 -0
- dsp_tools/clients/ontology_get_client_live.py +80 -0
- dsp_tools/clients/permissions_client.py +68 -0
- dsp_tools/clients/project_client.py +16 -0
- dsp_tools/clients/project_client_live.py +66 -0
- dsp_tools/commands/create/communicate_problems.py +24 -0
- dsp_tools/commands/create/create.py +134 -0
- dsp_tools/commands/create/create_on_server/cardinalities.py +111 -0
- dsp_tools/commands/create/create_on_server/classes.py +99 -0
- dsp_tools/commands/create/create_on_server/complete_ontologies.py +116 -0
- dsp_tools/commands/create/create_on_server/default_permissions.py +134 -0
- dsp_tools/commands/create/create_on_server/group_users.py +165 -0
- dsp_tools/commands/create/create_on_server/lists.py +163 -0
- dsp_tools/commands/create/create_on_server/mappers.py +12 -0
- dsp_tools/commands/create/create_on_server/onto_utils.py +74 -0
- dsp_tools/commands/create/create_on_server/ontology.py +52 -0
- dsp_tools/commands/create/create_on_server/project.py +68 -0
- dsp_tools/commands/create/create_on_server/properties.py +119 -0
- dsp_tools/commands/create/exceptions.py +29 -0
- dsp_tools/commands/create/lists_only.py +66 -0
- dsp_tools/commands/create/models/create_problems.py +87 -0
- dsp_tools/commands/create/models/parsed_ontology.py +88 -0
- dsp_tools/commands/create/models/parsed_project.py +81 -0
- dsp_tools/commands/create/models/rdf_ontology.py +12 -0
- dsp_tools/commands/create/models/server_project_info.py +100 -0
- dsp_tools/commands/create/parsing/parse_lists.py +45 -0
- dsp_tools/commands/create/parsing/parse_ontology.py +243 -0
- dsp_tools/commands/create/parsing/parse_project.py +149 -0
- dsp_tools/commands/create/parsing/parsing_utils.py +40 -0
- dsp_tools/commands/create/project_validate.py +595 -0
- dsp_tools/commands/create/serialisation/ontology.py +119 -0
- dsp_tools/commands/create/serialisation/project.py +44 -0
- dsp_tools/commands/excel2json/CLAUDE.md +101 -0
- dsp_tools/commands/excel2json/json_header.py +57 -23
- dsp_tools/commands/excel2json/{new_lists → lists}/compliance_checks.py +26 -26
- dsp_tools/commands/excel2json/{new_lists/make_new_lists.py → lists/make_lists.py} +19 -18
- dsp_tools/commands/excel2json/{new_lists → lists}/models/input_error.py +1 -12
- dsp_tools/commands/excel2json/{new_lists → lists}/models/serialise.py +9 -5
- dsp_tools/commands/excel2json/{new_lists → lists}/utils.py +4 -4
- dsp_tools/commands/excel2json/models/input_error.py +31 -11
- dsp_tools/commands/excel2json/models/json_header.py +53 -15
- dsp_tools/commands/excel2json/models/ontology.py +4 -3
- dsp_tools/commands/excel2json/{lists.py → old_lists.py} +26 -112
- dsp_tools/commands/excel2json/project.py +78 -34
- dsp_tools/commands/excel2json/properties.py +57 -36
- dsp_tools/commands/excel2json/resources.py +32 -12
- dsp_tools/commands/excel2json/utils.py +20 -1
- dsp_tools/commands/excel2xml/__init__.py +2 -2
- dsp_tools/commands/excel2xml/excel2xml_cli.py +7 -15
- dsp_tools/commands/excel2xml/excel2xml_lib.py +138 -493
- dsp_tools/commands/excel2xml/propertyelement.py +5 -5
- dsp_tools/commands/{project → get}/get.py +29 -13
- dsp_tools/commands/get/get_permissions.py +257 -0
- dsp_tools/commands/get/get_permissions_legacy.py +89 -0
- dsp_tools/commands/{project/models → get/legacy_models}/context.py +6 -6
- dsp_tools/commands/{project/models → get/legacy_models}/group.py +5 -10
- dsp_tools/commands/{project/models → get/legacy_models}/listnode.py +5 -35
- dsp_tools/commands/{project/models → get/legacy_models}/model.py +1 -1
- dsp_tools/commands/{project/models → get/legacy_models}/ontology.py +9 -14
- dsp_tools/commands/{project/models → get/legacy_models}/project.py +13 -6
- dsp_tools/commands/{project/models → get/legacy_models}/propertyclass.py +9 -16
- dsp_tools/commands/{project/models → get/legacy_models}/resourceclass.py +8 -46
- dsp_tools/commands/{project/models → get/legacy_models}/user.py +19 -60
- dsp_tools/commands/get/models/permissions_models.py +10 -0
- dsp_tools/commands/id2iri.py +20 -10
- dsp_tools/commands/ingest_xmlupload/bulk_ingest_client.py +81 -56
- dsp_tools/commands/ingest_xmlupload/create_resources/apply_ingest_id.py +4 -10
- dsp_tools/commands/ingest_xmlupload/create_resources/upload_xml.py +97 -37
- dsp_tools/commands/ingest_xmlupload/create_resources/user_information.py +2 -2
- dsp_tools/commands/ingest_xmlupload/ingest_files/ingest_files.py +9 -10
- dsp_tools/commands/ingest_xmlupload/upload_files/filechecker.py +3 -3
- dsp_tools/commands/ingest_xmlupload/upload_files/input_error.py +2 -10
- dsp_tools/commands/ingest_xmlupload/upload_files/upload_failures.py +12 -2
- dsp_tools/commands/ingest_xmlupload/upload_files/upload_files.py +8 -9
- dsp_tools/commands/resume_xmlupload/resume_xmlupload.py +18 -18
- dsp_tools/commands/start_stack.py +126 -77
- dsp_tools/commands/update_legal/CLAUDE.md +344 -0
- dsp_tools/commands/update_legal/__init__.py +0 -0
- dsp_tools/commands/update_legal/core.py +182 -0
- dsp_tools/commands/update_legal/csv_operations.py +135 -0
- dsp_tools/commands/update_legal/models.py +87 -0
- dsp_tools/commands/update_legal/xml_operations.py +247 -0
- dsp_tools/commands/validate_data/CLAUDE.md +159 -0
- dsp_tools/commands/validate_data/__init__.py +0 -0
- dsp_tools/commands/validate_data/constants.py +59 -0
- dsp_tools/commands/validate_data/mappers.py +143 -0
- dsp_tools/commands/validate_data/models/__init__.py +0 -0
- dsp_tools/commands/validate_data/models/api_responses.py +45 -0
- dsp_tools/commands/validate_data/models/input_problems.py +119 -0
- dsp_tools/commands/validate_data/models/rdf_like_data.py +117 -0
- dsp_tools/commands/validate_data/models/validation.py +106 -0
- dsp_tools/commands/validate_data/prepare_data/__init__.py +0 -0
- dsp_tools/commands/validate_data/prepare_data/get_rdf_like_data.py +296 -0
- dsp_tools/commands/validate_data/prepare_data/make_data_graph.py +91 -0
- dsp_tools/commands/validate_data/prepare_data/prepare_data.py +184 -0
- dsp_tools/commands/validate_data/process_validation_report/__init__.py +0 -0
- dsp_tools/commands/validate_data/process_validation_report/get_user_validation_message.py +358 -0
- dsp_tools/commands/validate_data/process_validation_report/query_validation_result.py +507 -0
- dsp_tools/commands/validate_data/process_validation_report/reformat_validation_results.py +150 -0
- dsp_tools/commands/validate_data/shacl_cli_validator.py +70 -0
- dsp_tools/commands/validate_data/sparql/__init__.py +0 -0
- dsp_tools/commands/{xml_validate/sparql/resource_shacl.py → validate_data/sparql/cardinality_shacl.py} +45 -47
- dsp_tools/commands/validate_data/sparql/construct_shacl.py +92 -0
- dsp_tools/commands/validate_data/sparql/legal_info_shacl.py +36 -0
- dsp_tools/commands/validate_data/sparql/value_shacl.py +357 -0
- dsp_tools/commands/validate_data/utils.py +59 -0
- dsp_tools/commands/validate_data/validate_data.py +283 -0
- dsp_tools/commands/validate_data/validation/__init__.py +0 -0
- dsp_tools/commands/validate_data/validation/check_duplicate_files.py +55 -0
- dsp_tools/commands/validate_data/validation/check_for_unknown_classes.py +67 -0
- dsp_tools/commands/validate_data/validation/get_validation_report.py +94 -0
- dsp_tools/commands/validate_data/validation/validate_ontology.py +107 -0
- dsp_tools/commands/xmlupload/CLAUDE.md +292 -0
- dsp_tools/commands/xmlupload/make_rdf_graph/__init__.py +0 -0
- dsp_tools/commands/xmlupload/make_rdf_graph/constants.py +63 -0
- dsp_tools/commands/xmlupload/make_rdf_graph/jsonld_utils.py +44 -0
- dsp_tools/commands/xmlupload/make_rdf_graph/make_file_value.py +77 -0
- dsp_tools/commands/xmlupload/make_rdf_graph/make_resource_and_values.py +114 -0
- dsp_tools/commands/xmlupload/make_rdf_graph/make_values.py +262 -0
- dsp_tools/commands/xmlupload/models/bitstream_info.py +18 -0
- dsp_tools/commands/xmlupload/models/formatted_text_value.py +0 -25
- dsp_tools/commands/xmlupload/models/ingest.py +56 -70
- dsp_tools/commands/xmlupload/models/input_problems.py +6 -14
- dsp_tools/commands/xmlupload/models/lookup_models.py +21 -0
- dsp_tools/commands/xmlupload/models/permission.py +0 -39
- dsp_tools/commands/xmlupload/models/{deserialise/xmlpermission.py → permissions_parsed.py} +2 -2
- dsp_tools/commands/xmlupload/models/processed/__init__.py +0 -0
- dsp_tools/commands/xmlupload/models/processed/file_values.py +29 -0
- dsp_tools/commands/xmlupload/models/processed/res.py +27 -0
- dsp_tools/commands/xmlupload/models/processed/values.py +101 -0
- dsp_tools/commands/xmlupload/models/rdf_models.py +26 -0
- dsp_tools/commands/xmlupload/models/upload_clients.py +3 -3
- dsp_tools/commands/xmlupload/models/upload_state.py +2 -4
- dsp_tools/commands/xmlupload/prepare_xml_input/__init__.py +0 -0
- dsp_tools/commands/xmlupload/{ark2iri.py → prepare_xml_input/ark2iri.py} +1 -1
- dsp_tools/commands/xmlupload/prepare_xml_input/get_processed_resources.py +252 -0
- dsp_tools/commands/xmlupload/{iiif_uri_validator.py → prepare_xml_input/iiif_uri_validator.py} +2 -14
- dsp_tools/commands/xmlupload/{list_client.py → prepare_xml_input/list_client.py} +15 -10
- dsp_tools/commands/xmlupload/prepare_xml_input/prepare_xml_input.py +67 -0
- dsp_tools/commands/xmlupload/prepare_xml_input/read_validate_xml_file.py +58 -0
- dsp_tools/commands/xmlupload/prepare_xml_input/transform_input_values.py +118 -0
- dsp_tools/commands/xmlupload/resource_create_client.py +7 -468
- dsp_tools/commands/xmlupload/richtext_id2iri.py +37 -0
- dsp_tools/commands/xmlupload/stash/{construct_and_analyze_graph.py → analyse_circular_reference_graph.py} +64 -157
- dsp_tools/commands/xmlupload/stash/create_info_for_graph.py +53 -0
- dsp_tools/commands/xmlupload/stash/graph_models.py +13 -8
- dsp_tools/commands/xmlupload/stash/stash_circular_references.py +48 -115
- dsp_tools/commands/xmlupload/stash/stash_models.py +4 -9
- dsp_tools/commands/xmlupload/stash/upload_stashed_resptr_props.py +34 -40
- dsp_tools/commands/xmlupload/stash/upload_stashed_xml_texts.py +98 -108
- dsp_tools/commands/xmlupload/upload_config.py +8 -0
- dsp_tools/commands/xmlupload/write_diagnostic_info.py +14 -9
- dsp_tools/commands/xmlupload/xmlupload.py +214 -192
- dsp_tools/config/__init__.py +0 -0
- dsp_tools/config/logger_config.py +69 -0
- dsp_tools/{utils → config}/warnings_config.py +4 -1
- dsp_tools/error/__init__.py +0 -0
- dsp_tools/error/custom_warnings.py +39 -0
- dsp_tools/error/exceptions.py +204 -0
- dsp_tools/error/problems.py +10 -0
- dsp_tools/error/xmllib_errors.py +20 -0
- dsp_tools/error/xmllib_warnings.py +54 -0
- dsp_tools/error/xmllib_warnings_util.py +159 -0
- dsp_tools/error/xsd_validation_error_msg.py +19 -0
- dsp_tools/legacy_models/__init__.py +0 -0
- dsp_tools/{models → legacy_models}/datetimestamp.py +7 -7
- dsp_tools/{models → legacy_models}/langstring.py +1 -1
- dsp_tools/{models → legacy_models}/projectContext.py +4 -4
- dsp_tools/resources/schema/data.xsd +108 -83
- dsp_tools/resources/schema/lists-only.json +4 -23
- dsp_tools/resources/schema/project.json +80 -35
- dsp_tools/resources/schema/properties-only.json +1 -4
- dsp_tools/resources/start-stack/docker-compose.override-host.j2 +11 -0
- dsp_tools/resources/start-stack/docker-compose.yml +34 -30
- dsp_tools/resources/start-stack/dsp-app-config.json +45 -0
- dsp_tools/resources/start-stack/dsp-app-config.override-host.j2 +26 -0
- dsp_tools/resources/validate_data/api-shapes-resource-cardinalities.ttl +191 -0
- dsp_tools/resources/validate_data/api-shapes.ttl +804 -0
- dsp_tools/resources/validate_data/shacl-cli-image.yml +4 -0
- dsp_tools/resources/validate_data/validate-ontology.ttl +99 -0
- dsp_tools/utils/ansi_colors.py +32 -0
- dsp_tools/utils/data_formats/__init__.py +0 -0
- dsp_tools/utils/{date_util.py → data_formats/date_util.py} +13 -1
- dsp_tools/utils/data_formats/iri_util.py +30 -0
- dsp_tools/utils/{shared.py → data_formats/shared.py} +1 -35
- dsp_tools/utils/{uri_util.py → data_formats/uri_util.py} +12 -2
- dsp_tools/utils/fuseki_bloating.py +63 -0
- dsp_tools/utils/json_parsing.py +22 -0
- dsp_tools/utils/rdf_constants.py +42 -0
- dsp_tools/utils/rdflib_utils.py +10 -0
- dsp_tools/utils/replace_id_with_iri.py +66 -0
- dsp_tools/utils/request_utils.py +238 -0
- dsp_tools/utils/xml_parsing/__init__.py +0 -0
- dsp_tools/utils/xml_parsing/get_lookups.py +32 -0
- dsp_tools/utils/xml_parsing/get_parsed_resources.py +325 -0
- dsp_tools/utils/xml_parsing/models/__init__.py +0 -0
- dsp_tools/utils/xml_parsing/models/parsed_resource.py +76 -0
- dsp_tools/utils/xml_parsing/parse_clean_validate_xml.py +137 -0
- dsp_tools/xmllib/CLAUDE.md +302 -0
- dsp_tools/xmllib/__init__.py +49 -0
- dsp_tools/xmllib/general_functions.py +877 -0
- dsp_tools/xmllib/internal/__init__.py +0 -0
- dsp_tools/xmllib/internal/checkers.py +162 -0
- dsp_tools/xmllib/internal/circumvent_circular_imports.py +36 -0
- dsp_tools/xmllib/internal/constants.py +46 -0
- dsp_tools/xmllib/internal/input_converters.py +155 -0
- dsp_tools/xmllib/internal/serialise_file_value.py +57 -0
- dsp_tools/xmllib/internal/serialise_resource.py +177 -0
- dsp_tools/xmllib/internal/serialise_values.py +152 -0
- dsp_tools/xmllib/internal/type_aliases.py +11 -0
- dsp_tools/xmllib/models/config_options.py +28 -0
- dsp_tools/xmllib/models/date_formats.py +48 -0
- dsp_tools/xmllib/models/dsp_base_resources.py +1380 -400
- dsp_tools/xmllib/models/internal/__init__.py +0 -0
- dsp_tools/xmllib/models/internal/file_values.py +172 -0
- dsp_tools/xmllib/models/internal/geometry.py +162 -0
- dsp_tools/xmllib/models/{migration_metadata.py → internal/migration_metadata.py} +14 -10
- dsp_tools/xmllib/models/internal/serialise_permissions.py +66 -0
- dsp_tools/xmllib/models/internal/values.py +342 -0
- dsp_tools/xmllib/models/licenses/__init__.py +0 -0
- dsp_tools/xmllib/models/licenses/other.py +59 -0
- dsp_tools/xmllib/models/licenses/recommended.py +107 -0
- dsp_tools/xmllib/models/permissions.py +41 -0
- dsp_tools/xmllib/models/res.py +1782 -0
- dsp_tools/xmllib/models/root.py +313 -26
- dsp_tools/xmllib/value_checkers.py +310 -47
- dsp_tools/xmllib/value_converters.py +765 -8
- dsp_tools-18.3.0.post13.dist-info/METADATA +90 -0
- dsp_tools-18.3.0.post13.dist-info/RECORD +286 -0
- dsp_tools-18.3.0.post13.dist-info/WHEEL +4 -0
- {dsp_tools-9.1.0.post11.dist-info → dsp_tools-18.3.0.post13.dist-info}/entry_points.txt +1 -0
- dsp_tools/commands/project/create/project_create.py +0 -1107
- dsp_tools/commands/project/create/project_create_lists.py +0 -204
- dsp_tools/commands/project/create/project_validate.py +0 -453
- dsp_tools/commands/project/models/project_definition.py +0 -12
- dsp_tools/commands/rosetta.py +0 -124
- dsp_tools/commands/template.py +0 -30
- dsp_tools/commands/xml_validate/api_connection.py +0 -122
- dsp_tools/commands/xml_validate/deserialise_input.py +0 -135
- dsp_tools/commands/xml_validate/make_data_rdf.py +0 -193
- dsp_tools/commands/xml_validate/models/data_deserialised.py +0 -108
- dsp_tools/commands/xml_validate/models/data_rdf.py +0 -214
- dsp_tools/commands/xml_validate/models/input_problems.py +0 -191
- dsp_tools/commands/xml_validate/models/validation.py +0 -29
- dsp_tools/commands/xml_validate/reformat_validaton_result.py +0 -89
- dsp_tools/commands/xml_validate/sparql/construct_shapes.py +0 -16
- dsp_tools/commands/xml_validate/xml_validate.py +0 -151
- dsp_tools/commands/xmlupload/check_consistency_with_ontology.py +0 -253
- dsp_tools/commands/xmlupload/models/deserialise/deserialise_value.py +0 -236
- dsp_tools/commands/xmlupload/models/deserialise/xmlresource.py +0 -171
- dsp_tools/commands/xmlupload/models/namespace_context.py +0 -39
- dsp_tools/commands/xmlupload/models/ontology_lookup_models.py +0 -161
- dsp_tools/commands/xmlupload/models/ontology_problem_models.py +0 -178
- dsp_tools/commands/xmlupload/models/serialise/jsonld_serialiser.py +0 -40
- dsp_tools/commands/xmlupload/models/serialise/serialise_value.py +0 -51
- dsp_tools/commands/xmlupload/ontology_client.py +0 -92
- dsp_tools/commands/xmlupload/project_client.py +0 -91
- dsp_tools/commands/xmlupload/read_validate_xml_file.py +0 -99
- dsp_tools/models/custom_warnings.py +0 -31
- dsp_tools/models/exceptions.py +0 -90
- dsp_tools/resources/0100-template-repo/template.json +0 -45
- dsp_tools/resources/0100-template-repo/template.xml +0 -27
- dsp_tools/resources/start-stack/docker-compose-validation.yml +0 -5
- dsp_tools/resources/start-stack/start-stack-config.yml +0 -4
- dsp_tools/resources/xml_validate/api-shapes.ttl +0 -411
- dsp_tools/resources/xml_validate/replace_namespace.xslt +0 -61
- dsp_tools/utils/connection_live.py +0 -383
- dsp_tools/utils/iri_util.py +0 -14
- dsp_tools/utils/logger_config.py +0 -41
- dsp_tools/utils/set_encoder.py +0 -20
- dsp_tools/utils/xml_utils.py +0 -145
- dsp_tools/utils/xml_validation.py +0 -197
- dsp_tools/utils/xml_validation_models.py +0 -68
- dsp_tools/xmllib/models/file_values.py +0 -78
- dsp_tools/xmllib/models/resource.py +0 -415
- dsp_tools/xmllib/models/values.py +0 -428
- dsp_tools-9.1.0.post11.dist-info/METADATA +0 -130
- dsp_tools-9.1.0.post11.dist-info/RECORD +0 -167
- dsp_tools-9.1.0.post11.dist-info/WHEEL +0 -4
- dsp_tools-9.1.0.post11.dist-info/licenses/LICENSE +0 -674
- /dsp_tools/{commands/excel2json/new_lists → clients}/__init__.py +0 -0
- /dsp_tools/commands/{excel2json/new_lists/models → create}/__init__.py +0 -0
- /dsp_tools/commands/{project → create/create_on_server}/__init__.py +0 -0
- /dsp_tools/commands/{project/create → create/models}/__init__.py +0 -0
- /dsp_tools/commands/{project/models → create/parsing}/__init__.py +0 -0
- /dsp_tools/commands/{xml_validate → create/serialisation}/__init__.py +0 -0
- /dsp_tools/commands/{xml_validate/models → excel2json/lists}/__init__.py +0 -0
- /dsp_tools/commands/{xml_validate/sparql → excel2json/lists/models}/__init__.py +0 -0
- /dsp_tools/commands/excel2json/{new_lists → lists}/models/deserialise.py +0 -0
- /dsp_tools/commands/{xmlupload/models/deserialise → get}/__init__.py +0 -0
- /dsp_tools/commands/{xmlupload/models/serialise → get/legacy_models}/__init__.py +0 -0
- /dsp_tools/commands/{project/models → get/legacy_models}/helpers.py +0 -0
- /dsp_tools/{models → commands/get/models}/__init__.py +0 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any
|
|
5
|
+
from typing import Protocol
|
|
6
|
+
|
|
7
|
+
from dsp_tools.clients.authentication_client import AuthenticationClient
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class OneList:
|
|
12
|
+
list_iri: str
|
|
13
|
+
list_name: str
|
|
14
|
+
nodes: list[OneNode]
|
|
15
|
+
|
|
16
|
+
def hlist(self) -> str:
|
|
17
|
+
return f'"hlist=<{self.list_iri}>"'
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class OneNode:
|
|
22
|
+
name: str
|
|
23
|
+
iri: str
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class ListGetClient(Protocol):
|
|
28
|
+
"""Client to request and reformat the lists of a project."""
|
|
29
|
+
|
|
30
|
+
api_url: str
|
|
31
|
+
shortcode: str
|
|
32
|
+
|
|
33
|
+
def get_all_lists_and_nodes(self) -> list[OneList]:
|
|
34
|
+
"""Get all lists and its nodes from a project."""
|
|
35
|
+
|
|
36
|
+
def get_all_list_iris_and_names(self) -> dict[str, str]:
|
|
37
|
+
"""Get all list names and IRIs"""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class ListCreateClient(Protocol):
|
|
42
|
+
api_url: str
|
|
43
|
+
auth: AuthenticationClient
|
|
44
|
+
|
|
45
|
+
def create_new_list(self, list_info: dict[str, Any]) -> str | None:
|
|
46
|
+
"""Create a new list."""
|
|
47
|
+
|
|
48
|
+
def add_list_node(self, node_info: dict[str, Any], parent_iri: str) -> str | None:
|
|
49
|
+
"""Add a list node to an existing list."""
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from http import HTTPStatus
|
|
3
|
+
from typing import Any
|
|
4
|
+
from typing import cast
|
|
5
|
+
from urllib.parse import quote_plus
|
|
6
|
+
|
|
7
|
+
import requests
|
|
8
|
+
from requests import RequestException
|
|
9
|
+
from requests import Response
|
|
10
|
+
|
|
11
|
+
from dsp_tools.clients.authentication_client import AuthenticationClient
|
|
12
|
+
from dsp_tools.clients.list_client import ListCreateClient
|
|
13
|
+
from dsp_tools.clients.list_client import ListGetClient
|
|
14
|
+
from dsp_tools.clients.list_client import OneList
|
|
15
|
+
from dsp_tools.clients.list_client import OneNode
|
|
16
|
+
from dsp_tools.error.exceptions import BadCredentialsError
|
|
17
|
+
from dsp_tools.error.exceptions import FatalNonOkApiResponseCode
|
|
18
|
+
from dsp_tools.utils.request_utils import RequestParameters
|
|
19
|
+
from dsp_tools.utils.request_utils import log_and_raise_request_exception
|
|
20
|
+
from dsp_tools.utils.request_utils import log_and_warn_unexpected_non_ok_response
|
|
21
|
+
from dsp_tools.utils.request_utils import log_request
|
|
22
|
+
from dsp_tools.utils.request_utils import log_response
|
|
23
|
+
|
|
24
|
+
TIMEOUT = 60
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class ListGetClientLive(ListGetClient):
|
|
29
|
+
"""Client to request and reformat the lists of a project."""
|
|
30
|
+
|
|
31
|
+
api_url: str
|
|
32
|
+
shortcode: str
|
|
33
|
+
|
|
34
|
+
def get_all_lists_and_nodes(self) -> list[OneList]:
|
|
35
|
+
list_json = self._get_all_list_iris()
|
|
36
|
+
all_iris = self._extract_list_iris(list_json)
|
|
37
|
+
all_lists = [self._get_one_list(iri) for iri in all_iris]
|
|
38
|
+
return [self._reformat_one_list(lst) for lst in all_lists]
|
|
39
|
+
|
|
40
|
+
def get_all_list_iris_and_names(self) -> dict[str, str]:
|
|
41
|
+
response_json = self._get_all_list_iris()
|
|
42
|
+
iris = self._extract_list_iris(response_json)
|
|
43
|
+
names = [x["name"] for x in response_json["lists"]]
|
|
44
|
+
return dict(zip(names, iris))
|
|
45
|
+
|
|
46
|
+
def _get_all_list_iris(self) -> dict[str, Any]:
|
|
47
|
+
url = f"{self.api_url}/admin/lists?projectShortcode={self.shortcode}"
|
|
48
|
+
timeout = 10
|
|
49
|
+
log_request(RequestParameters("GET", url, timeout))
|
|
50
|
+
try:
|
|
51
|
+
response = requests.get(url=url, timeout=timeout)
|
|
52
|
+
except RequestException as err:
|
|
53
|
+
log_and_raise_request_exception(err)
|
|
54
|
+
|
|
55
|
+
log_response(response)
|
|
56
|
+
if response.ok:
|
|
57
|
+
json_response = cast(dict[str, Any], response.json())
|
|
58
|
+
return json_response
|
|
59
|
+
raise FatalNonOkApiResponseCode(url, response.status_code, response.text)
|
|
60
|
+
|
|
61
|
+
def _extract_list_iris(self, response_json: dict[str, Any]) -> list[str]:
|
|
62
|
+
return [x["id"] for x in response_json["lists"]]
|
|
63
|
+
|
|
64
|
+
def _get_one_list(self, list_iri: str) -> dict[str, Any]:
|
|
65
|
+
encoded_list_iri = quote_plus(list_iri)
|
|
66
|
+
url = f"{self.api_url}/admin/lists/{encoded_list_iri}"
|
|
67
|
+
timeout = 30
|
|
68
|
+
log_request(RequestParameters("GET", url, timeout))
|
|
69
|
+
try:
|
|
70
|
+
response = requests.get(url=url, timeout=timeout)
|
|
71
|
+
except RequestException as err:
|
|
72
|
+
log_and_raise_request_exception(err)
|
|
73
|
+
|
|
74
|
+
log_response(response, include_response_content=False)
|
|
75
|
+
if response.ok:
|
|
76
|
+
response_json = cast(dict[str, Any], response.json())
|
|
77
|
+
return response_json
|
|
78
|
+
raise FatalNonOkApiResponseCode(url, response.status_code, response.text)
|
|
79
|
+
|
|
80
|
+
def _reformat_one_list(self, response_json: dict[str, Any]) -> OneList:
|
|
81
|
+
list_name = response_json["list"]["listinfo"]["name"]
|
|
82
|
+
list_id = response_json["list"]["listinfo"]["id"]
|
|
83
|
+
nodes = response_json["list"]["children"]
|
|
84
|
+
all_nodes = []
|
|
85
|
+
for child in nodes:
|
|
86
|
+
all_nodes.append(OneNode(child["name"], child["id"]))
|
|
87
|
+
if node_child := child.get("children"):
|
|
88
|
+
self._reformat_children(node_child, all_nodes)
|
|
89
|
+
return OneList(list_iri=list_id, list_name=list_name, nodes=all_nodes)
|
|
90
|
+
|
|
91
|
+
def _reformat_children(self, list_child: list[dict[str, Any]], current_nodes: list[OneNode]) -> None:
|
|
92
|
+
for child in list_child:
|
|
93
|
+
current_nodes.append(OneNode(child["name"], child["id"]))
|
|
94
|
+
if grand_child := child.get("children"):
|
|
95
|
+
self._reformat_children(grand_child, current_nodes)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@dataclass
|
|
99
|
+
class ListCreateClientLive(ListCreateClient):
|
|
100
|
+
api_url: str
|
|
101
|
+
project_iri: str
|
|
102
|
+
auth: AuthenticationClient
|
|
103
|
+
|
|
104
|
+
def create_new_list(self, list_info: dict[str, Any]) -> str | None:
|
|
105
|
+
url = f"{self.api_url}/admin/lists"
|
|
106
|
+
headers = self._get_request_header()
|
|
107
|
+
try:
|
|
108
|
+
response = _post_and_log_request(url, list_info, headers)
|
|
109
|
+
except RequestException as err:
|
|
110
|
+
log_and_raise_request_exception(err)
|
|
111
|
+
|
|
112
|
+
if response.ok:
|
|
113
|
+
result = response.json()
|
|
114
|
+
list_iri = cast(str, result["list"]["listinfo"]["id"])
|
|
115
|
+
return list_iri
|
|
116
|
+
if response.status_code == HTTPStatus.FORBIDDEN:
|
|
117
|
+
raise BadCredentialsError(
|
|
118
|
+
"Only a SystemAdmin or ProjectAdmin can create lists. "
|
|
119
|
+
"Your permissions are insufficient for this action."
|
|
120
|
+
)
|
|
121
|
+
log_and_warn_unexpected_non_ok_response(response.status_code, response.text)
|
|
122
|
+
return None
|
|
123
|
+
|
|
124
|
+
def add_list_node(self, node_info: dict[str, Any], parent_iri: str) -> str | None:
|
|
125
|
+
encoded_parent_iri = quote_plus(parent_iri)
|
|
126
|
+
url = f"{self.api_url}/admin/lists/{encoded_parent_iri}"
|
|
127
|
+
headers = self._get_request_header()
|
|
128
|
+
try:
|
|
129
|
+
response = _post_and_log_request(url, node_info, headers)
|
|
130
|
+
except RequestException as err:
|
|
131
|
+
log_and_raise_request_exception(err)
|
|
132
|
+
|
|
133
|
+
if response.ok:
|
|
134
|
+
result = response.json()
|
|
135
|
+
node_iri = cast(str, result["nodeinfo"]["id"])
|
|
136
|
+
return node_iri
|
|
137
|
+
if response.status_code == HTTPStatus.FORBIDDEN:
|
|
138
|
+
raise BadCredentialsError(
|
|
139
|
+
"Only a SystemAdmin or ProjectAdmin can add nodes to lists. "
|
|
140
|
+
"Your permissions are insufficient for this action."
|
|
141
|
+
)
|
|
142
|
+
log_and_warn_unexpected_non_ok_response(response.status_code, response.text)
|
|
143
|
+
return None
|
|
144
|
+
|
|
145
|
+
def _get_request_header(self) -> dict[str, str]:
|
|
146
|
+
return {
|
|
147
|
+
"Content-Type": "application/json",
|
|
148
|
+
"Authorization": f"Bearer {self.auth.get_token()}",
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _post_and_log_request(
|
|
153
|
+
url: str,
|
|
154
|
+
data: dict[str, Any],
|
|
155
|
+
headers: dict[str, str] | None = None,
|
|
156
|
+
) -> Response:
|
|
157
|
+
params = RequestParameters("POST", url, TIMEOUT, data, headers)
|
|
158
|
+
log_request(params)
|
|
159
|
+
response = requests.post(
|
|
160
|
+
url=params.url,
|
|
161
|
+
headers=params.headers,
|
|
162
|
+
data=params.data_serialized,
|
|
163
|
+
timeout=params.timeout,
|
|
164
|
+
)
|
|
165
|
+
log_response(response)
|
|
166
|
+
return response
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from enum import auto
|
|
4
|
+
from typing import Protocol
|
|
5
|
+
|
|
6
|
+
from dsp_tools.clients.authentication_client import AuthenticationClient
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ExistingResourcesRetrieved(Enum):
|
|
10
|
+
TRUE = auto()
|
|
11
|
+
FALSE = auto()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class MetadataClient(Protocol):
|
|
16
|
+
"""
|
|
17
|
+
Protocol class/interface for the metadata endpoint in the API.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
server: str
|
|
21
|
+
authentication_client: AuthenticationClient
|
|
22
|
+
|
|
23
|
+
def get_resource_metadata(self, shortcode: str) -> tuple[ExistingResourcesRetrieved, list[dict[str, str]]]:
|
|
24
|
+
"""Get all resource metadata from one project."""
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from http import HTTPStatus
|
|
3
|
+
|
|
4
|
+
import requests
|
|
5
|
+
from loguru import logger
|
|
6
|
+
from requests import RequestException
|
|
7
|
+
|
|
8
|
+
from dsp_tools.clients.authentication_client import AuthenticationClient
|
|
9
|
+
from dsp_tools.clients.metadata_client import ExistingResourcesRetrieved
|
|
10
|
+
from dsp_tools.clients.metadata_client import MetadataClient
|
|
11
|
+
from dsp_tools.utils.request_utils import RequestParameters
|
|
12
|
+
from dsp_tools.utils.request_utils import log_and_warn_unexpected_non_ok_response
|
|
13
|
+
from dsp_tools.utils.request_utils import log_request
|
|
14
|
+
from dsp_tools.utils.request_utils import log_response
|
|
15
|
+
|
|
16
|
+
TIMEOUT = 120
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class MetadataClientLive(MetadataClient):
|
|
21
|
+
server: str
|
|
22
|
+
authentication_client: AuthenticationClient
|
|
23
|
+
|
|
24
|
+
def get_resource_metadata(self, shortcode: str) -> tuple[ExistingResourcesRetrieved, list[dict[str, str]]]:
|
|
25
|
+
url = f"{self.server}/v2/metadata/projects/{shortcode}/resources?format=JSON"
|
|
26
|
+
header = {"Authorization": f"Bearer {self.authentication_client.get_token()}"}
|
|
27
|
+
params = RequestParameters(method="GET", url=url, timeout=TIMEOUT, headers=header)
|
|
28
|
+
logger.debug("GET Resource Metadata")
|
|
29
|
+
log_request(params)
|
|
30
|
+
try:
|
|
31
|
+
response = requests.get(
|
|
32
|
+
url=params.url,
|
|
33
|
+
headers=params.headers,
|
|
34
|
+
timeout=params.timeout,
|
|
35
|
+
)
|
|
36
|
+
except RequestException as err:
|
|
37
|
+
logger.exception(err)
|
|
38
|
+
return ExistingResourcesRetrieved.FALSE, []
|
|
39
|
+
if response.ok:
|
|
40
|
+
log_response(response, include_response_content=False)
|
|
41
|
+
logger.debug(f"{len(response.json())} NUMBER OF RESOURCES RETRIEVED")
|
|
42
|
+
return ExistingResourcesRetrieved.TRUE, response.json()
|
|
43
|
+
if response.status_code != HTTPStatus.FORBIDDEN:
|
|
44
|
+
# this warning is to inform for unhandled status codes
|
|
45
|
+
# if the user has insufficient credentials but references resources in the XML, they will get informed then
|
|
46
|
+
log_and_warn_unexpected_non_ok_response(response.status_code, response.text)
|
|
47
|
+
return ExistingResourcesRetrieved.FALSE, []
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from typing import Protocol
|
|
3
|
+
|
|
4
|
+
from rdflib import Literal
|
|
5
|
+
|
|
6
|
+
from dsp_tools.clients.authentication_client import AuthenticationClient
|
|
7
|
+
from dsp_tools.utils.request_utils import ResponseCodeAndText
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class OntologyCreateClient(Protocol):
|
|
11
|
+
"""
|
|
12
|
+
Protocol class/interface to create / update the ontology through the API.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
server: str
|
|
16
|
+
authentication_client: AuthenticationClient
|
|
17
|
+
|
|
18
|
+
def get_last_modification_date(self, project_iri: str, onto_iri: str) -> Literal:
|
|
19
|
+
"""Get the last modification date of an ontology"""
|
|
20
|
+
|
|
21
|
+
def post_resource_cardinalities(self, cardinality_graph: dict[str, Any]) -> Literal | None:
|
|
22
|
+
"""Add cardinalities to an existing resource class."""
|
|
23
|
+
|
|
24
|
+
def post_new_property(self, property_graph: dict[str, Any]) -> Literal | ResponseCodeAndText:
|
|
25
|
+
"""Create a property on the server"""
|
|
26
|
+
|
|
27
|
+
def post_new_class(self, property_graph: dict[str, Any]) -> Literal | ResponseCodeAndText:
|
|
28
|
+
"""Create a class on the server"""
|
|
29
|
+
|
|
30
|
+
def post_new_ontology(self, onto_graph: dict[str, Any]) -> str | ResponseCodeAndText:
|
|
31
|
+
"""Create a new ontology on the server"""
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class OntologyGetClient(Protocol):
|
|
35
|
+
"""
|
|
36
|
+
Protocol class/interface to get ontologies from the API.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
api_url: str
|
|
40
|
+
shortcode: str
|
|
41
|
+
|
|
42
|
+
def get_knora_api(self) -> str:
|
|
43
|
+
"""Get the knora-api ontology."""
|
|
44
|
+
|
|
45
|
+
def get_ontologies(self) -> tuple[list[str], list[str]]:
|
|
46
|
+
"""Get all project ontologies."""
|
|
47
|
+
|
|
48
|
+
def _get_one_ontology(self, ontology_iri: str) -> str:
|
|
49
|
+
"""Get one ontology by its IRI."""
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from http import HTTPStatus
|
|
3
|
+
from typing import Any
|
|
4
|
+
from typing import cast
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
from rdflib import Graph
|
|
8
|
+
from rdflib import Literal
|
|
9
|
+
from rdflib import URIRef
|
|
10
|
+
from requests import RequestException
|
|
11
|
+
from requests import Response
|
|
12
|
+
|
|
13
|
+
from dsp_tools.clients.authentication_client import AuthenticationClient
|
|
14
|
+
from dsp_tools.clients.ontology_clients import OntologyCreateClient
|
|
15
|
+
from dsp_tools.error.exceptions import BadCredentialsError
|
|
16
|
+
from dsp_tools.error.exceptions import FatalNonOkApiResponseCode
|
|
17
|
+
from dsp_tools.utils.rdf_constants import KNORA_API
|
|
18
|
+
from dsp_tools.utils.request_utils import RequestParameters
|
|
19
|
+
from dsp_tools.utils.request_utils import ResponseCodeAndText
|
|
20
|
+
from dsp_tools.utils.request_utils import log_and_raise_request_exception
|
|
21
|
+
from dsp_tools.utils.request_utils import log_and_warn_unexpected_non_ok_response
|
|
22
|
+
from dsp_tools.utils.request_utils import log_request
|
|
23
|
+
from dsp_tools.utils.request_utils import log_response
|
|
24
|
+
|
|
25
|
+
TIMEOUT = 60
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class OntologyCreateClientLive(OntologyCreateClient):
|
|
30
|
+
"""
|
|
31
|
+
Client for the ontology endpoint in the API.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
server: str
|
|
35
|
+
authentication_client: AuthenticationClient
|
|
36
|
+
|
|
37
|
+
def get_last_modification_date(self, project_iri: str, onto_iri: str) -> Literal:
|
|
38
|
+
url = f"{self.server}/v2/ontologies/metadata"
|
|
39
|
+
header = {"X-Knora-Accept-Project": project_iri}
|
|
40
|
+
try:
|
|
41
|
+
response = self._get_and_log_request(url, header)
|
|
42
|
+
except RequestException as err:
|
|
43
|
+
log_and_raise_request_exception(err)
|
|
44
|
+
|
|
45
|
+
if response.ok:
|
|
46
|
+
return _parse_last_modification_date(response.text, URIRef(onto_iri))
|
|
47
|
+
raise FatalNonOkApiResponseCode(url, response.status_code, response.text)
|
|
48
|
+
|
|
49
|
+
def post_resource_cardinalities(self, cardinality_graph: dict[str, Any]) -> Literal | None:
|
|
50
|
+
url = f"{self.server}/v2/ontologies/cardinalities"
|
|
51
|
+
try:
|
|
52
|
+
response = self._post_and_log_request(url, cardinality_graph)
|
|
53
|
+
except RequestException as err:
|
|
54
|
+
log_and_raise_request_exception(err)
|
|
55
|
+
|
|
56
|
+
if response.ok:
|
|
57
|
+
return _parse_last_modification_date(response.text)
|
|
58
|
+
if response.status_code == HTTPStatus.FORBIDDEN:
|
|
59
|
+
raise BadCredentialsError(
|
|
60
|
+
"Only a SystemAdmin or ProjectAdmin can add cardinalities to resource classes. "
|
|
61
|
+
"Your permissions are insufficient for this action."
|
|
62
|
+
)
|
|
63
|
+
log_and_warn_unexpected_non_ok_response(response.status_code, response.text)
|
|
64
|
+
return None
|
|
65
|
+
|
|
66
|
+
def post_new_property(self, property_graph: dict[str, Any]) -> Literal | ResponseCodeAndText:
|
|
67
|
+
url = f"{self.server}/v2/ontologies/properties"
|
|
68
|
+
try:
|
|
69
|
+
response = self._post_and_log_request(url, property_graph)
|
|
70
|
+
except RequestException as err:
|
|
71
|
+
log_and_raise_request_exception(err)
|
|
72
|
+
|
|
73
|
+
if response.ok:
|
|
74
|
+
return _parse_last_modification_date(response.text)
|
|
75
|
+
if response.status_code == HTTPStatus.FORBIDDEN:
|
|
76
|
+
raise BadCredentialsError(
|
|
77
|
+
"Only a SystemAdmin or ProjectAdmin can create properties. "
|
|
78
|
+
"Your permissions are insufficient for this action."
|
|
79
|
+
)
|
|
80
|
+
return ResponseCodeAndText(response.status_code, response.text)
|
|
81
|
+
|
|
82
|
+
def post_new_class(self, class_graph: dict[str, Any]) -> Literal | ResponseCodeAndText:
|
|
83
|
+
url = f"{self.server}/v2/ontologies/classes"
|
|
84
|
+
try:
|
|
85
|
+
response = self._post_and_log_request(url, class_graph)
|
|
86
|
+
except RequestException as err:
|
|
87
|
+
log_and_raise_request_exception(err)
|
|
88
|
+
|
|
89
|
+
if response.ok:
|
|
90
|
+
return _parse_last_modification_date(response.text)
|
|
91
|
+
if response.status_code == HTTPStatus.FORBIDDEN:
|
|
92
|
+
raise BadCredentialsError(
|
|
93
|
+
"Only a SystemAdmin or ProjectAdmin can create classes. "
|
|
94
|
+
"Your permissions are insufficient for this action."
|
|
95
|
+
)
|
|
96
|
+
return ResponseCodeAndText(response.status_code, response.text)
|
|
97
|
+
|
|
98
|
+
def post_new_ontology(self, onto_graph: dict[str, Any]) -> str | ResponseCodeAndText:
|
|
99
|
+
url = f"{self.server}/v2/ontologies"
|
|
100
|
+
try:
|
|
101
|
+
response = self._post_and_log_request(url, onto_graph)
|
|
102
|
+
except RequestException as err:
|
|
103
|
+
log_and_raise_request_exception(err)
|
|
104
|
+
|
|
105
|
+
if response.ok:
|
|
106
|
+
response_json: dict[str, Any] = response.json()
|
|
107
|
+
return cast(str, response_json["@id"])
|
|
108
|
+
if response.status_code == HTTPStatus.FORBIDDEN:
|
|
109
|
+
raise BadCredentialsError(
|
|
110
|
+
"Only a SystemAdmin or ProjectAdmin can create new ontologies. "
|
|
111
|
+
"Your permissions are insufficient for this action."
|
|
112
|
+
)
|
|
113
|
+
return ResponseCodeAndText(response.status_code, response.text)
|
|
114
|
+
|
|
115
|
+
def _post_and_log_request(
|
|
116
|
+
self,
|
|
117
|
+
url: str,
|
|
118
|
+
data: dict[str, Any] | None,
|
|
119
|
+
headers: dict[str, str] | None = None,
|
|
120
|
+
) -> Response:
|
|
121
|
+
data_dict, generic_headers = self._prepare_request(data, headers)
|
|
122
|
+
params = RequestParameters("POST", url, TIMEOUT, data_dict, generic_headers)
|
|
123
|
+
log_request(params)
|
|
124
|
+
response = requests.post(
|
|
125
|
+
url=params.url,
|
|
126
|
+
headers=params.headers,
|
|
127
|
+
data=params.data_serialized,
|
|
128
|
+
timeout=params.timeout,
|
|
129
|
+
)
|
|
130
|
+
log_response(response)
|
|
131
|
+
return response
|
|
132
|
+
|
|
133
|
+
def _get_and_log_request(
|
|
134
|
+
self,
|
|
135
|
+
url: str,
|
|
136
|
+
headers: dict[str, str] | None = None,
|
|
137
|
+
) -> Response:
|
|
138
|
+
_, generic_headers = self._prepare_request({}, headers)
|
|
139
|
+
params = RequestParameters(method="GET", url=url, timeout=TIMEOUT, headers=generic_headers)
|
|
140
|
+
log_request(params)
|
|
141
|
+
response = requests.get(
|
|
142
|
+
url=params.url,
|
|
143
|
+
headers=params.headers,
|
|
144
|
+
timeout=params.timeout,
|
|
145
|
+
)
|
|
146
|
+
log_response(response)
|
|
147
|
+
return response
|
|
148
|
+
|
|
149
|
+
def _prepare_request(
|
|
150
|
+
self, data: dict[str, Any] | None, headers: dict[str, str] | None
|
|
151
|
+
) -> tuple[dict[str, Any] | None, dict[str, str]]:
|
|
152
|
+
generic_headers = {
|
|
153
|
+
"Content-Type": "application/json",
|
|
154
|
+
"Authorization": f"Bearer {self.authentication_client.get_token()}",
|
|
155
|
+
}
|
|
156
|
+
data_dict = data if data else None
|
|
157
|
+
if headers:
|
|
158
|
+
generic_headers.update(headers)
|
|
159
|
+
return data_dict, generic_headers
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _parse_last_modification_date(response_text: str, onto_iri: URIRef | None = None) -> Literal:
|
|
163
|
+
g = Graph()
|
|
164
|
+
g.parse(data=response_text, format="json-ld")
|
|
165
|
+
date = next(g.objects(subject=onto_iri, predicate=KNORA_API.lastModificationDate))
|
|
166
|
+
return cast(Literal, date)
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Any
|
|
3
|
+
from typing import cast
|
|
4
|
+
|
|
5
|
+
import requests
|
|
6
|
+
from requests import RequestException
|
|
7
|
+
|
|
8
|
+
from dsp_tools.clients.ontology_clients import OntologyGetClient
|
|
9
|
+
from dsp_tools.error.exceptions import FatalNonOkApiResponseCode
|
|
10
|
+
from dsp_tools.error.exceptions import ProjectOntologyNotFound
|
|
11
|
+
from dsp_tools.utils.request_utils import RequestParameters
|
|
12
|
+
from dsp_tools.utils.request_utils import log_and_raise_request_exception
|
|
13
|
+
from dsp_tools.utils.request_utils import log_request
|
|
14
|
+
from dsp_tools.utils.request_utils import log_response
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class OntologyGetClientLive(OntologyGetClient):
|
|
19
|
+
api_url: str
|
|
20
|
+
shortcode: str
|
|
21
|
+
|
|
22
|
+
def get_knora_api(self) -> str:
|
|
23
|
+
url = f"{self.api_url}/ontology/knora-api/v2#"
|
|
24
|
+
headers = {"Accept": "text/turtle"}
|
|
25
|
+
timeout = 60
|
|
26
|
+
params = RequestParameters("GET", url, timeout=timeout, headers=headers)
|
|
27
|
+
log_request(params)
|
|
28
|
+
try:
|
|
29
|
+
response = requests.get(url=params.url, headers=params.headers, timeout=params.timeout)
|
|
30
|
+
except RequestException as err:
|
|
31
|
+
log_and_raise_request_exception(err)
|
|
32
|
+
log_response(response, include_response_content=False)
|
|
33
|
+
if response.ok:
|
|
34
|
+
return response.text
|
|
35
|
+
raise FatalNonOkApiResponseCode(params.url, response.status_code, response.text)
|
|
36
|
+
|
|
37
|
+
def get_ontologies(self) -> tuple[list[str], list[str]]:
|
|
38
|
+
"""
|
|
39
|
+
Returns a list of project ontologies as a string in turtle format.
|
|
40
|
+
And a list of the ontology IRIs
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
list of ontologies and IRIs
|
|
44
|
+
"""
|
|
45
|
+
ontology_iris = self._get_ontology_iris()
|
|
46
|
+
ontologies = [self._get_one_ontology(x) for x in ontology_iris]
|
|
47
|
+
return ontologies, ontology_iris
|
|
48
|
+
|
|
49
|
+
def _get_ontology_iris(self) -> list[str]:
|
|
50
|
+
url = f"{self.api_url}/admin/projects/shortcode/{self.shortcode}"
|
|
51
|
+
timeout = 10
|
|
52
|
+
params = RequestParameters("GET", url, timeout=timeout)
|
|
53
|
+
log_request(params)
|
|
54
|
+
try:
|
|
55
|
+
response = requests.get(url=params.url, timeout=params.timeout)
|
|
56
|
+
except RequestException as err:
|
|
57
|
+
log_and_raise_request_exception(err)
|
|
58
|
+
log_response(response)
|
|
59
|
+
if not response.ok:
|
|
60
|
+
raise FatalNonOkApiResponseCode(params.url, response.status_code, response.text)
|
|
61
|
+
response_json = cast(dict[str, Any], response.json())
|
|
62
|
+
if not (ontos := response_json.get("project", {}).get("ontologies")):
|
|
63
|
+
raise ProjectOntologyNotFound(self.shortcode)
|
|
64
|
+
output = cast(list[str], ontos)
|
|
65
|
+
return output
|
|
66
|
+
|
|
67
|
+
def _get_one_ontology(self, ontology_iri: str) -> str:
|
|
68
|
+
url = ontology_iri
|
|
69
|
+
headers = {"Accept": "text/turtle"}
|
|
70
|
+
timeout = 30
|
|
71
|
+
params = RequestParameters("GET", url, timeout=timeout, headers=headers)
|
|
72
|
+
log_request(params)
|
|
73
|
+
try:
|
|
74
|
+
response = requests.get(url=params.url, headers=params.headers, timeout=params.timeout)
|
|
75
|
+
except RequestException as err:
|
|
76
|
+
log_and_raise_request_exception(err)
|
|
77
|
+
log_response(response, include_response_content=False)
|
|
78
|
+
if response.ok:
|
|
79
|
+
return response.text
|
|
80
|
+
raise FatalNonOkApiResponseCode(params.url, response.status_code, response.text)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Any
|
|
3
|
+
from urllib.parse import quote_plus
|
|
4
|
+
|
|
5
|
+
import requests
|
|
6
|
+
from loguru import logger
|
|
7
|
+
from requests import RequestException
|
|
8
|
+
|
|
9
|
+
from dsp_tools.clients.authentication_client import AuthenticationClient
|
|
10
|
+
from dsp_tools.utils.request_utils import RequestParameters
|
|
11
|
+
from dsp_tools.utils.request_utils import log_request
|
|
12
|
+
from dsp_tools.utils.request_utils import log_response
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class PermissionsClient:
|
|
17
|
+
auth: AuthenticationClient
|
|
18
|
+
proj_iri: str
|
|
19
|
+
|
|
20
|
+
def get_project_doaps(self) -> list[dict[str, Any]]:
|
|
21
|
+
params = RequestParameters(
|
|
22
|
+
"GET",
|
|
23
|
+
f"{self.auth.server}/admin/permissions/doap/{quote_plus(self.proj_iri)}",
|
|
24
|
+
timeout=10,
|
|
25
|
+
headers={"Accept": "application/json", "Authorization": f"Bearer {self.auth.get_token()}"},
|
|
26
|
+
)
|
|
27
|
+
log_request(params)
|
|
28
|
+
try:
|
|
29
|
+
response = requests.get(params.url, timeout=params.timeout, headers=params.headers)
|
|
30
|
+
log_response(response)
|
|
31
|
+
except RequestException:
|
|
32
|
+
logger.exception("Error while retrieving existing DOAPs")
|
|
33
|
+
return []
|
|
34
|
+
res: list[dict[str, Any]] = response.json()["default_object_access_permissions"]
|
|
35
|
+
return res
|
|
36
|
+
|
|
37
|
+
def delete_doap(self, doap_iri: str) -> bool:
|
|
38
|
+
params = RequestParameters(
|
|
39
|
+
"DELETE",
|
|
40
|
+
f"{self.auth.server}/admin/permissions/{quote_plus(doap_iri)}",
|
|
41
|
+
timeout=10,
|
|
42
|
+
headers={"Authorization": f"Bearer {self.auth.get_token()}"},
|
|
43
|
+
)
|
|
44
|
+
log_request(params)
|
|
45
|
+
try:
|
|
46
|
+
response = requests.delete(params.url, timeout=params.timeout, headers=params.headers)
|
|
47
|
+
log_response(response)
|
|
48
|
+
except RequestException:
|
|
49
|
+
logger.exception("Error while deleting DOAP")
|
|
50
|
+
return False
|
|
51
|
+
return True
|
|
52
|
+
|
|
53
|
+
def create_new_doap(self, payload: dict[str, Any]) -> bool:
|
|
54
|
+
params = RequestParameters(
|
|
55
|
+
"POST",
|
|
56
|
+
f"{self.auth.server}/admin/permissions/doap",
|
|
57
|
+
timeout=10,
|
|
58
|
+
headers={"Authorization": f"Bearer {self.auth.get_token()}"},
|
|
59
|
+
data=payload,
|
|
60
|
+
)
|
|
61
|
+
log_request(params)
|
|
62
|
+
try:
|
|
63
|
+
response = requests.post(params.url, timeout=params.timeout, headers=params.headers, json=params.data)
|
|
64
|
+
log_response(response)
|
|
65
|
+
except RequestException:
|
|
66
|
+
logger.exception("Error while creating new DOAP")
|
|
67
|
+
return False
|
|
68
|
+
return True
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Any
|
|
3
|
+
from typing import Protocol
|
|
4
|
+
|
|
5
|
+
from dsp_tools.utils.request_utils import ResponseCodeAndText
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class ProjectClient(Protocol):
|
|
10
|
+
server: str
|
|
11
|
+
|
|
12
|
+
def get_project_iri(self, shortcode: str) -> str:
|
|
13
|
+
"""Get the IRI of a project via shortcode."""
|
|
14
|
+
|
|
15
|
+
def post_new_project(self, project_info: dict[str, Any]) -> str | ResponseCodeAndText:
|
|
16
|
+
"""Post a new project."""
|