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
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
2
|
-
from dataclasses import field
|
|
3
|
-
from typing import Any
|
|
4
|
-
from typing import Protocol
|
|
5
|
-
|
|
6
|
-
from dsp_tools.models.exceptions import BaseError
|
|
7
|
-
from dsp_tools.models.exceptions import UserError
|
|
8
|
-
from dsp_tools.utils.connection import Connection
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@dataclass
|
|
12
|
-
class OntologyClient(Protocol):
|
|
13
|
-
"""Interface (protocol) for ontology-related requests to the DSP-API."""
|
|
14
|
-
|
|
15
|
-
con: Connection
|
|
16
|
-
shortcode: str
|
|
17
|
-
default_ontology: str
|
|
18
|
-
ontology_names: list[str] = field(default_factory=list)
|
|
19
|
-
|
|
20
|
-
def get_all_project_ontologies_from_server(self) -> dict[str, list[dict[str, Any]]]:
|
|
21
|
-
"""Get all the ontologies for a project from the server."""
|
|
22
|
-
|
|
23
|
-
def get_knora_api_ontology_from_server(self) -> list[dict[str, Any]]:
|
|
24
|
-
"""Get the knora-api ontology from the server."""
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
@dataclass
|
|
28
|
-
class OntologyClientLive:
|
|
29
|
-
"""Client handling ontology-related requests to the DSP-API."""
|
|
30
|
-
|
|
31
|
-
con: Connection
|
|
32
|
-
shortcode: str
|
|
33
|
-
default_ontology: str
|
|
34
|
-
ontology_names: list[str] = field(default_factory=list)
|
|
35
|
-
|
|
36
|
-
def get_all_project_ontologies_from_server(self) -> dict[str, list[dict[str, Any]]]:
|
|
37
|
-
"""
|
|
38
|
-
This function returns all the project ontologies that are on the server.
|
|
39
|
-
|
|
40
|
-
Returns:
|
|
41
|
-
a dictionary with the ontology name as key and the ontology as value.
|
|
42
|
-
"""
|
|
43
|
-
self._get_ontology_names_from_server()
|
|
44
|
-
return {onto: self._get_ontology_from_server(onto) for onto in self.ontology_names}
|
|
45
|
-
|
|
46
|
-
def _get_ontology_names_from_server(self) -> None:
|
|
47
|
-
try:
|
|
48
|
-
url = f"/admin/projects/shortcode/{self.shortcode}"
|
|
49
|
-
res = self.con.get(url)
|
|
50
|
-
except BaseError as e:
|
|
51
|
-
raise UserError(f"A project with shortcode {self.shortcode} could not be found on the DSP server") from e
|
|
52
|
-
try:
|
|
53
|
-
onto_iris: list[str] = res["project"]["ontologies"]
|
|
54
|
-
except KeyError as e:
|
|
55
|
-
raise BaseError(f"Unexpected response from server: {res}") from e
|
|
56
|
-
onto_names: list[str] = [iri.split("/")[-2] for iri in onto_iris]
|
|
57
|
-
self.ontology_names = onto_names
|
|
58
|
-
|
|
59
|
-
def _get_ontology_from_server(self, ontology_name: str) -> list[dict[str, Any]]:
|
|
60
|
-
try:
|
|
61
|
-
url = f"/ontology/{self.shortcode}/{ontology_name}/v2"
|
|
62
|
-
res = self.con.get(url)
|
|
63
|
-
except BaseError:
|
|
64
|
-
raise BaseError(
|
|
65
|
-
f"Ontologies for project {self.shortcode} could not be retrieved from the DSP server"
|
|
66
|
-
) from None
|
|
67
|
-
try:
|
|
68
|
-
onto_graph: list[dict[str, Any]] = res["@graph"]
|
|
69
|
-
except KeyError as e:
|
|
70
|
-
raise BaseError(f"Unexpected response from server: {res}") from e
|
|
71
|
-
return onto_graph
|
|
72
|
-
|
|
73
|
-
def get_knora_api_ontology_from_server(self) -> list[dict[str, Any]]:
|
|
74
|
-
"""
|
|
75
|
-
This function returns the knora-api ontology from the server.
|
|
76
|
-
|
|
77
|
-
Returns:
|
|
78
|
-
knora-api ontology in json format
|
|
79
|
-
|
|
80
|
-
Raises:
|
|
81
|
-
BaseError: if an unexpected response from the server occurred
|
|
82
|
-
"""
|
|
83
|
-
url = "/ontology/knora-api/v2#"
|
|
84
|
-
try:
|
|
85
|
-
res = self.con.get(url)
|
|
86
|
-
except BaseError:
|
|
87
|
-
raise BaseError("Knora-api ontology could not be retrieved from the DSP server") from None
|
|
88
|
-
try:
|
|
89
|
-
onto_graph: list[dict[str, Any]] = res["@graph"]
|
|
90
|
-
except KeyError as e:
|
|
91
|
-
raise BaseError(f"Unexpected response from server when retrieving knora-api ontology: {res}") from e
|
|
92
|
-
return onto_graph
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
2
|
-
from dataclasses import field
|
|
3
|
-
from typing import Protocol
|
|
4
|
-
from urllib.parse import quote_plus
|
|
5
|
-
|
|
6
|
-
from dsp_tools.models.exceptions import BaseError
|
|
7
|
-
from dsp_tools.models.exceptions import UserError
|
|
8
|
-
from dsp_tools.utils.connection import Connection
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@dataclass(frozen=True)
|
|
12
|
-
class ProjectInfo:
|
|
13
|
-
"""Information about a project."""
|
|
14
|
-
|
|
15
|
-
project_iri: str
|
|
16
|
-
ontology_iris: list[str]
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class ProjectClient(Protocol):
|
|
20
|
-
"""Interface (protocol) for project-related requests to the DSP-API."""
|
|
21
|
-
|
|
22
|
-
con: Connection
|
|
23
|
-
shortcode: str
|
|
24
|
-
project_info: ProjectInfo | None
|
|
25
|
-
|
|
26
|
-
def get_project_iri(self) -> str:
|
|
27
|
-
"""Get the IRI of the project to which the data is being uploaded."""
|
|
28
|
-
|
|
29
|
-
def get_ontology_name_dict(self) -> dict[str, str]:
|
|
30
|
-
"""Returns a mapping of ontology names to ontology IRIs."""
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
@dataclass()
|
|
34
|
-
class ProjectClientLive:
|
|
35
|
-
"""Client handling project-related requests to the DSP-API."""
|
|
36
|
-
|
|
37
|
-
con: Connection
|
|
38
|
-
shortcode: str
|
|
39
|
-
project_info: ProjectInfo | None = field(init=False, default=None)
|
|
40
|
-
|
|
41
|
-
def get_project_iri(self) -> str:
|
|
42
|
-
"""Get the IRI of the project to which the data is being uploaded."""
|
|
43
|
-
if not self.project_info:
|
|
44
|
-
self.project_info = _get_project_info_from_server(self.con, self.shortcode)
|
|
45
|
-
return self.project_info.project_iri
|
|
46
|
-
|
|
47
|
-
def get_ontology_name_dict(self) -> dict[str, str]:
|
|
48
|
-
"""Returns a mapping of ontology names to ontology IRIs."""
|
|
49
|
-
if not self.project_info:
|
|
50
|
-
self.project_info = _get_project_info_from_server(self.con, self.shortcode)
|
|
51
|
-
return {_extract_name_from_onto_iri(iri): iri for iri in self.project_info.ontology_iris}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def _get_project_info_from_server(con: Connection, shortcode: str) -> ProjectInfo:
|
|
55
|
-
project_iri = _get_project_iri_from_server(con, shortcode)
|
|
56
|
-
ontologies = _get_ontologies_from_server(con, project_iri)
|
|
57
|
-
return ProjectInfo(project_iri=project_iri, ontology_iris=ontologies)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def _get_project_iri_from_server(con: Connection, shortcode: str) -> str:
|
|
61
|
-
url = f"/admin/projects/shortcode/{shortcode}"
|
|
62
|
-
try:
|
|
63
|
-
res = con.get(url)
|
|
64
|
-
except BaseError as e:
|
|
65
|
-
raise UserError(f"A project with shortcode {shortcode} could not be found on the DSP server") from e
|
|
66
|
-
|
|
67
|
-
iri: str | None = res.get("project", {}).get("id")
|
|
68
|
-
if not iri:
|
|
69
|
-
raise BaseError(f"Unexpected response from server: {res}")
|
|
70
|
-
return iri
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def _get_ontologies_from_server(con: Connection, project_iri: str) -> list[str]:
|
|
74
|
-
try:
|
|
75
|
-
iri = quote_plus(project_iri)
|
|
76
|
-
url = f"/v2/ontologies/metadata/{iri}"
|
|
77
|
-
res = con.get(url)
|
|
78
|
-
body = res.get("@graph", res)
|
|
79
|
-
match body:
|
|
80
|
-
case list():
|
|
81
|
-
return [o["@id"] for o in body]
|
|
82
|
-
case dict():
|
|
83
|
-
return [body["@id"]]
|
|
84
|
-
case _:
|
|
85
|
-
raise BaseError("Unexpected response from server")
|
|
86
|
-
except BaseError as e:
|
|
87
|
-
raise BaseError(f"Ontologies for project {project_iri} could not be retrieved from the DSP server") from e
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
def _extract_name_from_onto_iri(iri: str) -> str:
|
|
91
|
-
return iri.split("/")[-2]
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
|
|
5
|
-
import regex
|
|
6
|
-
from lxml import etree
|
|
7
|
-
|
|
8
|
-
from dsp_tools.models.exceptions import UserError
|
|
9
|
-
from dsp_tools.utils.iri_util import is_resource_iri
|
|
10
|
-
from dsp_tools.utils.xml_utils import parse_xml_file
|
|
11
|
-
from dsp_tools.utils.xml_utils import remove_comments_from_element_tree
|
|
12
|
-
from dsp_tools.utils.xml_utils import transform_special_tags_make_localname
|
|
13
|
-
from dsp_tools.utils.xml_validation import validate_xml
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def validate_and_parse(input_file: Path) -> tuple[etree._Element, str, str]:
|
|
17
|
-
"""Parse and validate an XML file.
|
|
18
|
-
|
|
19
|
-
Args:
|
|
20
|
-
input_file: Path to the XML file
|
|
21
|
-
|
|
22
|
-
Returns:
|
|
23
|
-
The root element of the parsed XML file, the shortcode, and the default ontology
|
|
24
|
-
"""
|
|
25
|
-
root = parse_xml_file(input_file)
|
|
26
|
-
root = remove_comments_from_element_tree(root)
|
|
27
|
-
|
|
28
|
-
validate_xml(root)
|
|
29
|
-
root = transform_special_tags_make_localname(root)
|
|
30
|
-
_check_if_link_targets_exist(root)
|
|
31
|
-
shortcode = root.attrib["shortcode"]
|
|
32
|
-
default_ontology = root.attrib["default-ontology"]
|
|
33
|
-
return root, shortcode, default_ontology
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def _check_if_link_targets_exist(root: etree._Element) -> None:
|
|
37
|
-
"""
|
|
38
|
-
Make sure that all targets of links (resptr and salsah-links)
|
|
39
|
-
are either IRIs or IDs that exist in the present XML file.
|
|
40
|
-
|
|
41
|
-
Args:
|
|
42
|
-
root: parsed XML file
|
|
43
|
-
|
|
44
|
-
Raises:
|
|
45
|
-
UserError: if a link target does not exist in the XML file
|
|
46
|
-
"""
|
|
47
|
-
resptr_errors = _check_if_resptr_targets_exist(root)
|
|
48
|
-
salsah_errors = _check_if_salsah_targets_exist(root)
|
|
49
|
-
if errors := resptr_errors + salsah_errors:
|
|
50
|
-
sep = "\n - "
|
|
51
|
-
msg = f"It is not possible to upload the XML file, because it contains invalid links:{sep}{sep.join(errors)}"
|
|
52
|
-
raise UserError(msg)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def _check_if_resptr_targets_exist(root: etree._Element) -> list[str]:
|
|
56
|
-
link_values = [x for x in root.iter() if x.tag == "resptr"]
|
|
57
|
-
resource_ids = [x.attrib["id"] for x in root.iter() if x.tag == "resource"]
|
|
58
|
-
invalid_link_values = [x for x in link_values if x.text not in resource_ids]
|
|
59
|
-
invalid_link_values = [x for x in invalid_link_values if not is_resource_iri(str(x.text))]
|
|
60
|
-
errors = []
|
|
61
|
-
for inv in invalid_link_values:
|
|
62
|
-
prop_name = next(inv.iterancestors(tag="resptr-prop")).attrib["name"]
|
|
63
|
-
res_id = next(inv.iterancestors(tag="resource")).attrib["id"]
|
|
64
|
-
errors.append(f"Resource '{res_id}', property '{prop_name}' has an invalid link target '{inv.text}'")
|
|
65
|
-
return errors
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def _check_if_salsah_targets_exist(root: etree._Element) -> list[str]:
|
|
69
|
-
link_values = [x for x in root.iter() if x.tag == "a"]
|
|
70
|
-
resource_ids = [x.attrib["id"] for x in root.iter() if x.tag == "resource"]
|
|
71
|
-
invalid_link_values = [x for x in link_values if regex.sub(r"IRI:|:IRI", "", x.attrib["href"]) not in resource_ids]
|
|
72
|
-
invalid_link_values = [x for x in invalid_link_values if x.attrib.get("class") == "salsah-link"]
|
|
73
|
-
invalid_link_values = [x for x in invalid_link_values if not is_resource_iri(x.attrib["href"])]
|
|
74
|
-
errors = []
|
|
75
|
-
for inv in invalid_link_values:
|
|
76
|
-
prop_name = next(inv.iterancestors(tag="text-prop")).attrib["name"]
|
|
77
|
-
res_id = next(inv.iterancestors(tag="resource")).attrib["id"]
|
|
78
|
-
errors.append(f"Resource '{res_id}', property '{prop_name}' has an invalid link target '{inv.attrib['href']}'")
|
|
79
|
-
return errors
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def check_if_bitstreams_exist(root: etree._Element, imgdir: str) -> None:
|
|
83
|
-
"""
|
|
84
|
-
Make sure that all bitstreams referenced in the XML file exist in the imgdir.
|
|
85
|
-
|
|
86
|
-
Args:
|
|
87
|
-
root: parsed XML file
|
|
88
|
-
imgdir: folder where the bitstreams are stored
|
|
89
|
-
|
|
90
|
-
Raises:
|
|
91
|
-
UserError: if a bitstream does not exist in the imgdir
|
|
92
|
-
"""
|
|
93
|
-
multimedia_resources = [x for x in root if any((y.tag == "bitstream" for y in x.iter()))]
|
|
94
|
-
for res in multimedia_resources:
|
|
95
|
-
pth = next(Path(x.text) for x in res.iter() if x.tag == "bitstream" and x.text)
|
|
96
|
-
if not Path(imgdir / pth).is_file():
|
|
97
|
-
raise UserError(
|
|
98
|
-
f"Bitstream '{pth!s}' of resource '{res.attrib['label']}' does not exist in the imgdir '{imgdir}'."
|
|
99
|
-
)
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
from typing import Protocol
|
|
2
|
-
from typing import runtime_checkable
|
|
3
|
-
|
|
4
|
-
from termcolor import cprint
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
@runtime_checkable
|
|
8
|
-
class DspToolsWarning(Protocol):
|
|
9
|
-
"""Protocol for warnings that implement a custom showwarnings() function"""
|
|
10
|
-
|
|
11
|
-
@classmethod
|
|
12
|
-
def showwarning(cls, message: str) -> None:
|
|
13
|
-
"""Functionality that should be executed when a warning of this class is emitted"""
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class DspToolsUserWarning(Warning):
|
|
17
|
-
"""Class for general user-facing warnings"""
|
|
18
|
-
|
|
19
|
-
@classmethod
|
|
20
|
-
def showwarning(cls, message: str) -> None:
|
|
21
|
-
"""Print the warning, without context"""
|
|
22
|
-
cprint(f"WARNING: {message}", color="red", attrs=["bold"])
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class DspToolsFutureWarning(FutureWarning):
|
|
26
|
-
"""Class for user-facing deprecation warnings"""
|
|
27
|
-
|
|
28
|
-
@classmethod
|
|
29
|
-
def showwarning(cls, message: str) -> None:
|
|
30
|
-
"""Print the warning, without context"""
|
|
31
|
-
cprint(f"DEPRECATION WARNING: {message}", color="red", attrs=["bold"])
|
dsp_tools/models/exceptions.py
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
@dataclass
|
|
6
|
-
class BaseError(Exception):
|
|
7
|
-
"""
|
|
8
|
-
A basic error class for DSP-TOOLS.
|
|
9
|
-
|
|
10
|
-
Attributes:
|
|
11
|
-
message: A message that describes the error
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
message: str
|
|
15
|
-
|
|
16
|
-
def __str__(self) -> str:
|
|
17
|
-
return self.message
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
@dataclass
|
|
21
|
-
class Excel2JsonListError(BaseError):
|
|
22
|
-
"""
|
|
23
|
-
Class for errors that are raised in the context of the excel2json ListNode class.
|
|
24
|
-
"""
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class InternalError(BaseError):
|
|
28
|
-
"""
|
|
29
|
-
Class for errors that are raised if the user cannot solve the problem themselves.
|
|
30
|
-
"""
|
|
31
|
-
|
|
32
|
-
def __init__(self, custom_msg: str | None = None, keep_default_msg: bool = True) -> None:
|
|
33
|
-
default_msg = (
|
|
34
|
-
"\n\nAn internal error occurred.\n"
|
|
35
|
-
"Please contact the dsp-tools development team with the following information:\n"
|
|
36
|
-
" - Which command was used.\n"
|
|
37
|
-
" - If applicable, any files that were used in conjunction with the command.\n"
|
|
38
|
-
" - A file with the terminal output copied into.\n"
|
|
39
|
-
" - The log files called 'logging.log', if there are several, include all.\n"
|
|
40
|
-
f" They can be found at: {Path.home() / Path('.dsp-tools')}\n"
|
|
41
|
-
)
|
|
42
|
-
match keep_default_msg, custom_msg:
|
|
43
|
-
case False, str():
|
|
44
|
-
super().__init__(custom_msg)
|
|
45
|
-
case True, str():
|
|
46
|
-
default_msg = f"\n\n{custom_msg}\n--------------------------{default_msg}"
|
|
47
|
-
super().__init__(default_msg)
|
|
48
|
-
case _:
|
|
49
|
-
super().__init__(default_msg)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
class PermissionNotExistsError(BaseError):
|
|
53
|
-
"""Class for errors that are raised when a permission does not exist."""
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
class InputError(BaseError):
|
|
57
|
-
"""Class for errors that is called when the user input is invalid."""
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
class UserError(BaseError):
|
|
61
|
-
"""
|
|
62
|
-
Class for errors that are intended for user feedback.
|
|
63
|
-
Typically, a UserError is raised when the execution of a program must be interrupted
|
|
64
|
-
due to a bad condition in the input data that prevents further processing.
|
|
65
|
-
The message should be as user-friendly as possible.
|
|
66
|
-
"""
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
class PermanentConnectionError(BaseError):
|
|
70
|
-
"""This error is raised when all attempts to reconnect to DSP have failed."""
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
class InvalidInputError(BaseError):
|
|
74
|
-
"""This error is raised if the API responds with a permanent error because of invalid input data"""
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
class PermanentTimeOutError(BaseError):
|
|
78
|
-
"""This error is raised when python throws a timeout due to no response from the DSP-API."""
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
class BadCredentialsError(PermanentConnectionError):
|
|
82
|
-
"""This error is raised when DSP-API doesn't accept the prodived credentials."""
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
class XmlUploadError(BaseError):
|
|
86
|
-
"""Represents an error raised in the context of the xmlupload."""
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
class XmlUploadInterruptedError(XmlUploadError):
|
|
90
|
-
"""Represents an error raised when the xmlupload was interrupted."""
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://raw.githubusercontent.com/dasch-swiss/dsp-tools/main/src/dsp_tools/resources/schema/project.json",
|
|
3
|
-
"project": {
|
|
4
|
-
"shortcode": "0100",
|
|
5
|
-
"shortname": "minimal",
|
|
6
|
-
"longname": "minimal",
|
|
7
|
-
"descriptions": { "en": "minimal" },
|
|
8
|
-
"keywords": ["minimal"],
|
|
9
|
-
"ontologies": [
|
|
10
|
-
{
|
|
11
|
-
"name": "minimal",
|
|
12
|
-
"label": "minimal",
|
|
13
|
-
"properties": [
|
|
14
|
-
{
|
|
15
|
-
"name": "hasText",
|
|
16
|
-
"super": [
|
|
17
|
-
"hasValue"
|
|
18
|
-
],
|
|
19
|
-
"object": "TextValue",
|
|
20
|
-
"labels": {
|
|
21
|
-
"en": "hasText"
|
|
22
|
-
},
|
|
23
|
-
"gui_element": "SimpleText"
|
|
24
|
-
}
|
|
25
|
-
],
|
|
26
|
-
"resources": [
|
|
27
|
-
{
|
|
28
|
-
"name": "MinimalResource",
|
|
29
|
-
"super": "Resource",
|
|
30
|
-
"labels": {
|
|
31
|
-
"en": "MinimalResource"
|
|
32
|
-
},
|
|
33
|
-
"cardinalities": [
|
|
34
|
-
{
|
|
35
|
-
"propname": ":hasText",
|
|
36
|
-
"gui_order": 1,
|
|
37
|
-
"cardinality": "0-n"
|
|
38
|
-
}
|
|
39
|
-
]
|
|
40
|
-
}
|
|
41
|
-
]
|
|
42
|
-
}
|
|
43
|
-
]
|
|
44
|
-
}
|
|
45
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
<?xml version='1.0' encoding='utf-8'?>
|
|
2
|
-
|
|
3
|
-
<knora xmlns="https://dasch.swiss/schema"
|
|
4
|
-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
5
|
-
xsi:schemaLocation="https://dasch.swiss/schema https://raw.githubusercontent.com/dasch-swiss/dsp-tools/main/src/dsp_tools/resources/schema/data.xsd"
|
|
6
|
-
shortcode="0100"
|
|
7
|
-
default-ontology="minimal">
|
|
8
|
-
|
|
9
|
-
<permissions id="res-default">
|
|
10
|
-
<allow group="UnknownUser">RV</allow>
|
|
11
|
-
<allow group="KnownUser">V</allow>
|
|
12
|
-
<allow group="ProjectMember">M</allow>
|
|
13
|
-
<allow group="ProjectAdmin">D</allow>
|
|
14
|
-
<allow group="Creator">CR</allow>
|
|
15
|
-
<allow group="SystemAdmin">CR</allow>
|
|
16
|
-
</permissions>
|
|
17
|
-
<permissions id="prop-default">
|
|
18
|
-
<allow group="SystemAdmin">CR</allow>
|
|
19
|
-
</permissions>
|
|
20
|
-
|
|
21
|
-
<resource label="res_0" restype=":MinimalResource" id="res_0" permissions="res-default">
|
|
22
|
-
<text-prop name=":hasText">
|
|
23
|
-
<text encoding="utf8" permissions="prop-default">Hello!</text>
|
|
24
|
-
</text-prop>
|
|
25
|
-
</resource>
|
|
26
|
-
|
|
27
|
-
</knora>
|