dsp-tools 0.9.13__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 +5 -0
- dsp_tools/cli/args.py +47 -0
- dsp_tools/cli/call_action.py +85 -0
- 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 +479 -0
- dsp_tools/cli/entry_point.py +322 -0
- 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/clients/connection.py +35 -0
- 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 +321 -0
- dsp_tools/commands/excel2json/lists/__init__.py +0 -0
- dsp_tools/commands/excel2json/lists/compliance_checks.py +292 -0
- dsp_tools/commands/excel2json/lists/make_lists.py +247 -0
- dsp_tools/commands/excel2json/lists/models/__init__.py +0 -0
- dsp_tools/commands/excel2json/lists/models/deserialise.py +30 -0
- dsp_tools/commands/excel2json/lists/models/input_error.py +216 -0
- dsp_tools/commands/excel2json/lists/models/serialise.py +57 -0
- dsp_tools/commands/excel2json/lists/utils.py +81 -0
- dsp_tools/commands/excel2json/models/__init__.py +0 -0
- dsp_tools/commands/excel2json/models/input_error.py +416 -0
- dsp_tools/commands/excel2json/models/json_header.py +175 -0
- dsp_tools/commands/excel2json/models/list_node_name.py +16 -0
- dsp_tools/commands/excel2json/models/ontology.py +76 -0
- dsp_tools/commands/excel2json/old_lists.py +328 -0
- dsp_tools/commands/excel2json/project.py +280 -0
- dsp_tools/commands/excel2json/properties.py +370 -0
- dsp_tools/commands/excel2json/resources.py +336 -0
- dsp_tools/commands/excel2json/utils.py +352 -0
- dsp_tools/commands/excel2xml/__init__.py +7 -0
- dsp_tools/commands/excel2xml/excel2xml_cli.py +523 -0
- dsp_tools/commands/excel2xml/excel2xml_lib.py +1953 -0
- dsp_tools/commands/excel2xml/propertyelement.py +47 -0
- dsp_tools/commands/get/__init__.py +0 -0
- dsp_tools/commands/get/get.py +166 -0
- dsp_tools/commands/get/get_permissions.py +257 -0
- dsp_tools/commands/get/get_permissions_legacy.py +89 -0
- dsp_tools/commands/get/legacy_models/__init__.py +0 -0
- dsp_tools/commands/get/legacy_models/context.py +318 -0
- dsp_tools/commands/get/legacy_models/group.py +241 -0
- dsp_tools/commands/get/legacy_models/helpers.py +47 -0
- dsp_tools/commands/get/legacy_models/listnode.py +390 -0
- dsp_tools/commands/get/legacy_models/model.py +12 -0
- dsp_tools/commands/get/legacy_models/ontology.py +324 -0
- dsp_tools/commands/get/legacy_models/project.py +366 -0
- dsp_tools/commands/get/legacy_models/propertyclass.py +417 -0
- dsp_tools/commands/get/legacy_models/resourceclass.py +676 -0
- dsp_tools/commands/get/legacy_models/user.py +438 -0
- dsp_tools/commands/get/models/__init__.py +0 -0
- dsp_tools/commands/get/models/permissions_models.py +10 -0
- dsp_tools/commands/id2iri.py +258 -0
- dsp_tools/commands/ingest_xmlupload/__init__.py +0 -0
- dsp_tools/commands/ingest_xmlupload/bulk_ingest_client.py +178 -0
- dsp_tools/commands/ingest_xmlupload/create_resources/__init__.py +0 -0
- dsp_tools/commands/ingest_xmlupload/create_resources/apply_ingest_id.py +69 -0
- dsp_tools/commands/ingest_xmlupload/create_resources/upload_xml.py +166 -0
- dsp_tools/commands/ingest_xmlupload/create_resources/user_information.py +121 -0
- dsp_tools/commands/ingest_xmlupload/ingest_files/__init__.py +0 -0
- dsp_tools/commands/ingest_xmlupload/ingest_files/ingest_files.py +64 -0
- dsp_tools/commands/ingest_xmlupload/upload_files/__init__.py +0 -0
- dsp_tools/commands/ingest_xmlupload/upload_files/filechecker.py +20 -0
- dsp_tools/commands/ingest_xmlupload/upload_files/input_error.py +57 -0
- dsp_tools/commands/ingest_xmlupload/upload_files/upload_failures.py +66 -0
- dsp_tools/commands/ingest_xmlupload/upload_files/upload_files.py +67 -0
- dsp_tools/commands/resume_xmlupload/__init__.py +0 -0
- dsp_tools/commands/resume_xmlupload/resume_xmlupload.py +96 -0
- dsp_tools/commands/start_stack.py +428 -0
- 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/validate_data/sparql/cardinality_shacl.py +209 -0
- 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/__init__.py +0 -0
- dsp_tools/commands/xmlupload/iri_resolver.py +21 -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/__init__.py +0 -0
- dsp_tools/commands/xmlupload/models/bitstream_info.py +18 -0
- dsp_tools/commands/xmlupload/models/formatted_text_value.py +10 -0
- dsp_tools/commands/xmlupload/models/ingest.py +143 -0
- dsp_tools/commands/xmlupload/models/input_problems.py +58 -0
- dsp_tools/commands/xmlupload/models/lookup_models.py +21 -0
- dsp_tools/commands/xmlupload/models/permission.py +45 -0
- dsp_tools/commands/xmlupload/models/permissions_parsed.py +93 -0
- 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 +14 -0
- dsp_tools/commands/xmlupload/models/upload_state.py +20 -0
- dsp_tools/commands/xmlupload/prepare_xml_input/__init__.py +0 -0
- dsp_tools/commands/xmlupload/prepare_xml_input/ark2iri.py +55 -0
- dsp_tools/commands/xmlupload/prepare_xml_input/get_processed_resources.py +252 -0
- dsp_tools/commands/xmlupload/prepare_xml_input/iiif_uri_validator.py +50 -0
- dsp_tools/commands/xmlupload/prepare_xml_input/list_client.py +120 -0
- 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 +25 -0
- dsp_tools/commands/xmlupload/richtext_id2iri.py +37 -0
- dsp_tools/commands/xmlupload/stash/__init__.py +0 -0
- dsp_tools/commands/xmlupload/stash/analyse_circular_reference_graph.py +236 -0
- dsp_tools/commands/xmlupload/stash/create_info_for_graph.py +53 -0
- dsp_tools/commands/xmlupload/stash/graph_models.py +87 -0
- dsp_tools/commands/xmlupload/stash/stash_circular_references.py +68 -0
- dsp_tools/commands/xmlupload/stash/stash_models.py +109 -0
- dsp_tools/commands/xmlupload/stash/upload_stashed_resptr_props.py +106 -0
- dsp_tools/commands/xmlupload/stash/upload_stashed_xml_texts.py +196 -0
- dsp_tools/commands/xmlupload/upload_config.py +76 -0
- dsp_tools/commands/xmlupload/write_diagnostic_info.py +27 -0
- dsp_tools/commands/xmlupload/xmlupload.py +516 -0
- dsp_tools/config/__init__.py +0 -0
- dsp_tools/config/logger_config.py +69 -0
- dsp_tools/config/warnings_config.py +32 -0
- 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/legacy_models/datetimestamp.py +81 -0
- dsp_tools/legacy_models/langstring.py +253 -0
- dsp_tools/legacy_models/projectContext.py +49 -0
- dsp_tools/py.typed +0 -0
- dsp_tools/resources/schema/data.xsd +648 -0
- dsp_tools/resources/schema/lists-only.json +72 -0
- dsp_tools/resources/schema/project.json +1258 -0
- dsp_tools/resources/schema/properties-only.json +874 -0
- dsp_tools/resources/schema/resources-only.json +140 -0
- dsp_tools/resources/start-stack/docker-compose.override-host.j2 +11 -0
- dsp_tools/resources/start-stack/docker-compose.override.yml +11 -0
- dsp_tools/resources/start-stack/docker-compose.yml +88 -0
- 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/__init__.py +0 -0
- dsp_tools/utils/ansi_colors.py +32 -0
- dsp_tools/utils/data_formats/__init__.py +0 -0
- dsp_tools/utils/data_formats/date_util.py +166 -0
- dsp_tools/utils/data_formats/iri_util.py +30 -0
- dsp_tools/utils/data_formats/shared.py +81 -0
- dsp_tools/utils/data_formats/uri_util.py +76 -0
- 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/__init__.py +0 -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 +1542 -0
- 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/internal/migration_metadata.py +55 -0
- 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 +348 -0
- dsp_tools/xmllib/value_checkers.py +434 -0
- dsp_tools/xmllib/value_converters.py +777 -0
- 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-18.3.0.post13.dist-info/entry_points.txt +3 -0
- dsp_tools-0.9.13.dist-info/LICENSE +0 -674
- dsp_tools-0.9.13.dist-info/METADATA +0 -144
- dsp_tools-0.9.13.dist-info/RECORD +0 -71
- dsp_tools-0.9.13.dist-info/WHEEL +0 -5
- dsp_tools-0.9.13.dist-info/entry_points.txt +0 -3
- dsp_tools-0.9.13.dist-info/top_level.txt +0 -1
- dsplib/models/connection.py +0 -272
- dsplib/models/group.py +0 -296
- dsplib/models/helpers.py +0 -505
- dsplib/models/langstring.py +0 -277
- dsplib/models/listnode.py +0 -578
- dsplib/models/model.py +0 -20
- dsplib/models/ontology.py +0 -448
- dsplib/models/permission.py +0 -112
- dsplib/models/project.py +0 -547
- dsplib/models/propertyclass.py +0 -505
- dsplib/models/resource.py +0 -366
- dsplib/models/resourceclass.py +0 -810
- dsplib/models/sipi.py +0 -30
- dsplib/models/user.py +0 -731
- dsplib/models/value.py +0 -1000
- dsplib/utils/knora-data-schema.xsd +0 -454
- dsplib/utils/knora-schema-lists.json +0 -83
- dsplib/utils/knora-schema.json +0 -434
- dsplib/utils/onto_commons.py +0 -24
- dsplib/utils/onto_create_lists.py +0 -73
- dsplib/utils/onto_create_ontology.py +0 -442
- dsplib/utils/onto_get.py +0 -58
- dsplib/utils/onto_validate.py +0 -33
- dsplib/utils/xml_upload.py +0 -539
- dsplib/widgets/doublepassword.py +0 -80
- knora/MLS-import-libraries.py +0 -84
- knora/dsp_tools.py +0 -96
- knora/dsplib/models/connection.py +0 -272
- knora/dsplib/models/group.py +0 -296
- knora/dsplib/models/helpers.py +0 -506
- knora/dsplib/models/langstring.py +0 -277
- knora/dsplib/models/listnode.py +0 -578
- knora/dsplib/models/model.py +0 -20
- knora/dsplib/models/ontology.py +0 -448
- knora/dsplib/models/permission.py +0 -112
- knora/dsplib/models/project.py +0 -583
- knora/dsplib/models/propertyclass.py +0 -505
- knora/dsplib/models/resource.py +0 -416
- knora/dsplib/models/resourceclass.py +0 -811
- knora/dsplib/models/sipi.py +0 -35
- knora/dsplib/models/user.py +0 -731
- knora/dsplib/models/value.py +0 -1000
- knora/dsplib/utils/knora-data-schema.xsd +0 -464
- knora/dsplib/utils/knora-schema-lists.json +0 -83
- knora/dsplib/utils/knora-schema.json +0 -444
- knora/dsplib/utils/onto_commons.py +0 -24
- knora/dsplib/utils/onto_create_lists.py +0 -73
- knora/dsplib/utils/onto_create_ontology.py +0 -451
- knora/dsplib/utils/onto_get.py +0 -58
- knora/dsplib/utils/onto_validate.py +0 -33
- knora/dsplib/utils/xml_upload.py +0 -540
- knora/dsplib/widgets/doublepassword.py +0 -80
- knora/knora.py +0 -2108
- knora/test.py +0 -99
- knora/testit.py +0 -76
- knora/xml2knora.py +0 -633
- {dsplib → dsp_tools/cli}/__init__.py +0 -0
- {dsplib/models → dsp_tools/clients}/__init__.py +0 -0
- {dsplib/utils → dsp_tools/commands}/__init__.py +0 -0
- {dsplib/widgets → dsp_tools/commands/create}/__init__.py +0 -0
- {knora → dsp_tools/commands/create/create_on_server}/__init__.py +0 -0
- {knora/dsplib → dsp_tools/commands/create/models}/__init__.py +0 -0
- {knora/dsplib/models → dsp_tools/commands/create/parsing}/__init__.py +0 -0
- {knora/dsplib/utils → dsp_tools/commands/create/serialisation}/__init__.py +0 -0
- {knora/dsplib/widgets → dsp_tools/commands/excel2json}/__init__.py +0 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
from loguru import logger
|
|
2
|
+
|
|
3
|
+
from dsp_tools.clients.permissions_client import PermissionsClient
|
|
4
|
+
from dsp_tools.utils.ansi_colors import BOLD
|
|
5
|
+
from dsp_tools.utils.ansi_colors import RESET_TO_DEFAULT
|
|
6
|
+
from dsp_tools.utils.rdf_constants import KNORA_ADMIN_PREFIX
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def create_default_permissions(
|
|
10
|
+
perm_client: PermissionsClient,
|
|
11
|
+
default_permissions: str,
|
|
12
|
+
default_permissions_overrule: dict[str, str | list[str]] | None,
|
|
13
|
+
shortcode: str,
|
|
14
|
+
) -> bool:
|
|
15
|
+
print(BOLD + "Processing default permissions:" + RESET_TO_DEFAULT)
|
|
16
|
+
logger.info("Processing default permissions:")
|
|
17
|
+
if not _delete_existing_doaps(perm_client):
|
|
18
|
+
print(" WARNING: Cannot delete the existing default permissions")
|
|
19
|
+
logger.warning("Cannot delete the existing default permissions")
|
|
20
|
+
return False
|
|
21
|
+
if not _create_new_doap(perm_client, default_permissions):
|
|
22
|
+
print(" WARNING: Cannot create default permissions")
|
|
23
|
+
logger.warning("Cannot create default permissions")
|
|
24
|
+
return False
|
|
25
|
+
if default_permissions_overrule:
|
|
26
|
+
if not _create_overrules(perm_client, default_permissions_overrule, shortcode):
|
|
27
|
+
print(" WARNING: Cannot create default permissions overrules")
|
|
28
|
+
logger.warning("Cannot create default permissions overrules")
|
|
29
|
+
return False
|
|
30
|
+
print(" Default permissions have been set")
|
|
31
|
+
logger.info("Default permissions have been set")
|
|
32
|
+
return True
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _delete_existing_doaps(perm_client: PermissionsClient) -> bool:
|
|
36
|
+
if not (doaps := perm_client.get_project_doaps()):
|
|
37
|
+
return False
|
|
38
|
+
existing_doap_iris: list[str] = [x["iri"] for x in doaps]
|
|
39
|
+
for iri in existing_doap_iris:
|
|
40
|
+
if not perm_client.delete_doap(iri):
|
|
41
|
+
# don't continue with the others, it's better to stop DOAP handling immediately, to avoid a mess
|
|
42
|
+
return False
|
|
43
|
+
return True
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _create_new_doap(perm_client: PermissionsClient, default_permissions: str) -> bool:
|
|
47
|
+
perm = [
|
|
48
|
+
{"additionalInformation": f"{KNORA_ADMIN_PREFIX}ProjectAdmin", "name": "CR", "permissionCode": None},
|
|
49
|
+
{"additionalInformation": f"{KNORA_ADMIN_PREFIX}ProjectMember", "name": "D", "permissionCode": None},
|
|
50
|
+
]
|
|
51
|
+
if default_permissions == "public":
|
|
52
|
+
perm.append({"additionalInformation": f"{KNORA_ADMIN_PREFIX}KnownUser", "name": "V", "permissionCode": None})
|
|
53
|
+
perm.append({"additionalInformation": f"{KNORA_ADMIN_PREFIX}UnknownUser", "name": "V", "permissionCode": None})
|
|
54
|
+
payload = {
|
|
55
|
+
"forGroup": f"{KNORA_ADMIN_PREFIX}ProjectMember",
|
|
56
|
+
"forProject": perm_client.proj_iri,
|
|
57
|
+
"hasPermissions": perm,
|
|
58
|
+
}
|
|
59
|
+
return perm_client.create_new_doap(payload)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _create_overrules(
|
|
63
|
+
perm_client: PermissionsClient, default_permissions_overrule: dict[str, str | list[str]], shortcode: str
|
|
64
|
+
) -> bool:
|
|
65
|
+
overall_success = True
|
|
66
|
+
|
|
67
|
+
# Handle private overrules
|
|
68
|
+
for entity in default_permissions_overrule.get("private", []):
|
|
69
|
+
first_letter = entity.split(":")[-1][0]
|
|
70
|
+
is_res = first_letter.upper() == first_letter
|
|
71
|
+
entity_iri = _get_iri_from_prefixed_name(entity, shortcode, perm_client.auth.server)
|
|
72
|
+
if is_res:
|
|
73
|
+
success = _create_one_private_overrule(perm_client=perm_client, res_iri=entity_iri, prop_iri=None)
|
|
74
|
+
else:
|
|
75
|
+
success = _create_one_private_overrule(perm_client=perm_client, res_iri=None, prop_iri=entity_iri)
|
|
76
|
+
if not success:
|
|
77
|
+
overall_success = False
|
|
78
|
+
|
|
79
|
+
# Handle limited_view overrules
|
|
80
|
+
if not (limited_view := default_permissions_overrule.get("limited_view")):
|
|
81
|
+
return overall_success
|
|
82
|
+
if limited_view == "all":
|
|
83
|
+
success = _create_one_limited_view_overrule(perm_client=perm_client, img_class_iri=None)
|
|
84
|
+
if not success:
|
|
85
|
+
overall_success = False
|
|
86
|
+
else:
|
|
87
|
+
# limited_view is a list of prefixed class names
|
|
88
|
+
for prefixed_img_class in limited_view:
|
|
89
|
+
img_class_iri = _get_iri_from_prefixed_name(prefixed_img_class, shortcode, perm_client.auth.server)
|
|
90
|
+
success = _create_one_limited_view_overrule(perm_client=perm_client, img_class_iri=img_class_iri)
|
|
91
|
+
if not success:
|
|
92
|
+
overall_success = False
|
|
93
|
+
|
|
94
|
+
return overall_success
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _create_one_private_overrule(perm_client: PermissionsClient, res_iri: str | None, prop_iri: str | None) -> bool:
|
|
98
|
+
perm = [
|
|
99
|
+
{"additionalInformation": f"{KNORA_ADMIN_PREFIX}ProjectAdmin", "name": "CR", "permissionCode": None},
|
|
100
|
+
{"additionalInformation": f"{KNORA_ADMIN_PREFIX}ProjectMember", "name": "D", "permissionCode": None},
|
|
101
|
+
]
|
|
102
|
+
payload = {
|
|
103
|
+
"forProperty": prop_iri,
|
|
104
|
+
"forResourceClass": res_iri,
|
|
105
|
+
"forProject": perm_client.proj_iri,
|
|
106
|
+
"hasPermissions": perm,
|
|
107
|
+
}
|
|
108
|
+
return perm_client.create_new_doap(payload)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _create_one_limited_view_overrule(perm_client: PermissionsClient, img_class_iri: str | None) -> bool:
|
|
112
|
+
# This makes only sense for the knora-api:hasStillImageFileValue property of image classes
|
|
113
|
+
# To set it for all image classes, set img_class_iri to None
|
|
114
|
+
perm = [
|
|
115
|
+
{"additionalInformation": f"{KNORA_ADMIN_PREFIX}ProjectAdmin", "name": "CR", "permissionCode": None},
|
|
116
|
+
{"additionalInformation": f"{KNORA_ADMIN_PREFIX}ProjectMember", "name": "D", "permissionCode": None},
|
|
117
|
+
{"additionalInformation": f"{KNORA_ADMIN_PREFIX}KnownUser", "name": "RV", "permissionCode": None},
|
|
118
|
+
{"additionalInformation": f"{KNORA_ADMIN_PREFIX}UnknownUser", "name": "RV", "permissionCode": None},
|
|
119
|
+
]
|
|
120
|
+
payload = {
|
|
121
|
+
"forProperty": "http://api.knora.org/ontology/knora-api/v2#hasStillImageFileValue",
|
|
122
|
+
"forResourceClass": img_class_iri,
|
|
123
|
+
"forProject": perm_client.proj_iri,
|
|
124
|
+
"hasPermissions": perm,
|
|
125
|
+
}
|
|
126
|
+
return perm_client.create_new_doap(payload)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _get_iri_from_prefixed_name(prefixed_name: str, proj_shortcode: str, server: str) -> str:
|
|
130
|
+
onto, name = prefixed_name.split(":")
|
|
131
|
+
host_iri = server.replace("https://", "http://")
|
|
132
|
+
if onto == "knora-api":
|
|
133
|
+
return f"http://api.knora.org/ontology/knora-api/v2#{name}"
|
|
134
|
+
return f"{host_iri}/ontology/{proj_shortcode}/{onto}/v2#{name}"
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from loguru import logger
|
|
4
|
+
from tqdm import tqdm
|
|
5
|
+
|
|
6
|
+
from dsp_tools.clients.authentication_client import AuthenticationClient
|
|
7
|
+
from dsp_tools.clients.group_user_clients import GroupClient
|
|
8
|
+
from dsp_tools.clients.group_user_clients import UserClient
|
|
9
|
+
from dsp_tools.clients.group_user_clients_live import UserClientLive
|
|
10
|
+
from dsp_tools.commands.create.models.create_problems import CollectedProblems
|
|
11
|
+
from dsp_tools.commands.create.models.create_problems import CreateProblem
|
|
12
|
+
from dsp_tools.commands.create.models.create_problems import UploadProblem
|
|
13
|
+
from dsp_tools.commands.create.models.create_problems import UploadProblemType
|
|
14
|
+
from dsp_tools.commands.create.models.parsed_project import ParsedGroup
|
|
15
|
+
from dsp_tools.commands.create.models.parsed_project import ParsedUser
|
|
16
|
+
from dsp_tools.commands.create.models.parsed_project import ParsedUserMemberShipInfo
|
|
17
|
+
from dsp_tools.commands.create.models.server_project_info import GroupNameToIriLookup
|
|
18
|
+
from dsp_tools.commands.create.models.server_project_info import UserNameToIriLookup
|
|
19
|
+
from dsp_tools.commands.create.serialisation.project import serialise_one_group
|
|
20
|
+
from dsp_tools.commands.create.serialisation.project import serialise_one_user_for_creation
|
|
21
|
+
from dsp_tools.utils.ansi_colors import BOLD
|
|
22
|
+
from dsp_tools.utils.ansi_colors import RESET_TO_DEFAULT
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def create_users(
|
|
26
|
+
users: list[ParsedUser],
|
|
27
|
+
user_memberships: list[ParsedUserMemberShipInfo],
|
|
28
|
+
group_lookup: GroupNameToIriLookup,
|
|
29
|
+
auth: AuthenticationClient,
|
|
30
|
+
project_iri: str,
|
|
31
|
+
) -> CollectedProblems | None:
|
|
32
|
+
print(BOLD + "Processing user section:" + RESET_TO_DEFAULT)
|
|
33
|
+
client = UserClientLive(auth.server, auth)
|
|
34
|
+
user_to_iri, problems = _create_all_users(users, client)
|
|
35
|
+
membership_problems = _add_all_memberships(user_memberships, user_to_iri, group_lookup, client, project_iri)
|
|
36
|
+
problems.extend(membership_problems)
|
|
37
|
+
if problems:
|
|
38
|
+
return CollectedProblems("During the creation of the users the following problems occurred:", problems)
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _create_all_users(users: list[ParsedUser], client: UserClient) -> tuple[UserNameToIriLookup, list[CreateProblem]]:
|
|
43
|
+
problems: list[CreateProblem] = []
|
|
44
|
+
user_to_iri = UserNameToIriLookup()
|
|
45
|
+
progress_bar = tqdm(users, desc=" Creating users", dynamic_ncols=True)
|
|
46
|
+
logger.debug("Creating users")
|
|
47
|
+
for usr in progress_bar:
|
|
48
|
+
result = _create_one_user(usr, client)
|
|
49
|
+
if result is None:
|
|
50
|
+
problems.append(UploadProblem(usr.username, UploadProblemType.USER_COULD_NOT_BE_CREATED))
|
|
51
|
+
else:
|
|
52
|
+
user_to_iri.add_iri(usr.username, result)
|
|
53
|
+
return user_to_iri, problems
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _create_one_user(user: ParsedUser, client: UserClient) -> str | None:
|
|
57
|
+
if user_iri := client.get_user_iri_by_username(user.username):
|
|
58
|
+
return user_iri
|
|
59
|
+
serialised_user = serialise_one_user_for_creation(user)
|
|
60
|
+
return client.post_new_user(serialised_user)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _add_all_memberships(
|
|
64
|
+
memberships: list[ParsedUserMemberShipInfo],
|
|
65
|
+
user_to_iri: UserNameToIriLookup,
|
|
66
|
+
group_lookup: GroupNameToIriLookup,
|
|
67
|
+
client: UserClient,
|
|
68
|
+
project_iri: str,
|
|
69
|
+
) -> list[CreateProblem]:
|
|
70
|
+
problems: list[CreateProblem] = []
|
|
71
|
+
progress_bar = tqdm(memberships, desc=" Updating user information", dynamic_ncols=True)
|
|
72
|
+
logger.debug("Updating user information")
|
|
73
|
+
for memb in progress_bar:
|
|
74
|
+
if usr_iri := user_to_iri.get_iri(memb.username):
|
|
75
|
+
result = _add_user_to_project_memberships(memb, usr_iri, project_iri, client)
|
|
76
|
+
problems.extend(result)
|
|
77
|
+
if memb.groups:
|
|
78
|
+
result = _add_user_to_custom_groups(memb, usr_iri, client, group_lookup)
|
|
79
|
+
problems.extend(result)
|
|
80
|
+
else:
|
|
81
|
+
logger.debug(f"IRI of user '{memb.username}' could not be found, no project membership added.")
|
|
82
|
+
return problems
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _add_user_to_project_memberships(
|
|
86
|
+
membership: ParsedUserMemberShipInfo, user_iri: str, project_iri: str, client: UserClient
|
|
87
|
+
) -> list[CreateProblem]:
|
|
88
|
+
problems: list[CreateProblem] = []
|
|
89
|
+
membership_good = client.add_user_as_project_member(user_iri, project_iri)
|
|
90
|
+
if not membership_good:
|
|
91
|
+
problems.append(UploadProblem(membership.username, UploadProblemType.PROJECT_MEMBERSHIP_COULD_NOT_BE_ADDED))
|
|
92
|
+
if membership.is_admin:
|
|
93
|
+
good = client.add_user_as_project_admin(user_iri, project_iri)
|
|
94
|
+
if not good:
|
|
95
|
+
problems.append(UploadProblem(membership.username, UploadProblemType.PROJECT_ADMIN_COULD_NOT_BE_ADDED))
|
|
96
|
+
return problems
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _add_user_to_custom_groups(
|
|
100
|
+
membership: ParsedUserMemberShipInfo, user_iri: str, client: UserClient, group_lookup: GroupNameToIriLookup
|
|
101
|
+
) -> list[CreateProblem]:
|
|
102
|
+
problems: list[CreateProblem] = []
|
|
103
|
+
groups_not_found = []
|
|
104
|
+
groups_iris = []
|
|
105
|
+
for gr in membership.groups:
|
|
106
|
+
if found := group_lookup.get_iri(gr):
|
|
107
|
+
groups_iris.append(found)
|
|
108
|
+
else:
|
|
109
|
+
groups_not_found.append(gr)
|
|
110
|
+
if groups_iris:
|
|
111
|
+
group_good = client.add_user_to_custom_groups(user_iri, groups_iris)
|
|
112
|
+
if not group_good:
|
|
113
|
+
problems.append(UploadProblem(membership.username, UploadProblemType.USER_COULD_NOT_BE_ADDED_TO_GROUP))
|
|
114
|
+
if groups_not_found:
|
|
115
|
+
problems.append(UploadProblem(membership.username, UploadProblemType.USER_GROUPS_NOT_FOUND))
|
|
116
|
+
return problems
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def create_groups(
|
|
120
|
+
groups: list[ParsedGroup],
|
|
121
|
+
group_client: GroupClient,
|
|
122
|
+
project_iri: str,
|
|
123
|
+
group_lookup: GroupNameToIriLookup,
|
|
124
|
+
) -> tuple[GroupNameToIriLookup, CollectedProblems | None]:
|
|
125
|
+
problems: list[CreateProblem] = []
|
|
126
|
+
print(BOLD + "Processing group section:" + RESET_TO_DEFAULT)
|
|
127
|
+
progress_bar = tqdm(groups, desc=" Creating groups", dynamic_ncols=True)
|
|
128
|
+
logger.debug("Creating groups")
|
|
129
|
+
for gr in progress_bar:
|
|
130
|
+
if group_lookup.check_exists(gr.name):
|
|
131
|
+
logger.debug(f"Group with the name '{gr.name}' already exists, skipping.")
|
|
132
|
+
continue
|
|
133
|
+
result = _create_one_group(gr, group_client, project_iri)
|
|
134
|
+
if isinstance(result, UploadProblem):
|
|
135
|
+
problems.append(result)
|
|
136
|
+
else:
|
|
137
|
+
group_lookup.add_iri(gr.name, result)
|
|
138
|
+
all_problems = None
|
|
139
|
+
if problems:
|
|
140
|
+
all_problems = CollectedProblems("During the creation of the groups the following problems happened:", problems)
|
|
141
|
+
return group_lookup, all_problems
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _create_one_group(group: ParsedGroup, group_client: GroupClient, project_iri: str) -> str | UploadProblem:
|
|
145
|
+
serialised = serialise_one_group(group, project_iri)
|
|
146
|
+
new_iri = group_client.create_new_group(serialised)
|
|
147
|
+
if new_iri:
|
|
148
|
+
return new_iri
|
|
149
|
+
return UploadProblem(group.name, UploadProblemType.GROUP_COULD_NOT_BE_CREATED)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def get_existing_group_to_iri_lookup(
|
|
153
|
+
group_client: GroupClient, project_iri: str, shortname: str
|
|
154
|
+
) -> GroupNameToIriLookup:
|
|
155
|
+
all_groups = group_client.get_all_groups()
|
|
156
|
+
return _construct_group_lookup(all_groups, project_iri, shortname)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _construct_group_lookup(all_groups: list[dict[str, Any]], project_iri: str, shortname: str) -> GroupNameToIriLookup:
|
|
160
|
+
lookup = GroupNameToIriLookup({}, shortname)
|
|
161
|
+
for group in all_groups:
|
|
162
|
+
group_project_iri = group["project"]["id"]
|
|
163
|
+
if group_project_iri == project_iri:
|
|
164
|
+
lookup.add_iri(group["name"], group["id"])
|
|
165
|
+
return lookup
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from loguru import logger
|
|
5
|
+
from tqdm import tqdm
|
|
6
|
+
|
|
7
|
+
from dsp_tools.clients.authentication_client import AuthenticationClient
|
|
8
|
+
from dsp_tools.clients.list_client import ListCreateClient
|
|
9
|
+
from dsp_tools.clients.list_client_live import ListCreateClientLive
|
|
10
|
+
from dsp_tools.clients.list_client_live import ListGetClientLive
|
|
11
|
+
from dsp_tools.commands.create.models.create_problems import CollectedProblems
|
|
12
|
+
from dsp_tools.commands.create.models.create_problems import CreateProblem
|
|
13
|
+
from dsp_tools.commands.create.models.create_problems import UploadProblem
|
|
14
|
+
from dsp_tools.commands.create.models.create_problems import UploadProblemType
|
|
15
|
+
from dsp_tools.commands.create.models.create_problems import UserInformation
|
|
16
|
+
from dsp_tools.commands.create.models.create_problems import UserInformationMessage
|
|
17
|
+
from dsp_tools.commands.create.models.parsed_project import ParsedList
|
|
18
|
+
from dsp_tools.commands.create.models.parsed_project import ParsedListNode
|
|
19
|
+
from dsp_tools.commands.create.models.parsed_project import ParsedNodeInfo
|
|
20
|
+
from dsp_tools.commands.create.models.server_project_info import ListNameToIriLookup
|
|
21
|
+
from dsp_tools.error.custom_warnings import DspToolsUnexpectedStatusCodeWarning
|
|
22
|
+
from dsp_tools.error.exceptions import FatalNonOkApiResponseCode
|
|
23
|
+
from dsp_tools.utils.ansi_colors import BOLD
|
|
24
|
+
from dsp_tools.utils.ansi_colors import BOLD_CYAN
|
|
25
|
+
from dsp_tools.utils.ansi_colors import RESET_TO_DEFAULT
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def create_lists(
|
|
29
|
+
parsed_lists: list[ParsedList], shortcode: str, auth: AuthenticationClient, project_iri: str
|
|
30
|
+
) -> tuple[ListNameToIriLookup, CollectedProblems | None]:
|
|
31
|
+
print(BOLD + "Processing list section:" + RESET_TO_DEFAULT)
|
|
32
|
+
name2iri = get_existing_lists_on_server(shortcode, auth)
|
|
33
|
+
if not parsed_lists:
|
|
34
|
+
return name2iri, None
|
|
35
|
+
lists_to_create, existing_info = _filter_out_existing_lists(parsed_lists, name2iri)
|
|
36
|
+
if existing_info:
|
|
37
|
+
_print_existing_list_info(existing_info)
|
|
38
|
+
if not lists_to_create:
|
|
39
|
+
msg = " All lists defined in the project are already on the server, no list was uploaded."
|
|
40
|
+
logger.warning(msg)
|
|
41
|
+
print(BOLD_CYAN + msg + RESET_TO_DEFAULT)
|
|
42
|
+
return name2iri, None
|
|
43
|
+
|
|
44
|
+
create_client = ListCreateClientLive(auth.server, auth, project_iri)
|
|
45
|
+
|
|
46
|
+
all_problems: list[CreateProblem] = []
|
|
47
|
+
progress_bar = tqdm(lists_to_create, desc=" Creating lists", dynamic_ncols=True)
|
|
48
|
+
for new_lst in progress_bar:
|
|
49
|
+
list_iri, problems = _create_new_list(new_lst, create_client, project_iri)
|
|
50
|
+
if list_iri is None:
|
|
51
|
+
problems.extend(problems)
|
|
52
|
+
else:
|
|
53
|
+
name2iri.add_iri(new_lst.list_info.name, list_iri)
|
|
54
|
+
|
|
55
|
+
create_problems = None
|
|
56
|
+
if all_problems:
|
|
57
|
+
create_problems = CollectedProblems("The following problems occurred during list creation:", all_problems)
|
|
58
|
+
return name2iri, create_problems
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _print_existing_list_info(existing_lists: list[UserInformation]) -> None:
|
|
62
|
+
lists = ", ".join([x.focus_object for x in existing_lists])
|
|
63
|
+
msg = f" The following lists already exist on the server and will be skipped: {lists}"
|
|
64
|
+
logger.info(msg)
|
|
65
|
+
print(BOLD_CYAN + msg + RESET_TO_DEFAULT)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def get_existing_lists_on_server(shortcode: str, auth: AuthenticationClient) -> ListNameToIriLookup:
|
|
69
|
+
client = ListGetClientLive(auth.server, shortcode)
|
|
70
|
+
try:
|
|
71
|
+
name2iri_dict = client.get_all_list_iris_and_names()
|
|
72
|
+
return ListNameToIriLookup(name2iri_dict)
|
|
73
|
+
except FatalNonOkApiResponseCode as e:
|
|
74
|
+
logger.exception(e)
|
|
75
|
+
warnings.warn(
|
|
76
|
+
DspToolsUnexpectedStatusCodeWarning(
|
|
77
|
+
"Could not retrieve existing lists on server. "
|
|
78
|
+
"We will not be able to create any properties that require a list that is not defined in the JSON."
|
|
79
|
+
)
|
|
80
|
+
)
|
|
81
|
+
return ListNameToIriLookup({})
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _filter_out_existing_lists(
|
|
85
|
+
parsed_lists: list[ParsedList], name2iri: ListNameToIriLookup
|
|
86
|
+
) -> tuple[list[ParsedList], list[UserInformation]]:
|
|
87
|
+
lists_to_create: list[ParsedList] = []
|
|
88
|
+
existing_info: list[UserInformation] = []
|
|
89
|
+
|
|
90
|
+
for parsed_list in parsed_lists:
|
|
91
|
+
if name2iri.check_list_exists(parsed_list.list_info.name):
|
|
92
|
+
existing_info.append(
|
|
93
|
+
UserInformation(parsed_list.list_info.name, UserInformationMessage.LIST_EXISTS_ON_SERVER)
|
|
94
|
+
)
|
|
95
|
+
else:
|
|
96
|
+
lists_to_create.append(parsed_list)
|
|
97
|
+
|
|
98
|
+
return lists_to_create, existing_info
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _create_new_list(
|
|
102
|
+
parsed_list: ParsedList, create_client: ListCreateClient, project_iri: str
|
|
103
|
+
) -> tuple[str | None, list[UploadProblem]]:
|
|
104
|
+
serialised = _serialise_list(parsed_list.list_info, project_iri)
|
|
105
|
+
new_iri = create_client.create_new_list(serialised)
|
|
106
|
+
|
|
107
|
+
if new_iri is None:
|
|
108
|
+
problems: list[UploadProblem] = [
|
|
109
|
+
UploadProblem(parsed_list.list_info.name, UploadProblemType.LIST_COULD_NOT_BE_CREATED)
|
|
110
|
+
]
|
|
111
|
+
return None, problems
|
|
112
|
+
|
|
113
|
+
node_problems = []
|
|
114
|
+
if parsed_list.children:
|
|
115
|
+
node_problems = _create_node_tree(parsed_list.children, new_iri, create_client, project_iri)
|
|
116
|
+
|
|
117
|
+
return new_iri, node_problems
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _serialise_list(parsed_list_info: ParsedNodeInfo, project_iri: str) -> dict[str, Any]:
|
|
121
|
+
node_dict = {
|
|
122
|
+
"projectIri": project_iri,
|
|
123
|
+
"name": parsed_list_info.name,
|
|
124
|
+
"labels": _convert_to_api_format(parsed_list_info.labels),
|
|
125
|
+
}
|
|
126
|
+
if parsed_list_info.comments:
|
|
127
|
+
node_dict["comments"] = _convert_to_api_format(parsed_list_info.comments)
|
|
128
|
+
return node_dict
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _create_node_tree(
|
|
132
|
+
nodes: list[ParsedListNode], parent_iri: str, create_client: ListCreateClient, project_iri: str
|
|
133
|
+
) -> list[UploadProblem]:
|
|
134
|
+
problems: list[UploadProblem] = []
|
|
135
|
+
|
|
136
|
+
for node in nodes:
|
|
137
|
+
serialised = _serialise_node(node.node_info, parent_iri, project_iri)
|
|
138
|
+
node_iri = create_client.add_list_node(serialised, parent_iri)
|
|
139
|
+
if node_iri is None:
|
|
140
|
+
problems.append(UploadProblem(node.node_info.name, UploadProblemType.LIST_NODE_COULD_NOT_BE_CREATED))
|
|
141
|
+
continue
|
|
142
|
+
|
|
143
|
+
if node.children:
|
|
144
|
+
child_problems = _create_node_tree(node.children, node_iri, create_client, project_iri)
|
|
145
|
+
problems.extend(child_problems)
|
|
146
|
+
|
|
147
|
+
return problems
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _serialise_node(node_info: ParsedNodeInfo, parent_iri: str, project_iri: str) -> dict[str, Any]:
|
|
151
|
+
node_dict = {
|
|
152
|
+
"parentNodeIri": parent_iri,
|
|
153
|
+
"projectIri": project_iri,
|
|
154
|
+
"name": node_info.name,
|
|
155
|
+
"labels": _convert_to_api_format(node_info.labels),
|
|
156
|
+
}
|
|
157
|
+
if node_info.comments:
|
|
158
|
+
node_dict["comments"] = _convert_to_api_format(node_info.comments)
|
|
159
|
+
return node_dict
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _convert_to_api_format(lang_dict: dict[str, str]) -> list[dict[str, str]]:
|
|
163
|
+
return [{"value": value, "language": lang} for lang, value in lang_dict.items()]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from rdflib import OWL
|
|
2
|
+
from rdflib import Literal
|
|
3
|
+
|
|
4
|
+
from dsp_tools.commands.create.models.parsed_ontology import Cardinality
|
|
5
|
+
from dsp_tools.commands.create.models.rdf_ontology import RdfCardinalityRestriction
|
|
6
|
+
|
|
7
|
+
PARSED_CARDINALITY_TO_RDF = {
|
|
8
|
+
Cardinality.C_1: RdfCardinalityRestriction(OWL.cardinality, Literal(1)),
|
|
9
|
+
Cardinality.C_0_1: RdfCardinalityRestriction(OWL.maxCardinality, Literal(1)),
|
|
10
|
+
Cardinality.C_1_N: RdfCardinalityRestriction(OWL.minCardinality, Literal(1)),
|
|
11
|
+
Cardinality.C_0_N: RdfCardinalityRestriction(OWL.minCardinality, Literal(0)),
|
|
12
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import time
|
|
2
|
+
from http import HTTPStatus
|
|
3
|
+
|
|
4
|
+
import regex
|
|
5
|
+
import rustworkx as rx
|
|
6
|
+
from loguru import logger
|
|
7
|
+
from rdflib import OWL
|
|
8
|
+
from rdflib import RDF
|
|
9
|
+
from rdflib import Graph
|
|
10
|
+
from rdflib import URIRef
|
|
11
|
+
|
|
12
|
+
from dsp_tools.clients.ontology_clients import OntologyCreateClient
|
|
13
|
+
from dsp_tools.clients.ontology_get_client_live import OntologyGetClientLive
|
|
14
|
+
from dsp_tools.commands.create.exceptions import CircularOntologyDependency
|
|
15
|
+
from dsp_tools.commands.create.models.server_project_info import OntoLastModDateLookup
|
|
16
|
+
from dsp_tools.commands.create.models.server_project_info import ProjectIriLookup
|
|
17
|
+
from dsp_tools.error.exceptions import ProjectOntologyNotFound
|
|
18
|
+
from dsp_tools.utils.request_utils import ResponseCodeAndText
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def should_retry_request(response: ResponseCodeAndText) -> bool:
|
|
22
|
+
if response.status_code == HTTPStatus.BAD_REQUEST:
|
|
23
|
+
if regex.search(r"Ontology .+ modified", response.text):
|
|
24
|
+
return True
|
|
25
|
+
elif HTTPStatus.INTERNAL_SERVER_ERROR <= response.status_code <= HTTPStatus.NETWORK_AUTHENTICATION_REQUIRED:
|
|
26
|
+
time.sleep(5)
|
|
27
|
+
return True
|
|
28
|
+
return False
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def sort_for_upload(graph: rx.PyDiGraph, node_to_iri: dict[int, str]) -> list[str]:
|
|
32
|
+
try:
|
|
33
|
+
node_sorting_order = rx.topological_sort(graph)
|
|
34
|
+
return [node_to_iri[x] for x in reversed(node_sorting_order)]
|
|
35
|
+
except rx.DAGHasCycle as e:
|
|
36
|
+
logger.error(e)
|
|
37
|
+
raise CircularOntologyDependency("super-properties") from None
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_modification_date_onto_lookup(
|
|
41
|
+
project_iri_lookup: ProjectIriLookup,
|
|
42
|
+
onto_client: OntologyCreateClient,
|
|
43
|
+
) -> OntoLastModDateLookup:
|
|
44
|
+
lookup = OntoLastModDateLookup(
|
|
45
|
+
project_iri=project_iri_lookup.project_iri,
|
|
46
|
+
onto_iris={name: URIRef(iri) for name, iri in project_iri_lookup.onto_iris.items()},
|
|
47
|
+
)
|
|
48
|
+
for onto_iri in project_iri_lookup.onto_iris.values():
|
|
49
|
+
last_mod = onto_client.get_last_modification_date(project_iri_lookup.project_iri, onto_iri)
|
|
50
|
+
lookup.update_last_mod_date(onto_iri, last_mod)
|
|
51
|
+
return lookup
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def get_project_iri_lookup(server: str, shortcode: str, project_iri: str) -> ProjectIriLookup:
|
|
55
|
+
client = OntologyGetClientLive(server, shortcode)
|
|
56
|
+
try:
|
|
57
|
+
ontologies, onto_iris = client.get_ontologies()
|
|
58
|
+
logger.debug(f"Project ontologies found: {', '.join(onto_iris)}")
|
|
59
|
+
lookup = _get_name_to_iri_lookup(ontologies)
|
|
60
|
+
return ProjectIriLookup(project_iri, lookup)
|
|
61
|
+
except ProjectOntologyNotFound:
|
|
62
|
+
logger.debug("No project ontologies on server.")
|
|
63
|
+
return ProjectIriLookup(project_iri)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _get_name_to_iri_lookup(ontologies: list[str]) -> dict[str, str]:
|
|
67
|
+
lookup = {}
|
|
68
|
+
for onto in ontologies:
|
|
69
|
+
g = Graph()
|
|
70
|
+
g.parse(data=onto, format="ttl")
|
|
71
|
+
iri = str(next(g.subjects(RDF.type, OWL.Ontology)))
|
|
72
|
+
name = iri.split("/")[-2]
|
|
73
|
+
lookup[str(name)] = str(iri)
|
|
74
|
+
return lookup
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import time
|
|
2
|
+
|
|
3
|
+
from loguru import logger
|
|
4
|
+
from tqdm import tqdm
|
|
5
|
+
|
|
6
|
+
from dsp_tools.clients.ontology_clients import OntologyCreateClient
|
|
7
|
+
from dsp_tools.commands.create.models.create_problems import CollectedProblems
|
|
8
|
+
from dsp_tools.commands.create.models.create_problems import CreateProblem
|
|
9
|
+
from dsp_tools.commands.create.models.create_problems import UploadProblem
|
|
10
|
+
from dsp_tools.commands.create.models.create_problems import UploadProblemType
|
|
11
|
+
from dsp_tools.commands.create.models.parsed_ontology import ParsedOntology
|
|
12
|
+
from dsp_tools.commands.create.models.server_project_info import ProjectIriLookup
|
|
13
|
+
from dsp_tools.commands.create.serialisation.ontology import serialise_ontology_graph_for_request
|
|
14
|
+
from dsp_tools.utils.request_utils import ResponseCodeAndText
|
|
15
|
+
from dsp_tools.utils.request_utils import is_server_error
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def create_all_ontologies(
|
|
19
|
+
ontologies: list[ParsedOntology],
|
|
20
|
+
project_iri_lookup: ProjectIriLookup,
|
|
21
|
+
client: OntologyCreateClient,
|
|
22
|
+
) -> tuple[ProjectIriLookup, CollectedProblems | None]:
|
|
23
|
+
logger.debug("Creating ontologies")
|
|
24
|
+
progress_bar = tqdm(ontologies, " Creating ontologies", dynamic_ncols=True)
|
|
25
|
+
problems: list[CreateProblem] = []
|
|
26
|
+
for o in progress_bar:
|
|
27
|
+
result = _create_one_ontology(o, project_iri_lookup.project_iri, client)
|
|
28
|
+
if isinstance(result, UploadProblem):
|
|
29
|
+
problems.append(result)
|
|
30
|
+
else:
|
|
31
|
+
project_iri_lookup.add_onto(o.name, result)
|
|
32
|
+
if problems:
|
|
33
|
+
return project_iri_lookup, CollectedProblems(
|
|
34
|
+
" While creating ontologies the following problems occurred:", problems
|
|
35
|
+
)
|
|
36
|
+
return project_iri_lookup, None
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _create_one_ontology(
|
|
40
|
+
onto: ParsedOntology,
|
|
41
|
+
project_iri: str,
|
|
42
|
+
client: OntologyCreateClient,
|
|
43
|
+
) -> UploadProblem | str:
|
|
44
|
+
serialised = serialise_ontology_graph_for_request(onto, project_iri)
|
|
45
|
+
result = client.post_new_ontology(serialised)
|
|
46
|
+
if isinstance(result, ResponseCodeAndText):
|
|
47
|
+
if is_server_error(result):
|
|
48
|
+
time.sleep(5)
|
|
49
|
+
result = client.post_new_ontology(serialised)
|
|
50
|
+
if isinstance(result, ResponseCodeAndText):
|
|
51
|
+
return UploadProblem(result.text, UploadProblemType.ONTOLOGY_COULD_NOT_BE_CREATED)
|
|
52
|
+
return result
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
|
|
3
|
+
from loguru import logger
|
|
4
|
+
|
|
5
|
+
from dsp_tools.clients.authentication_client import AuthenticationClient
|
|
6
|
+
from dsp_tools.clients.project_client import ProjectClient
|
|
7
|
+
from dsp_tools.clients.project_client_live import ProjectClientLive
|
|
8
|
+
from dsp_tools.commands.create.exceptions import UnableToCreateProjectError
|
|
9
|
+
from dsp_tools.commands.create.models.parsed_project import ParsedProjectMetadata
|
|
10
|
+
from dsp_tools.commands.create.serialisation.project import serialise_project
|
|
11
|
+
from dsp_tools.error.exceptions import ProjectNotFoundError
|
|
12
|
+
from dsp_tools.utils.ansi_colors import BACKGROUND_BOLD_YELLOW
|
|
13
|
+
from dsp_tools.utils.ansi_colors import BOLD
|
|
14
|
+
from dsp_tools.utils.ansi_colors import BOLD_RED
|
|
15
|
+
from dsp_tools.utils.ansi_colors import RESET_TO_DEFAULT
|
|
16
|
+
from dsp_tools.utils.request_utils import is_server_error
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def create_project(project: ParsedProjectMetadata, auth: AuthenticationClient, exit_if_exists: bool) -> str:
|
|
20
|
+
client = ProjectClientLive(auth.server, auth)
|
|
21
|
+
try:
|
|
22
|
+
project_iri = client.get_project_iri(project.shortcode)
|
|
23
|
+
_exit_if_create_should_not_continue(project.shortcode, exit_if_exists)
|
|
24
|
+
return project_iri
|
|
25
|
+
|
|
26
|
+
except ProjectNotFoundError:
|
|
27
|
+
logger.debug("No project with the shortcode exists. Continuing creating the project.")
|
|
28
|
+
return _create_project_on_server(project, client)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _exit_if_create_should_not_continue(shortcode: str, exit_if_exists: bool) -> None:
|
|
32
|
+
if exit_if_exists:
|
|
33
|
+
msg = (
|
|
34
|
+
"The project already exists on the server and the flag '--exit-if-exists' was set. "
|
|
35
|
+
"The process is aborted without further uploads."
|
|
36
|
+
)
|
|
37
|
+
logger.info(msg)
|
|
38
|
+
print(BACKGROUND_BOLD_YELLOW + msg + RESET_TO_DEFAULT)
|
|
39
|
+
sys.exit(0)
|
|
40
|
+
|
|
41
|
+
msg = (
|
|
42
|
+
f"A project with the shortcode '{shortcode}' already exists on the server. "
|
|
43
|
+
f"Do you wish to continue uploading additional information? [y/n] "
|
|
44
|
+
)
|
|
45
|
+
logger.debug(msg)
|
|
46
|
+
resp = None
|
|
47
|
+
while resp not in ["y", "n"]:
|
|
48
|
+
resp = input(BOLD_RED + msg + RESET_TO_DEFAULT)
|
|
49
|
+
if resp == "n":
|
|
50
|
+
logger.debug("Response 'n' abort command.")
|
|
51
|
+
sys.exit(1)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _create_project_on_server(project: ParsedProjectMetadata, client: ProjectClient) -> str:
|
|
55
|
+
info_str = f"Creating project '{project.shortname}' ({project.shortcode})"
|
|
56
|
+
print(BOLD + info_str + RESET_TO_DEFAULT)
|
|
57
|
+
logger.debug(info_str)
|
|
58
|
+
serialised = serialise_project(project)
|
|
59
|
+
result = client.post_new_project(serialised)
|
|
60
|
+
if isinstance(result, str):
|
|
61
|
+
return result
|
|
62
|
+
if is_server_error(result):
|
|
63
|
+
msg = "Due to a server error it was not possible to create the project. "
|
|
64
|
+
else:
|
|
65
|
+
msg = "Unable to create project."
|
|
66
|
+
raise UnableToCreateProjectError(
|
|
67
|
+
msg + f"\nOriginal response code: {result.status_code}\nOriginal response message: {result.text}"
|
|
68
|
+
)
|