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
|
@@ -2,7 +2,7 @@ from dataclasses import dataclass
|
|
|
2
2
|
from typing import Optional
|
|
3
3
|
from typing import Union
|
|
4
4
|
|
|
5
|
-
from dsp_tools.
|
|
5
|
+
from dsp_tools.error.exceptions import BaseError
|
|
6
6
|
|
|
7
7
|
# ruff: noqa: E501 (line-too-long)
|
|
8
8
|
|
|
@@ -25,20 +25,20 @@ class PropertyElement:
|
|
|
25
25
|
|
|
26
26
|
>>> excel2xml.make_text_prop(":testproperty", "first text")
|
|
27
27
|
<text-prop name=":testproperty">
|
|
28
|
-
<text encoding="utf8" permissions="
|
|
28
|
+
<text encoding="utf8" permissions="public">
|
|
29
29
|
first text
|
|
30
30
|
</text>
|
|
31
31
|
</text-prop>
|
|
32
|
-
>>> excel2xml.make_text_prop(":testproperty", excel2xml.PropertyElement("first text", permissions="
|
|
32
|
+
>>> excel2xml.make_text_prop(":testproperty", excel2xml.PropertyElement("first text", permissions="private", encoding="xml"))
|
|
33
33
|
<text-prop name=":testproperty">
|
|
34
|
-
<text encoding="xml" permissions="
|
|
34
|
+
<text encoding="xml" permissions="private">
|
|
35
35
|
first text
|
|
36
36
|
</text>
|
|
37
37
|
</text-prop>
|
|
38
38
|
"""
|
|
39
39
|
|
|
40
40
|
value: Union[str, int, float, bool]
|
|
41
|
-
permissions: str = "
|
|
41
|
+
permissions: str = "public"
|
|
42
42
|
comment: Optional[str] = None
|
|
43
43
|
encoding: Optional[str] = None
|
|
44
44
|
|
|
@@ -5,14 +5,16 @@ from typing import Any
|
|
|
5
5
|
import regex
|
|
6
6
|
|
|
7
7
|
from dsp_tools.cli.args import ServerCredentials
|
|
8
|
-
from dsp_tools.
|
|
9
|
-
from dsp_tools.
|
|
10
|
-
from dsp_tools.
|
|
11
|
-
from dsp_tools.commands.
|
|
12
|
-
from dsp_tools.commands.
|
|
13
|
-
from dsp_tools.
|
|
14
|
-
from dsp_tools.
|
|
15
|
-
from dsp_tools.
|
|
8
|
+
from dsp_tools.clients.authentication_client_live import AuthenticationClientLive
|
|
9
|
+
from dsp_tools.clients.connection import Connection
|
|
10
|
+
from dsp_tools.clients.connection_live import ConnectionLive
|
|
11
|
+
from dsp_tools.commands.get.get_permissions import get_default_permissions
|
|
12
|
+
from dsp_tools.commands.get.legacy_models.group import Group
|
|
13
|
+
from dsp_tools.commands.get.legacy_models.listnode import ListNode
|
|
14
|
+
from dsp_tools.commands.get.legacy_models.ontology import Ontology
|
|
15
|
+
from dsp_tools.commands.get.legacy_models.project import Project
|
|
16
|
+
from dsp_tools.commands.get.legacy_models.user import User
|
|
17
|
+
from dsp_tools.error.exceptions import BaseError
|
|
16
18
|
|
|
17
19
|
|
|
18
20
|
def get_project(
|
|
@@ -36,24 +38,38 @@ def get_project(
|
|
|
36
38
|
Returns:
|
|
37
39
|
True if the process finishes without errors
|
|
38
40
|
"""
|
|
39
|
-
|
|
41
|
+
auth = AuthenticationClientLive(creds.server, creds.user, creds.password)
|
|
40
42
|
try:
|
|
41
|
-
|
|
43
|
+
auth.get_token()
|
|
44
|
+
con = ConnectionLive(creds.server, auth)
|
|
45
|
+
authenticated = True
|
|
42
46
|
except BaseError:
|
|
43
|
-
warnings.warn("WARNING: Missing or wrong credentials. You won't get data
|
|
47
|
+
warnings.warn("WARNING: Missing or wrong credentials. You won't get sensitive data of this project.")
|
|
48
|
+
con = ConnectionLive(creds.server)
|
|
49
|
+
authenticated = False
|
|
44
50
|
|
|
45
51
|
project = _create_project(con, project_identifier)
|
|
46
52
|
|
|
47
53
|
project = project.read()
|
|
48
54
|
project_obj = project.createDefinitionFileObj()
|
|
49
55
|
|
|
56
|
+
prefixes, ontos = _get_ontologies(con, str(project.iri), verbose)
|
|
57
|
+
|
|
58
|
+
if authenticated:
|
|
59
|
+
default_permissions, default_permissions_overrule = get_default_permissions(auth, str(project.iri), prefixes)
|
|
60
|
+
project_obj["default_permissions"] = default_permissions
|
|
61
|
+
if default_permissions_overrule:
|
|
62
|
+
project_obj["default_permissions_overrule"] = default_permissions_overrule
|
|
63
|
+
else:
|
|
64
|
+
project_obj["default_permissions"] = "Please provide credentials to retrieve the permissions of this project."
|
|
65
|
+
|
|
50
66
|
project_obj["groups"] = _get_groups(con, str(project.iri), verbose)
|
|
51
67
|
|
|
52
|
-
|
|
68
|
+
if users := _get_users(con, project, verbose):
|
|
69
|
+
project_obj["users"] = users
|
|
53
70
|
|
|
54
71
|
project_obj["lists"] = _get_lists(con, project, verbose)
|
|
55
72
|
|
|
56
|
-
prefixes, ontos = _get_ontologies(con, str(project.iri), verbose)
|
|
57
73
|
project_obj["ontologies"] = ontos
|
|
58
74
|
|
|
59
75
|
schema = "https://raw.githubusercontent.com/dasch-swiss/dsp-tools/main/src/dsp_tools/resources/schema/project.json"
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from typing import Literal
|
|
3
|
+
|
|
4
|
+
import regex
|
|
5
|
+
|
|
6
|
+
from dsp_tools.clients.authentication_client import AuthenticationClient
|
|
7
|
+
from dsp_tools.clients.permissions_client import PermissionsClient
|
|
8
|
+
from dsp_tools.commands.get.get_permissions_legacy import parse_legacy_doaps
|
|
9
|
+
from dsp_tools.commands.get.models.permissions_models import DoapCategories
|
|
10
|
+
from dsp_tools.error.exceptions import UnknownDOAPException
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_default_permissions(
|
|
14
|
+
auth: AuthenticationClient, project_iri: str, prefixes: dict[str, str]
|
|
15
|
+
) -> tuple[str, dict[str, list[str] | Literal["all"]] | None]:
|
|
16
|
+
"""
|
|
17
|
+
Retrieve the DOAPs of a project from the server,
|
|
18
|
+
and try to fit them into our system of "default_permissions" and "default_permissions_overrule".
|
|
19
|
+
If an anomaly is found, return an error message for "default_permissions",
|
|
20
|
+
and None for "default_permissions_overrule".
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
"default_permissions": "public" or "private" or error message
|
|
24
|
+
"default_permissions_overrule": {"private": [<classes_or_props>], "limited_view": ["all" or <img_classes>]}
|
|
25
|
+
"""
|
|
26
|
+
perm_client = PermissionsClient(auth, project_iri)
|
|
27
|
+
project_doaps = perm_client.get_project_doaps()
|
|
28
|
+
fallback_text = (
|
|
29
|
+
"We cannot determine if this project is public or private. "
|
|
30
|
+
"The DSP-TOOLS devs can assist you in analysing the existing DOAPs, "
|
|
31
|
+
"and help you decide if the original intent was rather public or rather private."
|
|
32
|
+
)
|
|
33
|
+
try:
|
|
34
|
+
default_permissions = _parse_default_permissions(project_doaps)
|
|
35
|
+
default_permissions_overrule = _parse_default_permissions_overrule(project_doaps, prefixes)
|
|
36
|
+
except UnknownDOAPException:
|
|
37
|
+
default_permissions = fallback_text
|
|
38
|
+
default_permissions_overrule = None
|
|
39
|
+
return default_permissions, default_permissions_overrule
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _parse_default_permissions(project_doaps: list[dict[str, Any]]) -> str:
|
|
43
|
+
"""
|
|
44
|
+
First tries to parse legacy DOAPs with multiple groups, then falls back to new-style parsing.
|
|
45
|
+
New-style parsing: If the DOAPs exactly match our definition of public/private, return public/private.
|
|
46
|
+
Otherwise, raise an exception.
|
|
47
|
+
"""
|
|
48
|
+
# First, try to parse legacy DOAPs (multiple groups: ProjectAdmin, ProjectMember)
|
|
49
|
+
if legacy_result := parse_legacy_doaps(project_doaps):
|
|
50
|
+
return legacy_result
|
|
51
|
+
|
|
52
|
+
# Fall back to new-style parsing (single ProjectMember group)
|
|
53
|
+
unsupported_groups = ("SystemAdmin", "ProjectAdmin", "Creator", "KnownUser", "UnknownUser")
|
|
54
|
+
if [x for x in project_doaps if x.get("forGroup", "").endswith(unsupported_groups)]:
|
|
55
|
+
raise UnknownDOAPException("The only supported target group for DOAPs is ProjectMember.")
|
|
56
|
+
proj_member_doaps = [x for x in project_doaps if x.get("forGroup", "").endswith("ProjectMember")]
|
|
57
|
+
if len(proj_member_doaps) != 1:
|
|
58
|
+
raise UnknownDOAPException("There must be exactly 1 DOAP for ProjectMember.")
|
|
59
|
+
perms = proj_member_doaps[0]["hasPermissions"]
|
|
60
|
+
if len(perms) not in [2, 4]:
|
|
61
|
+
err_msg = "The only allowed permissions are 'private' (with 2 elements), and 'limited_view' (with 4 elements)"
|
|
62
|
+
raise UnknownDOAPException(err_msg)
|
|
63
|
+
proj_adm_perms = [x for x in perms if x["additionalInformation"].endswith("ProjectAdmin")]
|
|
64
|
+
proj_mem_perms = [x for x in perms if x["additionalInformation"].endswith("ProjectMember")]
|
|
65
|
+
knwn_usr_perms = [x for x in perms if x["additionalInformation"].endswith("KnownUser")]
|
|
66
|
+
unkn_usr_perms = [x for x in perms if x["additionalInformation"].endswith("UnknownUser")]
|
|
67
|
+
if not (len(proj_adm_perms) == len(proj_mem_perms) == 1):
|
|
68
|
+
raise UnknownDOAPException("There must be always 1 permission for ProjectAdmin and 1 for ProjectMember")
|
|
69
|
+
if proj_adm_perms[0]["name"] != "CR" or proj_mem_perms[0]["name"] != "D":
|
|
70
|
+
raise UnknownDOAPException("ProjectAdmin must always have CR and ProjectMember must always have D")
|
|
71
|
+
if len(knwn_usr_perms) == len(unkn_usr_perms) == 0:
|
|
72
|
+
return "private"
|
|
73
|
+
if not (len(knwn_usr_perms) == len(unkn_usr_perms) == 1):
|
|
74
|
+
raise UnknownDOAPException("In case of 'limited_view', there must be 1 for KnownUser and 1 for UnknownUser")
|
|
75
|
+
if knwn_usr_perms[0]["name"] != "V" or unkn_usr_perms[0]["name"] != "V":
|
|
76
|
+
raise UnknownDOAPException("In case of 'public', KnownUser and UnknownUser must always have V")
|
|
77
|
+
return "public"
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _parse_default_permissions_overrule(
|
|
81
|
+
project_doaps: list[dict[str, Any]], prefixes: dict[str, str]
|
|
82
|
+
) -> dict[str, list[str] | Literal["all"]] | None:
|
|
83
|
+
"""
|
|
84
|
+
The DOAPs retrieved from the server are examined if they fit into our system of the overrules.
|
|
85
|
+
If yes, an overrule object is returned. Otherwise, an exception is raised.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
project_doaps: DOAPs as retrieved from the server
|
|
89
|
+
prefixes: dict in the form {"my-onto": "http://0.0.0.0:3333/ontology/1234/my-onto/v2"}
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
an overrule object that can be written into the JSON project definition file, in this form:
|
|
93
|
+
"default_permissions_overrule": {"private": [<classes_or_props>], "limited_view": ["all" or <img_classes>]}
|
|
94
|
+
|
|
95
|
+
Raises:
|
|
96
|
+
UnknownDOAPException: if there are DOAPs that do not fit into our system
|
|
97
|
+
"""
|
|
98
|
+
prefixes_knora_base_inverted = _convert_prefixes(prefixes)
|
|
99
|
+
doap_categories = _categorize_doaps(project_doaps)
|
|
100
|
+
_validate_doap_categories(doap_categories)
|
|
101
|
+
return _construct_overrule_object(doap_categories, prefixes_knora_base_inverted)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _convert_prefixes(prefixes: dict[str, str]) -> dict[str, str]:
|
|
105
|
+
"""
|
|
106
|
+
Convert knora-api form of prefixes into knora-base form (used by DOAPs), and invert it.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
prefixes: dict in the form of {"my-onto": "http://0.0.0.0:3333/ontology/1234/my-onto/v2"}
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
dict in the form of {"http://www.knora.org/ontology/1234/my-onto": "my-onto"}
|
|
113
|
+
"""
|
|
114
|
+
prefixes_knora_base_inverted = {}
|
|
115
|
+
for onto_shorthand, knora_api_iri in prefixes.items():
|
|
116
|
+
if match := regex.search(r"/ontology/([0-9A-Fa-f]{4})/([^/]+)/v2", knora_api_iri):
|
|
117
|
+
shortcode, onto_name = match.groups()
|
|
118
|
+
prefixes_knora_base_inverted[f"http://www.knora.org/ontology/{shortcode}/{onto_name}"] = onto_shorthand
|
|
119
|
+
return prefixes_knora_base_inverted
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _categorize_doaps(project_doaps: list[dict[str, Any]]) -> DoapCategories:
|
|
123
|
+
"""
|
|
124
|
+
The overrule object of the JSON project definition file has 2 categories: private and limited_view.
|
|
125
|
+
- "private" is a list of classes/properties that are private.
|
|
126
|
+
The DOAPs for these correspond 1:1 to the classes/properties.
|
|
127
|
+
- "limited_view" is
|
|
128
|
+
- a list of image classes that are limited_view:
|
|
129
|
+
The DOAPs for these are for knora-api:hasStillImageFileValue and the respective class.
|
|
130
|
+
- or the string "all". The DOAPs for these are only for knora-api:hasStillImageFileValue.
|
|
131
|
+
|
|
132
|
+
This function groups the DOAPs into these categories.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
project_doaps: the DOAPs as retrieved from the server
|
|
136
|
+
|
|
137
|
+
Raises:
|
|
138
|
+
UnknownDOAPException: if there are DOAPs that do not fit into our system
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
a DTO with the categories
|
|
142
|
+
"""
|
|
143
|
+
class_doaps = []
|
|
144
|
+
prop_doaps = []
|
|
145
|
+
has_img_all_classes_doaps = []
|
|
146
|
+
has_img_specific_class_doaps = []
|
|
147
|
+
other_doaps = []
|
|
148
|
+
for doap in project_doaps:
|
|
149
|
+
match (doap.get("forResourceClass"), doap.get("forProperty")):
|
|
150
|
+
case (for_class, None) if for_class:
|
|
151
|
+
class_doaps.append(doap)
|
|
152
|
+
case (None, for_prop) if for_prop and "hasStillImageFileValue" not in for_prop:
|
|
153
|
+
prop_doaps.append(doap)
|
|
154
|
+
case (None, for_prop) if for_prop and "hasStillImageFileValue" in for_prop:
|
|
155
|
+
has_img_all_classes_doaps.append(doap)
|
|
156
|
+
case (for_class, for_prop) if for_class and for_prop and "hasStillImageFileValue" in for_prop:
|
|
157
|
+
has_img_specific_class_doaps.append(doap)
|
|
158
|
+
case _:
|
|
159
|
+
other_doaps.append(doap)
|
|
160
|
+
# Only validate other_doaps if there are any
|
|
161
|
+
if other_doaps:
|
|
162
|
+
try:
|
|
163
|
+
_parse_default_permissions(other_doaps)
|
|
164
|
+
except UnknownDOAPException:
|
|
165
|
+
raise UnknownDOAPException("Found DOAPs that do not fit into our system") from None
|
|
166
|
+
return DoapCategories(
|
|
167
|
+
class_doaps=class_doaps,
|
|
168
|
+
prop_doaps=prop_doaps,
|
|
169
|
+
has_img_all_classes_doaps=has_img_all_classes_doaps,
|
|
170
|
+
has_img_specific_class_doaps=has_img_specific_class_doaps,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def _validate_doap_categories(doap_categories: DoapCategories) -> None:
|
|
175
|
+
for expected_private_doap in doap_categories.class_doaps + doap_categories.prop_doaps:
|
|
176
|
+
perm = sorted(expected_private_doap["hasPermissions"], key=lambda x: x["name"])
|
|
177
|
+
if len(perm) != 2:
|
|
178
|
+
raise UnknownDOAPException("'private' is defined as CR ProjectAdmin|D ProjectMember")
|
|
179
|
+
CR, D = perm
|
|
180
|
+
if CR["name"] != "CR" or not CR["additionalInformation"].endswith("ProjectAdmin"):
|
|
181
|
+
raise UnknownDOAPException("'private' is defined as CR ProjectAdmin|D ProjectMember")
|
|
182
|
+
if D["name"] != "D" or not D["additionalInformation"].endswith("ProjectMember"):
|
|
183
|
+
raise UnknownDOAPException("'private' is defined as CR ProjectAdmin|D ProjectMember")
|
|
184
|
+
|
|
185
|
+
for expected_limited_view in (
|
|
186
|
+
doap_categories.has_img_all_classes_doaps + doap_categories.has_img_specific_class_doaps
|
|
187
|
+
):
|
|
188
|
+
err_msg = "'limited_view' is defined as CR ProjectAdmin|D ProjectMember|RV KnownUser|RV UnknownUser"
|
|
189
|
+
perm = sorted(expected_limited_view["hasPermissions"], key=lambda x: x["name"])
|
|
190
|
+
if len(perm) != 4:
|
|
191
|
+
raise UnknownDOAPException(err_msg)
|
|
192
|
+
CR, D, RV1, RV2 = perm
|
|
193
|
+
if CR["name"] != "CR" or not CR["additionalInformation"].endswith("ProjectAdmin"):
|
|
194
|
+
raise UnknownDOAPException(err_msg)
|
|
195
|
+
if D["name"] != "D" or not D["additionalInformation"].endswith("ProjectMember"):
|
|
196
|
+
raise UnknownDOAPException(err_msg)
|
|
197
|
+
if RV1["name"] != "RV" or not RV2["additionalInformation"].endswith("nownUser"):
|
|
198
|
+
raise UnknownDOAPException(err_msg)
|
|
199
|
+
if RV2["name"] != "RV" or not RV2["additionalInformation"].endswith("nownUser"):
|
|
200
|
+
raise UnknownDOAPException(err_msg)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def _construct_overrule_object(
|
|
204
|
+
doap_categories: DoapCategories, prefixes_knora_base_inverted: dict[str, str]
|
|
205
|
+
) -> dict[str, list[str] | Literal["all"]]:
|
|
206
|
+
"""
|
|
207
|
+
Construct the final overrules object that can be written into the JSON project definition file.
|
|
208
|
+
To do so, the fully qualified IRIs of the classes/properties must be converted to prefixed IRIs.
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
doap_categories: The categorized DOAPs from the server
|
|
212
|
+
prefixes_knora_base_inverted: lookup from fully qualified IRIs to prefixed IRIs
|
|
213
|
+
|
|
214
|
+
Raises:
|
|
215
|
+
UnknownDOAPException: if the DOAPs do not fit into our system
|
|
216
|
+
|
|
217
|
+
Returns:
|
|
218
|
+
the final overrules object that can be written into the JSON project definition file
|
|
219
|
+
"""
|
|
220
|
+
privates: list[str] = []
|
|
221
|
+
for class_doap in doap_categories.class_doaps:
|
|
222
|
+
privates.append(_get_prefixed_iri(class_doap["forResourceClass"], prefixes_knora_base_inverted))
|
|
223
|
+
for prop_doap in doap_categories.prop_doaps:
|
|
224
|
+
privates.append(_get_prefixed_iri(prop_doap["forProperty"], prefixes_knora_base_inverted))
|
|
225
|
+
|
|
226
|
+
limited_views: list[str] | Literal["all"]
|
|
227
|
+
if len(doap_categories.has_img_all_classes_doaps) > 1:
|
|
228
|
+
raise UnknownDOAPException("There can only be 1 all-images DOAP for 'hasStillImageFileValue'")
|
|
229
|
+
if len(doap_categories.has_img_all_classes_doaps) == 1 and len(doap_categories.has_img_specific_class_doaps) > 0:
|
|
230
|
+
raise UnknownDOAPException("If there is a DOAP for all images, there cannot be DOAPs for specific img classes")
|
|
231
|
+
if len(doap_categories.has_img_all_classes_doaps) == 1:
|
|
232
|
+
limited_views = "all"
|
|
233
|
+
else:
|
|
234
|
+
limited_views = []
|
|
235
|
+
for img_doap in doap_categories.has_img_specific_class_doaps:
|
|
236
|
+
limited_views.append(_get_prefixed_iri(img_doap["forResourceClass"], prefixes_knora_base_inverted))
|
|
237
|
+
|
|
238
|
+
result: dict[str, list[str] | Literal["all"]] = {}
|
|
239
|
+
if privates:
|
|
240
|
+
result["private"] = privates
|
|
241
|
+
if limited_views:
|
|
242
|
+
result["limited_view"] = limited_views
|
|
243
|
+
return result
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def _get_prefixed_iri(full_iri: str, prefixes_inverted: dict[str, str]) -> str:
|
|
247
|
+
# example:
|
|
248
|
+
# - full_iri = "http://www.knora.org/ontology/1234/my-onto/v2#MyClass"
|
|
249
|
+
# - prefixes_inverted = {"http://www.knora.org/ontology/1234/my-onto": "my-onto"}
|
|
250
|
+
# - output = "my-onto:MyClass"
|
|
251
|
+
if "#" not in full_iri:
|
|
252
|
+
raise ValueError(f"{full_iri} is not a valid full IRI")
|
|
253
|
+
before_hashtag, after_hashtag = full_iri.rsplit("#", maxsplit=1)
|
|
254
|
+
if before_hashtag not in prefixes_inverted:
|
|
255
|
+
raise ValueError(f"{full_iri} belongs to an unknown ontology. It cannot be found in the prefixes.")
|
|
256
|
+
prefix = prefixes_inverted[before_hashtag]
|
|
257
|
+
return f"{prefix}:{after_hashtag}"
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from typing import Literal
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def parse_legacy_doaps(project_doaps: list[dict[str, Any]]) -> Literal["public", "private"] | None:
|
|
6
|
+
"""
|
|
7
|
+
Check if DOAPs match one of the legacy patterns.
|
|
8
|
+
|
|
9
|
+
Legacy private:
|
|
10
|
+
- For group ProjectAdmin: ProjectAdmin CR, ProjectMember CR/M
|
|
11
|
+
- For group ProjectMember: ProjectAdmin CR, ProjectMember CR/M
|
|
12
|
+
|
|
13
|
+
Legacy public:
|
|
14
|
+
- For group ProjectAdmin: ProjectAdmin CR, (optionally: Creator CR), ProjectMember D/M, KnownUser V, UnknownUser V
|
|
15
|
+
- For group ProjectMember: ProjectAdmin CR, (optionally: Creator CR), ProjectMember D/M, KnownUser V, UnknownUser V
|
|
16
|
+
"""
|
|
17
|
+
if len(project_doaps) != 2:
|
|
18
|
+
return None
|
|
19
|
+
admin_doaps = [x for x in project_doaps if x.get("forGroup", "").endswith("ProjectAdmin")]
|
|
20
|
+
member_doaps = [x for x in project_doaps if x.get("forGroup", "").endswith("ProjectMember")]
|
|
21
|
+
if len(admin_doaps) != 1 or len(member_doaps) != 1:
|
|
22
|
+
return None
|
|
23
|
+
|
|
24
|
+
admin_perms = admin_doaps[0]["hasPermissions"]
|
|
25
|
+
member_perms = member_doaps[0]["hasPermissions"]
|
|
26
|
+
if all([_is_legacy_private(admin_perms), _is_legacy_private(member_perms)]):
|
|
27
|
+
return "private"
|
|
28
|
+
if all([_is_legacy_public(admin_perms), _is_legacy_public(member_perms)]):
|
|
29
|
+
return "public"
|
|
30
|
+
|
|
31
|
+
return None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _is_legacy_private(perms: list[dict[str, Any]]) -> bool:
|
|
35
|
+
"""
|
|
36
|
+
Check if permissions match the legacy private pattern: ProjectAdmin CR, ProjectMember M/D
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
perms: List of permission objects
|
|
40
|
+
"""
|
|
41
|
+
if len(perms) != 2:
|
|
42
|
+
return False
|
|
43
|
+
|
|
44
|
+
sorted_perms = sorted(perms, key=lambda x: x.get("name", ""))
|
|
45
|
+
|
|
46
|
+
# First should be CR for ProjectAdmin
|
|
47
|
+
if sorted_perms[0]["name"] != "CR" or not sorted_perms[0]["additionalInformation"].endswith("ProjectAdmin"):
|
|
48
|
+
return False
|
|
49
|
+
|
|
50
|
+
# Second should be D or M for ProjectMember
|
|
51
|
+
if sorted_perms[1]["name"] not in ["D", "M"] or not sorted_perms[1]["additionalInformation"].endswith(
|
|
52
|
+
"ProjectMember"
|
|
53
|
+
):
|
|
54
|
+
return False
|
|
55
|
+
|
|
56
|
+
return True
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _is_legacy_public(perms: list[dict[str, Any]]) -> bool:
|
|
60
|
+
"""
|
|
61
|
+
Check if permissions match the public pattern:
|
|
62
|
+
ProjectAdmin CR, (optionally: Creator CR), ProjectMember D/M, KnownUser V, UnknownUser V
|
|
63
|
+
"""
|
|
64
|
+
# Should have exactly 4 permissions after filtering out Creator
|
|
65
|
+
filtered_perms = [p for p in perms if not p["additionalInformation"].endswith("Creator")]
|
|
66
|
+
if len(filtered_perms) != 4:
|
|
67
|
+
return False
|
|
68
|
+
|
|
69
|
+
sorted_perms = sorted(filtered_perms, key=lambda x: x.get("name", ""))
|
|
70
|
+
|
|
71
|
+
# First should be CR for ProjectAdmin
|
|
72
|
+
if sorted_perms[0]["name"] != "CR" or not sorted_perms[0]["additionalInformation"].endswith("ProjectAdmin"):
|
|
73
|
+
return False
|
|
74
|
+
|
|
75
|
+
# Second should be D or M for ProjectMember
|
|
76
|
+
if sorted_perms[1]["name"] not in ["D", "M"] or not sorted_perms[1]["additionalInformation"].endswith(
|
|
77
|
+
"ProjectMember"
|
|
78
|
+
):
|
|
79
|
+
return False
|
|
80
|
+
|
|
81
|
+
# Third/Fourth should be V for KnownUser
|
|
82
|
+
if sorted_perms[2]["name"] != "V" or not sorted_perms[2]["additionalInformation"].endswith("nownUser"):
|
|
83
|
+
return False
|
|
84
|
+
|
|
85
|
+
# Third/Fourth should be V for UnknownUser
|
|
86
|
+
if sorted_perms[3]["name"] != "V" or not sorted_perms[3]["additionalInformation"].endswith("nownUser"):
|
|
87
|
+
return False
|
|
88
|
+
|
|
89
|
+
return True
|
|
@@ -4,10 +4,10 @@ from typing import Optional
|
|
|
4
4
|
|
|
5
5
|
import regex
|
|
6
6
|
|
|
7
|
-
from dsp_tools.commands.
|
|
8
|
-
from dsp_tools.commands.
|
|
9
|
-
from dsp_tools.
|
|
10
|
-
from dsp_tools.utils.iri_util import is_iri
|
|
7
|
+
from dsp_tools.commands.get.legacy_models.helpers import ContextType
|
|
8
|
+
from dsp_tools.commands.get.legacy_models.helpers import OntoIri
|
|
9
|
+
from dsp_tools.error.exceptions import BaseError
|
|
10
|
+
from dsp_tools.utils.data_formats.iri_util import is_iri
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class ContextIterator:
|
|
@@ -15,7 +15,7 @@ class ContextIterator:
|
|
|
15
15
|
_prefixes: list[str]
|
|
16
16
|
_index: int
|
|
17
17
|
|
|
18
|
-
def __init__(self, context:
|
|
18
|
+
def __init__(self, context: Context):
|
|
19
19
|
self._context = context
|
|
20
20
|
self._prefixes = list(self._context.context)
|
|
21
21
|
self._index = 0
|
|
@@ -127,7 +127,7 @@ class Context:
|
|
|
127
127
|
:param value: Dictionary of context
|
|
128
128
|
:return: None
|
|
129
129
|
"""
|
|
130
|
-
if value is not None and isinstance(value,
|
|
130
|
+
if value is not None and isinstance(value, dict):
|
|
131
131
|
self._context = value
|
|
132
132
|
else:
|
|
133
133
|
raise BaseError("Error in parameter to context setter")
|
|
@@ -28,11 +28,11 @@ from typing import Optional
|
|
|
28
28
|
from typing import Union
|
|
29
29
|
from urllib.parse import quote_plus
|
|
30
30
|
|
|
31
|
-
from dsp_tools.
|
|
32
|
-
from dsp_tools.commands.
|
|
33
|
-
from dsp_tools.
|
|
34
|
-
from dsp_tools.
|
|
35
|
-
from dsp_tools.
|
|
31
|
+
from dsp_tools.clients.connection import Connection
|
|
32
|
+
from dsp_tools.commands.get.legacy_models.model import Model
|
|
33
|
+
from dsp_tools.commands.get.legacy_models.project import Project
|
|
34
|
+
from dsp_tools.error.exceptions import BaseError
|
|
35
|
+
from dsp_tools.legacy_models.langstring import LangString
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
class Group(Model):
|
|
@@ -68,7 +68,6 @@ class Group(Model):
|
|
|
68
68
|
|
|
69
69
|
PROJECT_MEMBER_GROUP: str = "http://www.knora.org/ontology/knora-admin#ProjectMember"
|
|
70
70
|
PROJECT_ADMIN_GROUP: str = "http://www.knora.org/ontology/knora-admin#ProjectAdmin"
|
|
71
|
-
PROJECT_SYSTEMADMIN_GROUP: str = "http://www.knora.org/ontology/knora-admin#SystemAdmin"
|
|
72
71
|
ROUTE: str = "/admin/groups"
|
|
73
72
|
ROUTE_SLASH: str = ROUTE + "/"
|
|
74
73
|
|
|
@@ -224,10 +223,6 @@ class Group(Model):
|
|
|
224
223
|
tmp["selfjoin"] = self._selfjoin
|
|
225
224
|
return tmp
|
|
226
225
|
|
|
227
|
-
def delete(self) -> Group:
|
|
228
|
-
result = self._con.delete(Group.ROUTE_SLASH + quote_plus(self._iri))
|
|
229
|
-
return Group.fromJsonObj(self._con, result["group"])
|
|
230
|
-
|
|
231
226
|
@staticmethod
|
|
232
227
|
def getAllGroups(con: Connection) -> list[Group]:
|
|
233
228
|
result = con.get(Group.ROUTE)
|
|
@@ -18,11 +18,11 @@ from typing import Optional
|
|
|
18
18
|
from typing import Union
|
|
19
19
|
from urllib.parse import quote_plus
|
|
20
20
|
|
|
21
|
-
from dsp_tools.
|
|
22
|
-
from dsp_tools.commands.
|
|
23
|
-
from dsp_tools.
|
|
24
|
-
from dsp_tools.
|
|
25
|
-
from dsp_tools.
|
|
21
|
+
from dsp_tools.clients.connection import Connection
|
|
22
|
+
from dsp_tools.commands.get.legacy_models.model import Model
|
|
23
|
+
from dsp_tools.commands.get.legacy_models.project import Project
|
|
24
|
+
from dsp_tools.error.exceptions import BaseError
|
|
25
|
+
from dsp_tools.legacy_models.langstring import LangString
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
class ListNode(Model):
|
|
@@ -301,36 +301,6 @@ class ListNode(Model):
|
|
|
301
301
|
rootNodeIri=rootNodeIri,
|
|
302
302
|
)
|
|
303
303
|
|
|
304
|
-
def create(self) -> ListNode:
|
|
305
|
-
"""
|
|
306
|
-
Create a new List
|
|
307
|
-
|
|
308
|
-
:return: JSON-object from DSP-API
|
|
309
|
-
"""
|
|
310
|
-
jsonobj = self._toJsonObj_create()
|
|
311
|
-
if self._parent:
|
|
312
|
-
result = self._con.post(ListNode.ROUTE_SLASH + quote_plus(self._parent), jsonobj)
|
|
313
|
-
return ListNode.fromJsonObj(self._con, result["nodeinfo"])
|
|
314
|
-
else:
|
|
315
|
-
result = self._con.post(ListNode.ROUTE, jsonobj)
|
|
316
|
-
return ListNode.fromJsonObj(self._con, result["list"]["listinfo"])
|
|
317
|
-
|
|
318
|
-
def _toJsonObj_create(self):
|
|
319
|
-
tmp = {}
|
|
320
|
-
if self._project is None:
|
|
321
|
-
raise BaseError("There must be a project id given!")
|
|
322
|
-
tmp["projectIri"] = self._project
|
|
323
|
-
if self._label.isEmpty():
|
|
324
|
-
raise BaseError("There must be a valid ListNode label!")
|
|
325
|
-
tmp["labels"] = self._label.toJsonObj()
|
|
326
|
-
if self._comments:
|
|
327
|
-
tmp["comments"] = self._comments.toJsonObj()
|
|
328
|
-
if self._name:
|
|
329
|
-
tmp["name"] = self._name
|
|
330
|
-
if self._parent:
|
|
331
|
-
tmp["parentNodeIri"] = self._parent
|
|
332
|
-
return tmp
|
|
333
|
-
|
|
334
304
|
def read(self) -> Any:
|
|
335
305
|
"""
|
|
336
306
|
Read a project from DSP-API
|
|
@@ -26,15 +26,15 @@ from urllib.parse import quote_plus
|
|
|
26
26
|
|
|
27
27
|
import regex
|
|
28
28
|
|
|
29
|
-
from dsp_tools.
|
|
30
|
-
from dsp_tools.commands.
|
|
31
|
-
from dsp_tools.commands.
|
|
32
|
-
from dsp_tools.commands.
|
|
33
|
-
from dsp_tools.commands.
|
|
34
|
-
from dsp_tools.commands.
|
|
35
|
-
from dsp_tools.
|
|
36
|
-
from dsp_tools.
|
|
37
|
-
from dsp_tools.
|
|
29
|
+
from dsp_tools.clients.connection import Connection
|
|
30
|
+
from dsp_tools.commands.get.legacy_models.context import Context
|
|
31
|
+
from dsp_tools.commands.get.legacy_models.helpers import WithId
|
|
32
|
+
from dsp_tools.commands.get.legacy_models.model import Model
|
|
33
|
+
from dsp_tools.commands.get.legacy_models.project import Project
|
|
34
|
+
from dsp_tools.commands.get.legacy_models.propertyclass import PropertyClass
|
|
35
|
+
from dsp_tools.commands.get.legacy_models.resourceclass import ResourceClass
|
|
36
|
+
from dsp_tools.error.exceptions import BaseError
|
|
37
|
+
from dsp_tools.legacy_models.datetimestamp import DateTimeStamp
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
class Ontology(Model):
|
|
@@ -287,11 +287,6 @@ class Ontology(Model):
|
|
|
287
287
|
result = self._con.get(Ontology.ROUTE + "/allentities/" + quote_plus(self._iri) + Ontology.ALL_LANGUAGES)
|
|
288
288
|
return Ontology.fromJsonObj(self._con, result)
|
|
289
289
|
|
|
290
|
-
@staticmethod
|
|
291
|
-
def getAllOntologies(con: Connection) -> list[Ontology]:
|
|
292
|
-
result = con.get(Ontology.ROUTE + Ontology.METADATA)
|
|
293
|
-
return Ontology.allOntologiesFromJsonObj(con, result)
|
|
294
|
-
|
|
295
290
|
@staticmethod
|
|
296
291
|
def getProjectOntologies(con: Connection, project_id: str) -> list[Ontology]:
|
|
297
292
|
if project_id is None:
|