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.
Files changed (348) hide show
  1. dsp_tools/__init__.py +5 -0
  2. dsp_tools/cli/args.py +47 -0
  3. dsp_tools/cli/call_action.py +85 -0
  4. dsp_tools/cli/call_action_files_only.py +101 -0
  5. dsp_tools/cli/call_action_with_network.py +207 -0
  6. dsp_tools/cli/create_parsers.py +479 -0
  7. dsp_tools/cli/entry_point.py +322 -0
  8. dsp_tools/cli/utils.py +87 -0
  9. dsp_tools/clients/CLAUDE.md +420 -0
  10. dsp_tools/clients/authentication_client.py +14 -0
  11. dsp_tools/clients/authentication_client_live.py +66 -0
  12. dsp_tools/clients/connection.py +35 -0
  13. dsp_tools/clients/connection_live.py +233 -0
  14. dsp_tools/clients/fuseki_metrics.py +60 -0
  15. dsp_tools/clients/group_user_clients.py +35 -0
  16. dsp_tools/clients/group_user_clients_live.py +181 -0
  17. dsp_tools/clients/legal_info_client.py +23 -0
  18. dsp_tools/clients/legal_info_client_live.py +132 -0
  19. dsp_tools/clients/list_client.py +49 -0
  20. dsp_tools/clients/list_client_live.py +166 -0
  21. dsp_tools/clients/metadata_client.py +24 -0
  22. dsp_tools/clients/metadata_client_live.py +47 -0
  23. dsp_tools/clients/ontology_clients.py +49 -0
  24. dsp_tools/clients/ontology_create_client_live.py +166 -0
  25. dsp_tools/clients/ontology_get_client_live.py +80 -0
  26. dsp_tools/clients/permissions_client.py +68 -0
  27. dsp_tools/clients/project_client.py +16 -0
  28. dsp_tools/clients/project_client_live.py +66 -0
  29. dsp_tools/commands/create/communicate_problems.py +24 -0
  30. dsp_tools/commands/create/create.py +134 -0
  31. dsp_tools/commands/create/create_on_server/cardinalities.py +111 -0
  32. dsp_tools/commands/create/create_on_server/classes.py +99 -0
  33. dsp_tools/commands/create/create_on_server/complete_ontologies.py +116 -0
  34. dsp_tools/commands/create/create_on_server/default_permissions.py +134 -0
  35. dsp_tools/commands/create/create_on_server/group_users.py +165 -0
  36. dsp_tools/commands/create/create_on_server/lists.py +163 -0
  37. dsp_tools/commands/create/create_on_server/mappers.py +12 -0
  38. dsp_tools/commands/create/create_on_server/onto_utils.py +74 -0
  39. dsp_tools/commands/create/create_on_server/ontology.py +52 -0
  40. dsp_tools/commands/create/create_on_server/project.py +68 -0
  41. dsp_tools/commands/create/create_on_server/properties.py +119 -0
  42. dsp_tools/commands/create/exceptions.py +29 -0
  43. dsp_tools/commands/create/lists_only.py +66 -0
  44. dsp_tools/commands/create/models/create_problems.py +87 -0
  45. dsp_tools/commands/create/models/parsed_ontology.py +88 -0
  46. dsp_tools/commands/create/models/parsed_project.py +81 -0
  47. dsp_tools/commands/create/models/rdf_ontology.py +12 -0
  48. dsp_tools/commands/create/models/server_project_info.py +100 -0
  49. dsp_tools/commands/create/parsing/parse_lists.py +45 -0
  50. dsp_tools/commands/create/parsing/parse_ontology.py +243 -0
  51. dsp_tools/commands/create/parsing/parse_project.py +149 -0
  52. dsp_tools/commands/create/parsing/parsing_utils.py +40 -0
  53. dsp_tools/commands/create/project_validate.py +595 -0
  54. dsp_tools/commands/create/serialisation/ontology.py +119 -0
  55. dsp_tools/commands/create/serialisation/project.py +44 -0
  56. dsp_tools/commands/excel2json/CLAUDE.md +101 -0
  57. dsp_tools/commands/excel2json/json_header.py +321 -0
  58. dsp_tools/commands/excel2json/lists/__init__.py +0 -0
  59. dsp_tools/commands/excel2json/lists/compliance_checks.py +292 -0
  60. dsp_tools/commands/excel2json/lists/make_lists.py +247 -0
  61. dsp_tools/commands/excel2json/lists/models/__init__.py +0 -0
  62. dsp_tools/commands/excel2json/lists/models/deserialise.py +30 -0
  63. dsp_tools/commands/excel2json/lists/models/input_error.py +216 -0
  64. dsp_tools/commands/excel2json/lists/models/serialise.py +57 -0
  65. dsp_tools/commands/excel2json/lists/utils.py +81 -0
  66. dsp_tools/commands/excel2json/models/__init__.py +0 -0
  67. dsp_tools/commands/excel2json/models/input_error.py +416 -0
  68. dsp_tools/commands/excel2json/models/json_header.py +175 -0
  69. dsp_tools/commands/excel2json/models/list_node_name.py +16 -0
  70. dsp_tools/commands/excel2json/models/ontology.py +76 -0
  71. dsp_tools/commands/excel2json/old_lists.py +328 -0
  72. dsp_tools/commands/excel2json/project.py +280 -0
  73. dsp_tools/commands/excel2json/properties.py +370 -0
  74. dsp_tools/commands/excel2json/resources.py +336 -0
  75. dsp_tools/commands/excel2json/utils.py +352 -0
  76. dsp_tools/commands/excel2xml/__init__.py +7 -0
  77. dsp_tools/commands/excel2xml/excel2xml_cli.py +523 -0
  78. dsp_tools/commands/excel2xml/excel2xml_lib.py +1953 -0
  79. dsp_tools/commands/excel2xml/propertyelement.py +47 -0
  80. dsp_tools/commands/get/__init__.py +0 -0
  81. dsp_tools/commands/get/get.py +166 -0
  82. dsp_tools/commands/get/get_permissions.py +257 -0
  83. dsp_tools/commands/get/get_permissions_legacy.py +89 -0
  84. dsp_tools/commands/get/legacy_models/__init__.py +0 -0
  85. dsp_tools/commands/get/legacy_models/context.py +318 -0
  86. dsp_tools/commands/get/legacy_models/group.py +241 -0
  87. dsp_tools/commands/get/legacy_models/helpers.py +47 -0
  88. dsp_tools/commands/get/legacy_models/listnode.py +390 -0
  89. dsp_tools/commands/get/legacy_models/model.py +12 -0
  90. dsp_tools/commands/get/legacy_models/ontology.py +324 -0
  91. dsp_tools/commands/get/legacy_models/project.py +366 -0
  92. dsp_tools/commands/get/legacy_models/propertyclass.py +417 -0
  93. dsp_tools/commands/get/legacy_models/resourceclass.py +676 -0
  94. dsp_tools/commands/get/legacy_models/user.py +438 -0
  95. dsp_tools/commands/get/models/__init__.py +0 -0
  96. dsp_tools/commands/get/models/permissions_models.py +10 -0
  97. dsp_tools/commands/id2iri.py +258 -0
  98. dsp_tools/commands/ingest_xmlupload/__init__.py +0 -0
  99. dsp_tools/commands/ingest_xmlupload/bulk_ingest_client.py +178 -0
  100. dsp_tools/commands/ingest_xmlupload/create_resources/__init__.py +0 -0
  101. dsp_tools/commands/ingest_xmlupload/create_resources/apply_ingest_id.py +69 -0
  102. dsp_tools/commands/ingest_xmlupload/create_resources/upload_xml.py +166 -0
  103. dsp_tools/commands/ingest_xmlupload/create_resources/user_information.py +121 -0
  104. dsp_tools/commands/ingest_xmlupload/ingest_files/__init__.py +0 -0
  105. dsp_tools/commands/ingest_xmlupload/ingest_files/ingest_files.py +64 -0
  106. dsp_tools/commands/ingest_xmlupload/upload_files/__init__.py +0 -0
  107. dsp_tools/commands/ingest_xmlupload/upload_files/filechecker.py +20 -0
  108. dsp_tools/commands/ingest_xmlupload/upload_files/input_error.py +57 -0
  109. dsp_tools/commands/ingest_xmlupload/upload_files/upload_failures.py +66 -0
  110. dsp_tools/commands/ingest_xmlupload/upload_files/upload_files.py +67 -0
  111. dsp_tools/commands/resume_xmlupload/__init__.py +0 -0
  112. dsp_tools/commands/resume_xmlupload/resume_xmlupload.py +96 -0
  113. dsp_tools/commands/start_stack.py +428 -0
  114. dsp_tools/commands/update_legal/CLAUDE.md +344 -0
  115. dsp_tools/commands/update_legal/__init__.py +0 -0
  116. dsp_tools/commands/update_legal/core.py +182 -0
  117. dsp_tools/commands/update_legal/csv_operations.py +135 -0
  118. dsp_tools/commands/update_legal/models.py +87 -0
  119. dsp_tools/commands/update_legal/xml_operations.py +247 -0
  120. dsp_tools/commands/validate_data/CLAUDE.md +159 -0
  121. dsp_tools/commands/validate_data/__init__.py +0 -0
  122. dsp_tools/commands/validate_data/constants.py +59 -0
  123. dsp_tools/commands/validate_data/mappers.py +143 -0
  124. dsp_tools/commands/validate_data/models/__init__.py +0 -0
  125. dsp_tools/commands/validate_data/models/api_responses.py +45 -0
  126. dsp_tools/commands/validate_data/models/input_problems.py +119 -0
  127. dsp_tools/commands/validate_data/models/rdf_like_data.py +117 -0
  128. dsp_tools/commands/validate_data/models/validation.py +106 -0
  129. dsp_tools/commands/validate_data/prepare_data/__init__.py +0 -0
  130. dsp_tools/commands/validate_data/prepare_data/get_rdf_like_data.py +296 -0
  131. dsp_tools/commands/validate_data/prepare_data/make_data_graph.py +91 -0
  132. dsp_tools/commands/validate_data/prepare_data/prepare_data.py +184 -0
  133. dsp_tools/commands/validate_data/process_validation_report/__init__.py +0 -0
  134. dsp_tools/commands/validate_data/process_validation_report/get_user_validation_message.py +358 -0
  135. dsp_tools/commands/validate_data/process_validation_report/query_validation_result.py +507 -0
  136. dsp_tools/commands/validate_data/process_validation_report/reformat_validation_results.py +150 -0
  137. dsp_tools/commands/validate_data/shacl_cli_validator.py +70 -0
  138. dsp_tools/commands/validate_data/sparql/__init__.py +0 -0
  139. dsp_tools/commands/validate_data/sparql/cardinality_shacl.py +209 -0
  140. dsp_tools/commands/validate_data/sparql/construct_shacl.py +92 -0
  141. dsp_tools/commands/validate_data/sparql/legal_info_shacl.py +36 -0
  142. dsp_tools/commands/validate_data/sparql/value_shacl.py +357 -0
  143. dsp_tools/commands/validate_data/utils.py +59 -0
  144. dsp_tools/commands/validate_data/validate_data.py +283 -0
  145. dsp_tools/commands/validate_data/validation/__init__.py +0 -0
  146. dsp_tools/commands/validate_data/validation/check_duplicate_files.py +55 -0
  147. dsp_tools/commands/validate_data/validation/check_for_unknown_classes.py +67 -0
  148. dsp_tools/commands/validate_data/validation/get_validation_report.py +94 -0
  149. dsp_tools/commands/validate_data/validation/validate_ontology.py +107 -0
  150. dsp_tools/commands/xmlupload/CLAUDE.md +292 -0
  151. dsp_tools/commands/xmlupload/__init__.py +0 -0
  152. dsp_tools/commands/xmlupload/iri_resolver.py +21 -0
  153. dsp_tools/commands/xmlupload/make_rdf_graph/__init__.py +0 -0
  154. dsp_tools/commands/xmlupload/make_rdf_graph/constants.py +63 -0
  155. dsp_tools/commands/xmlupload/make_rdf_graph/jsonld_utils.py +44 -0
  156. dsp_tools/commands/xmlupload/make_rdf_graph/make_file_value.py +77 -0
  157. dsp_tools/commands/xmlupload/make_rdf_graph/make_resource_and_values.py +114 -0
  158. dsp_tools/commands/xmlupload/make_rdf_graph/make_values.py +262 -0
  159. dsp_tools/commands/xmlupload/models/__init__.py +0 -0
  160. dsp_tools/commands/xmlupload/models/bitstream_info.py +18 -0
  161. dsp_tools/commands/xmlupload/models/formatted_text_value.py +10 -0
  162. dsp_tools/commands/xmlupload/models/ingest.py +143 -0
  163. dsp_tools/commands/xmlupload/models/input_problems.py +58 -0
  164. dsp_tools/commands/xmlupload/models/lookup_models.py +21 -0
  165. dsp_tools/commands/xmlupload/models/permission.py +45 -0
  166. dsp_tools/commands/xmlupload/models/permissions_parsed.py +93 -0
  167. dsp_tools/commands/xmlupload/models/processed/__init__.py +0 -0
  168. dsp_tools/commands/xmlupload/models/processed/file_values.py +29 -0
  169. dsp_tools/commands/xmlupload/models/processed/res.py +27 -0
  170. dsp_tools/commands/xmlupload/models/processed/values.py +101 -0
  171. dsp_tools/commands/xmlupload/models/rdf_models.py +26 -0
  172. dsp_tools/commands/xmlupload/models/upload_clients.py +14 -0
  173. dsp_tools/commands/xmlupload/models/upload_state.py +20 -0
  174. dsp_tools/commands/xmlupload/prepare_xml_input/__init__.py +0 -0
  175. dsp_tools/commands/xmlupload/prepare_xml_input/ark2iri.py +55 -0
  176. dsp_tools/commands/xmlupload/prepare_xml_input/get_processed_resources.py +252 -0
  177. dsp_tools/commands/xmlupload/prepare_xml_input/iiif_uri_validator.py +50 -0
  178. dsp_tools/commands/xmlupload/prepare_xml_input/list_client.py +120 -0
  179. dsp_tools/commands/xmlupload/prepare_xml_input/prepare_xml_input.py +67 -0
  180. dsp_tools/commands/xmlupload/prepare_xml_input/read_validate_xml_file.py +58 -0
  181. dsp_tools/commands/xmlupload/prepare_xml_input/transform_input_values.py +118 -0
  182. dsp_tools/commands/xmlupload/resource_create_client.py +25 -0
  183. dsp_tools/commands/xmlupload/richtext_id2iri.py +37 -0
  184. dsp_tools/commands/xmlupload/stash/__init__.py +0 -0
  185. dsp_tools/commands/xmlupload/stash/analyse_circular_reference_graph.py +236 -0
  186. dsp_tools/commands/xmlupload/stash/create_info_for_graph.py +53 -0
  187. dsp_tools/commands/xmlupload/stash/graph_models.py +87 -0
  188. dsp_tools/commands/xmlupload/stash/stash_circular_references.py +68 -0
  189. dsp_tools/commands/xmlupload/stash/stash_models.py +109 -0
  190. dsp_tools/commands/xmlupload/stash/upload_stashed_resptr_props.py +106 -0
  191. dsp_tools/commands/xmlupload/stash/upload_stashed_xml_texts.py +196 -0
  192. dsp_tools/commands/xmlupload/upload_config.py +76 -0
  193. dsp_tools/commands/xmlupload/write_diagnostic_info.py +27 -0
  194. dsp_tools/commands/xmlupload/xmlupload.py +516 -0
  195. dsp_tools/config/__init__.py +0 -0
  196. dsp_tools/config/logger_config.py +69 -0
  197. dsp_tools/config/warnings_config.py +32 -0
  198. dsp_tools/error/__init__.py +0 -0
  199. dsp_tools/error/custom_warnings.py +39 -0
  200. dsp_tools/error/exceptions.py +204 -0
  201. dsp_tools/error/problems.py +10 -0
  202. dsp_tools/error/xmllib_errors.py +20 -0
  203. dsp_tools/error/xmllib_warnings.py +54 -0
  204. dsp_tools/error/xmllib_warnings_util.py +159 -0
  205. dsp_tools/error/xsd_validation_error_msg.py +19 -0
  206. dsp_tools/legacy_models/__init__.py +0 -0
  207. dsp_tools/legacy_models/datetimestamp.py +81 -0
  208. dsp_tools/legacy_models/langstring.py +253 -0
  209. dsp_tools/legacy_models/projectContext.py +49 -0
  210. dsp_tools/py.typed +0 -0
  211. dsp_tools/resources/schema/data.xsd +648 -0
  212. dsp_tools/resources/schema/lists-only.json +72 -0
  213. dsp_tools/resources/schema/project.json +1258 -0
  214. dsp_tools/resources/schema/properties-only.json +874 -0
  215. dsp_tools/resources/schema/resources-only.json +140 -0
  216. dsp_tools/resources/start-stack/docker-compose.override-host.j2 +11 -0
  217. dsp_tools/resources/start-stack/docker-compose.override.yml +11 -0
  218. dsp_tools/resources/start-stack/docker-compose.yml +88 -0
  219. dsp_tools/resources/start-stack/dsp-app-config.json +45 -0
  220. dsp_tools/resources/start-stack/dsp-app-config.override-host.j2 +26 -0
  221. dsp_tools/resources/validate_data/api-shapes-resource-cardinalities.ttl +191 -0
  222. dsp_tools/resources/validate_data/api-shapes.ttl +804 -0
  223. dsp_tools/resources/validate_data/shacl-cli-image.yml +4 -0
  224. dsp_tools/resources/validate_data/validate-ontology.ttl +99 -0
  225. dsp_tools/utils/__init__.py +0 -0
  226. dsp_tools/utils/ansi_colors.py +32 -0
  227. dsp_tools/utils/data_formats/__init__.py +0 -0
  228. dsp_tools/utils/data_formats/date_util.py +166 -0
  229. dsp_tools/utils/data_formats/iri_util.py +30 -0
  230. dsp_tools/utils/data_formats/shared.py +81 -0
  231. dsp_tools/utils/data_formats/uri_util.py +76 -0
  232. dsp_tools/utils/fuseki_bloating.py +63 -0
  233. dsp_tools/utils/json_parsing.py +22 -0
  234. dsp_tools/utils/rdf_constants.py +42 -0
  235. dsp_tools/utils/rdflib_utils.py +10 -0
  236. dsp_tools/utils/replace_id_with_iri.py +66 -0
  237. dsp_tools/utils/request_utils.py +238 -0
  238. dsp_tools/utils/xml_parsing/__init__.py +0 -0
  239. dsp_tools/utils/xml_parsing/get_lookups.py +32 -0
  240. dsp_tools/utils/xml_parsing/get_parsed_resources.py +325 -0
  241. dsp_tools/utils/xml_parsing/models/__init__.py +0 -0
  242. dsp_tools/utils/xml_parsing/models/parsed_resource.py +76 -0
  243. dsp_tools/utils/xml_parsing/parse_clean_validate_xml.py +137 -0
  244. dsp_tools/xmllib/CLAUDE.md +302 -0
  245. dsp_tools/xmllib/__init__.py +49 -0
  246. dsp_tools/xmllib/general_functions.py +877 -0
  247. dsp_tools/xmllib/internal/__init__.py +0 -0
  248. dsp_tools/xmllib/internal/checkers.py +162 -0
  249. dsp_tools/xmllib/internal/circumvent_circular_imports.py +36 -0
  250. dsp_tools/xmllib/internal/constants.py +46 -0
  251. dsp_tools/xmllib/internal/input_converters.py +155 -0
  252. dsp_tools/xmllib/internal/serialise_file_value.py +57 -0
  253. dsp_tools/xmllib/internal/serialise_resource.py +177 -0
  254. dsp_tools/xmllib/internal/serialise_values.py +152 -0
  255. dsp_tools/xmllib/internal/type_aliases.py +11 -0
  256. dsp_tools/xmllib/models/__init__.py +0 -0
  257. dsp_tools/xmllib/models/config_options.py +28 -0
  258. dsp_tools/xmllib/models/date_formats.py +48 -0
  259. dsp_tools/xmllib/models/dsp_base_resources.py +1542 -0
  260. dsp_tools/xmllib/models/internal/__init__.py +0 -0
  261. dsp_tools/xmllib/models/internal/file_values.py +172 -0
  262. dsp_tools/xmllib/models/internal/geometry.py +162 -0
  263. dsp_tools/xmllib/models/internal/migration_metadata.py +55 -0
  264. dsp_tools/xmllib/models/internal/serialise_permissions.py +66 -0
  265. dsp_tools/xmllib/models/internal/values.py +342 -0
  266. dsp_tools/xmllib/models/licenses/__init__.py +0 -0
  267. dsp_tools/xmllib/models/licenses/other.py +59 -0
  268. dsp_tools/xmllib/models/licenses/recommended.py +107 -0
  269. dsp_tools/xmllib/models/permissions.py +41 -0
  270. dsp_tools/xmllib/models/res.py +1782 -0
  271. dsp_tools/xmllib/models/root.py +348 -0
  272. dsp_tools/xmllib/value_checkers.py +434 -0
  273. dsp_tools/xmllib/value_converters.py +777 -0
  274. dsp_tools-18.3.0.post13.dist-info/METADATA +90 -0
  275. dsp_tools-18.3.0.post13.dist-info/RECORD +286 -0
  276. dsp_tools-18.3.0.post13.dist-info/WHEEL +4 -0
  277. dsp_tools-18.3.0.post13.dist-info/entry_points.txt +3 -0
  278. dsp_tools-0.9.13.dist-info/LICENSE +0 -674
  279. dsp_tools-0.9.13.dist-info/METADATA +0 -144
  280. dsp_tools-0.9.13.dist-info/RECORD +0 -71
  281. dsp_tools-0.9.13.dist-info/WHEEL +0 -5
  282. dsp_tools-0.9.13.dist-info/entry_points.txt +0 -3
  283. dsp_tools-0.9.13.dist-info/top_level.txt +0 -1
  284. dsplib/models/connection.py +0 -272
  285. dsplib/models/group.py +0 -296
  286. dsplib/models/helpers.py +0 -505
  287. dsplib/models/langstring.py +0 -277
  288. dsplib/models/listnode.py +0 -578
  289. dsplib/models/model.py +0 -20
  290. dsplib/models/ontology.py +0 -448
  291. dsplib/models/permission.py +0 -112
  292. dsplib/models/project.py +0 -547
  293. dsplib/models/propertyclass.py +0 -505
  294. dsplib/models/resource.py +0 -366
  295. dsplib/models/resourceclass.py +0 -810
  296. dsplib/models/sipi.py +0 -30
  297. dsplib/models/user.py +0 -731
  298. dsplib/models/value.py +0 -1000
  299. dsplib/utils/knora-data-schema.xsd +0 -454
  300. dsplib/utils/knora-schema-lists.json +0 -83
  301. dsplib/utils/knora-schema.json +0 -434
  302. dsplib/utils/onto_commons.py +0 -24
  303. dsplib/utils/onto_create_lists.py +0 -73
  304. dsplib/utils/onto_create_ontology.py +0 -442
  305. dsplib/utils/onto_get.py +0 -58
  306. dsplib/utils/onto_validate.py +0 -33
  307. dsplib/utils/xml_upload.py +0 -539
  308. dsplib/widgets/doublepassword.py +0 -80
  309. knora/MLS-import-libraries.py +0 -84
  310. knora/dsp_tools.py +0 -96
  311. knora/dsplib/models/connection.py +0 -272
  312. knora/dsplib/models/group.py +0 -296
  313. knora/dsplib/models/helpers.py +0 -506
  314. knora/dsplib/models/langstring.py +0 -277
  315. knora/dsplib/models/listnode.py +0 -578
  316. knora/dsplib/models/model.py +0 -20
  317. knora/dsplib/models/ontology.py +0 -448
  318. knora/dsplib/models/permission.py +0 -112
  319. knora/dsplib/models/project.py +0 -583
  320. knora/dsplib/models/propertyclass.py +0 -505
  321. knora/dsplib/models/resource.py +0 -416
  322. knora/dsplib/models/resourceclass.py +0 -811
  323. knora/dsplib/models/sipi.py +0 -35
  324. knora/dsplib/models/user.py +0 -731
  325. knora/dsplib/models/value.py +0 -1000
  326. knora/dsplib/utils/knora-data-schema.xsd +0 -464
  327. knora/dsplib/utils/knora-schema-lists.json +0 -83
  328. knora/dsplib/utils/knora-schema.json +0 -444
  329. knora/dsplib/utils/onto_commons.py +0 -24
  330. knora/dsplib/utils/onto_create_lists.py +0 -73
  331. knora/dsplib/utils/onto_create_ontology.py +0 -451
  332. knora/dsplib/utils/onto_get.py +0 -58
  333. knora/dsplib/utils/onto_validate.py +0 -33
  334. knora/dsplib/utils/xml_upload.py +0 -540
  335. knora/dsplib/widgets/doublepassword.py +0 -80
  336. knora/knora.py +0 -2108
  337. knora/test.py +0 -99
  338. knora/testit.py +0 -76
  339. knora/xml2knora.py +0 -633
  340. {dsplib → dsp_tools/cli}/__init__.py +0 -0
  341. {dsplib/models → dsp_tools/clients}/__init__.py +0 -0
  342. {dsplib/utils → dsp_tools/commands}/__init__.py +0 -0
  343. {dsplib/widgets → dsp_tools/commands/create}/__init__.py +0 -0
  344. {knora → dsp_tools/commands/create/create_on_server}/__init__.py +0 -0
  345. {knora/dsplib → dsp_tools/commands/create/models}/__init__.py +0 -0
  346. {knora/dsplib/models → dsp_tools/commands/create/parsing}/__init__.py +0 -0
  347. {knora/dsplib/utils → dsp_tools/commands/create/serialisation}/__init__.py +0 -0
  348. {knora/dsplib/widgets → dsp_tools/commands/excel2json}/__init__.py +0 -0
@@ -0,0 +1,262 @@
1
+ from typing import Union
2
+
3
+ from rdflib import RDF
4
+ from rdflib import XSD
5
+ from rdflib import BNode
6
+ from rdflib import Graph
7
+ from rdflib import Literal
8
+ from rdflib import URIRef
9
+
10
+ from dsp_tools.commands.xmlupload.iri_resolver import IriResolver
11
+ from dsp_tools.commands.xmlupload.make_rdf_graph.constants import LINK_PROP_TYPE_INFO
12
+ from dsp_tools.commands.xmlupload.make_rdf_graph.constants import LIST_PROP_TYPE_INFO
13
+ from dsp_tools.commands.xmlupload.make_rdf_graph.constants import RDF_LITERAL_PROP_TYPE_MAPPER
14
+ from dsp_tools.commands.xmlupload.make_rdf_graph.constants import RICHTEXT_PROP_TYPE_INFO
15
+ from dsp_tools.commands.xmlupload.models.lookup_models import IRILookups
16
+ from dsp_tools.commands.xmlupload.models.permission import Permissions
17
+ from dsp_tools.commands.xmlupload.models.processed.values import ProcessedBoolean
18
+ from dsp_tools.commands.xmlupload.models.processed.values import ProcessedColor
19
+ from dsp_tools.commands.xmlupload.models.processed.values import ProcessedDate
20
+ from dsp_tools.commands.xmlupload.models.processed.values import ProcessedDecimal
21
+ from dsp_tools.commands.xmlupload.models.processed.values import ProcessedGeometry
22
+ from dsp_tools.commands.xmlupload.models.processed.values import ProcessedGeoname
23
+ from dsp_tools.commands.xmlupload.models.processed.values import ProcessedInt
24
+ from dsp_tools.commands.xmlupload.models.processed.values import ProcessedInterval
25
+ from dsp_tools.commands.xmlupload.models.processed.values import ProcessedLink
26
+ from dsp_tools.commands.xmlupload.models.processed.values import ProcessedList
27
+ from dsp_tools.commands.xmlupload.models.processed.values import ProcessedRichtext
28
+ from dsp_tools.commands.xmlupload.models.processed.values import ProcessedSimpleText
29
+ from dsp_tools.commands.xmlupload.models.processed.values import ProcessedTime
30
+ from dsp_tools.commands.xmlupload.models.processed.values import ProcessedUri
31
+ from dsp_tools.commands.xmlupload.models.processed.values import ProcessedValue
32
+ from dsp_tools.commands.xmlupload.models.rdf_models import RDFPropTypeInfo
33
+ from dsp_tools.commands.xmlupload.richtext_id2iri import prepare_richtext_string_for_upload
34
+ from dsp_tools.config.logger_config import WARNINGS_SAVEPATH
35
+ from dsp_tools.error.exceptions import BaseError
36
+ from dsp_tools.error.exceptions import InputError
37
+ from dsp_tools.utils.data_formats.date_util import DayMonthYearEra
38
+ from dsp_tools.utils.data_formats.date_util import SingleDate
39
+ from dsp_tools.utils.data_formats.date_util import StartEnd
40
+ from dsp_tools.utils.data_formats.iri_util import is_resource_iri
41
+ from dsp_tools.utils.rdf_constants import KNORA_API
42
+
43
+ type LiteralValueTypesAlias = Union[
44
+ ProcessedBoolean,
45
+ ProcessedColor,
46
+ ProcessedDecimal,
47
+ ProcessedGeoname,
48
+ ProcessedGeometry,
49
+ ProcessedInt,
50
+ ProcessedSimpleText,
51
+ ProcessedTime,
52
+ ProcessedUri,
53
+ ]
54
+
55
+
56
+ def make_values(values: list[ProcessedValue], res_node: BNode | URIRef, lookups: IRILookups) -> Graph:
57
+ """
58
+ Serialise the values of a resource.
59
+
60
+ Args:
61
+ values: list of ProcessedValues of the resource
62
+ res_node: node of the resource
63
+ lookups: lookups to resolve IRIs
64
+
65
+ Returns:
66
+ Graph with the values
67
+ """
68
+ properties_graph = Graph()
69
+ for val in values:
70
+ single_prop_graph = _make_one_value_graph(val=val, res_node=res_node, iri_lookups=lookups)
71
+ properties_graph += single_prop_graph
72
+ return properties_graph
73
+
74
+
75
+ def _make_one_value_graph(val: ProcessedValue, res_node: BNode | URIRef, iri_lookups: IRILookups) -> Graph:
76
+ match val:
77
+ case (
78
+ ProcessedBoolean()
79
+ | ProcessedColor()
80
+ | ProcessedDecimal()
81
+ | ProcessedGeometry()
82
+ | ProcessedGeoname()
83
+ | ProcessedInt()
84
+ | ProcessedTime()
85
+ | ProcessedUri()
86
+ | ProcessedSimpleText()
87
+ ):
88
+ literal_info = RDF_LITERAL_PROP_TYPE_MAPPER[type(val)]
89
+ properties_graph = _make_value_graph_with_literal_object(
90
+ val=val,
91
+ res_node=res_node,
92
+ prop_type_info=literal_info,
93
+ )
94
+ case ProcessedList():
95
+ properties_graph = _make_list_value_graph(val=val, res_node=res_node, prop_type_info=LIST_PROP_TYPE_INFO)
96
+ case ProcessedLink():
97
+ target_iri = _resolve_id_to_iri(val.value, iri_lookups.id_to_iri)
98
+ properties_graph = make_link_value_graph(
99
+ val=val,
100
+ val_node=BNode(),
101
+ res_node=res_node,
102
+ target_iri=URIRef(target_iri),
103
+ )
104
+ case ProcessedRichtext():
105
+ properties_graph = make_richtext_value_graph(
106
+ val=val,
107
+ val_node=BNode(),
108
+ res_node=res_node,
109
+ iri_resolver=iri_lookups.id_to_iri,
110
+ )
111
+ case ProcessedDate():
112
+ properties_graph = _make_date_value_graph(
113
+ val=val,
114
+ res_node=res_node,
115
+ )
116
+ case ProcessedInterval():
117
+ properties_graph = _make_interval_value_graph(
118
+ val=val,
119
+ res_node=res_node,
120
+ )
121
+ case _:
122
+ raise InputError(f"Unknown value type: {type(val).__name__}")
123
+ return properties_graph
124
+
125
+
126
+ def _make_base_value_graph(
127
+ val: ProcessedValue,
128
+ val_node: BNode | URIRef,
129
+ prop_type_info: RDFPropTypeInfo,
130
+ res_node: BNode | URIRef,
131
+ ) -> Graph:
132
+ g = _add_optional_triples(val_node, val.permissions, val.comment)
133
+ g.add((res_node, URIRef(val.prop_iri), val_node))
134
+ g.add((val_node, RDF.type, prop_type_info.knora_type))
135
+ return g
136
+
137
+
138
+ def _add_optional_triples(val_bn: BNode | URIRef, permissions: Permissions | None, comment: str | None) -> Graph:
139
+ g = Graph()
140
+ if permissions:
141
+ g.add((val_bn, KNORA_API.hasPermissions, Literal(str(permissions), datatype=XSD.string)))
142
+ if comment:
143
+ g.add((val_bn, KNORA_API.valueHasComment, Literal(comment, datatype=XSD.string)))
144
+ return g
145
+
146
+
147
+ def _make_value_graph_with_literal_object(
148
+ val: LiteralValueTypesAlias,
149
+ prop_type_info: RDFPropTypeInfo,
150
+ res_node: BNode | URIRef,
151
+ ) -> Graph:
152
+ val_bn = BNode()
153
+ g = _make_base_value_graph(val=val, val_node=val_bn, prop_type_info=prop_type_info, res_node=res_node)
154
+ g.add((val_bn, prop_type_info.knora_prop, Literal(val.value, datatype=prop_type_info.xsd_type)))
155
+ return g
156
+
157
+
158
+ def _make_list_value_graph(
159
+ val: ProcessedList,
160
+ res_node: BNode | URIRef,
161
+ prop_type_info: RDFPropTypeInfo,
162
+ ) -> Graph:
163
+ val_bn = BNode()
164
+ g = _make_base_value_graph(val=val, val_node=val_bn, prop_type_info=prop_type_info, res_node=res_node)
165
+ g.add((val_bn, prop_type_info.knora_prop, URIRef(val.value)))
166
+ return g
167
+
168
+
169
+ def make_link_value_graph(
170
+ val: ProcessedLink,
171
+ val_node: BNode | URIRef,
172
+ res_node: BNode | URIRef,
173
+ target_iri: URIRef,
174
+ ) -> Graph:
175
+ """Make a LinkValue Graph"""
176
+ g = _make_base_value_graph(val=val, val_node=val_node, prop_type_info=LINK_PROP_TYPE_INFO, res_node=res_node)
177
+ g.add((val_node, LINK_PROP_TYPE_INFO.knora_prop, target_iri))
178
+ return g
179
+
180
+
181
+ def _resolve_id_to_iri(value: str, iri_resolver: IriResolver) -> URIRef:
182
+ if is_resource_iri(value):
183
+ return URIRef(value)
184
+ elif resolved_iri := iri_resolver.get(value):
185
+ return URIRef(resolved_iri)
186
+ msg = (
187
+ f"Could not find the ID {value} in the id2iri mapping. "
188
+ f"This is probably because the resource '{value}' could not be created. "
189
+ f"See {WARNINGS_SAVEPATH} for more information."
190
+ )
191
+ raise BaseError(msg)
192
+
193
+
194
+ def _make_date_value_graph(
195
+ val: ProcessedDate,
196
+ res_node: BNode | URIRef,
197
+ ) -> Graph:
198
+ val_bn = BNode()
199
+ date = val.value
200
+ g = _add_optional_triples(val_bn, val.permissions, val.comment)
201
+ g.add((res_node, URIRef(val.prop_iri), val_bn))
202
+ g.add((val_bn, RDF.type, KNORA_API.DateValue))
203
+ if cal := date.calendar:
204
+ g.add((val_bn, KNORA_API.dateValueHasCalendar, Literal(cal.value, datatype=XSD.string)))
205
+ g += _make_single_date_graph(val_bn, date.start, StartEnd.START)
206
+ if date.end:
207
+ g += _make_single_date_graph(val_bn, date.end, StartEnd.END)
208
+ return g
209
+
210
+
211
+ def _make_single_date_graph(val_bn: BNode, date: SingleDate, start_end: StartEnd) -> Graph:
212
+ def get_prop(precision: DayMonthYearEra) -> URIRef:
213
+ return KNORA_API[f"dateValueHas{start_end.value}{precision.value}"]
214
+
215
+ g = Graph()
216
+ if yr := date.year:
217
+ g.add((val_bn, get_prop(DayMonthYearEra.YEAR), Literal(yr, datatype=XSD.integer)))
218
+ if mnt := date.month:
219
+ g.add((val_bn, get_prop(DayMonthYearEra.MONTH), Literal(mnt, datatype=XSD.integer)))
220
+ if day := date.day:
221
+ g.add((val_bn, get_prop(DayMonthYearEra.DAY), Literal(day, datatype=XSD.integer)))
222
+ if era := date.era:
223
+ g.add((val_bn, get_prop(DayMonthYearEra.ERA), Literal(era.value, datatype=XSD.string)))
224
+ return g
225
+
226
+
227
+ def _make_interval_value_graph(
228
+ val: ProcessedInterval,
229
+ res_node: BNode | URIRef,
230
+ ) -> Graph:
231
+ val_bn = BNode()
232
+ g = _add_optional_triples(val_bn, val.permissions, val.comment)
233
+ g.add((res_node, URIRef(val.prop_iri), val_bn))
234
+ g.add((val_bn, RDF.type, KNORA_API.IntervalValue))
235
+ g.add((val_bn, KNORA_API.intervalValueHasStart, Literal(val.value.start, datatype=XSD.decimal)))
236
+ g.add((val_bn, KNORA_API.intervalValueHasEnd, Literal(val.value.end, datatype=XSD.decimal)))
237
+ return g
238
+
239
+
240
+ def make_richtext_value_graph(
241
+ val: ProcessedRichtext,
242
+ val_node: BNode | URIRef,
243
+ res_node: BNode | URIRef,
244
+ iri_resolver: IriResolver,
245
+ ) -> Graph:
246
+ """
247
+ Creates an rdflib graph for a richtext value.
248
+
249
+ Args:
250
+ val: Richtext value
251
+ val_node: IRI or blank node of the value
252
+ res_node: IRI or blank node of the resource
253
+ iri_resolver: id to IRI resolver
254
+
255
+ Returns:
256
+ Graph
257
+ """
258
+ g = _make_base_value_graph(val=val, val_node=val_node, prop_type_info=RICHTEXT_PROP_TYPE_INFO, res_node=res_node)
259
+ val_str = prepare_richtext_string_for_upload(val.value.xmlstr, iri_resolver)
260
+ g.add((val_node, RICHTEXT_PROP_TYPE_INFO.knora_prop, Literal(val_str, datatype=XSD.string)))
261
+ g.add((val_node, KNORA_API.textValueHasMapping, URIRef("http://rdfh.ch/standoff/mappings/StandardMapping")))
262
+ return g
File without changes
@@ -0,0 +1,18 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+
5
+ from dsp_tools.commands.xmlupload.models.permission import Permissions
6
+
7
+
8
+ @dataclass(frozen=True)
9
+ class BitstreamInfo:
10
+ """
11
+ Represents a bitstream object,
12
+ consisting of its file name on the local file system,
13
+ the internal file name assigned by the ingest service
14
+ and optionally its permissions.
15
+ """
16
+
17
+ internal_file_name: str
18
+ permissions: Permissions | None = None
@@ -0,0 +1,10 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+
5
+
6
+ @dataclass
7
+ class FormattedTextValue:
8
+ """Represents a formatted text value with standard standoff markup"""
9
+
10
+ xmlstr: str
@@ -0,0 +1,143 @@
1
+ from __future__ import annotations
2
+
3
+ import urllib
4
+ from dataclasses import dataclass
5
+ from dataclasses import field
6
+ from http import HTTPStatus
7
+ from pathlib import Path
8
+ from typing import Protocol
9
+
10
+ import requests
11
+ from loguru import logger
12
+ from requests import Session
13
+ from requests.adapters import HTTPAdapter
14
+ from requests.adapters import Retry
15
+
16
+ from dsp_tools.clients.authentication_client import AuthenticationClient
17
+ from dsp_tools.commands.xmlupload.models.bitstream_info import BitstreamInfo
18
+ from dsp_tools.commands.xmlupload.models.processed.file_values import ProcessedFileValue
19
+ from dsp_tools.error.exceptions import BadCredentialsError
20
+ from dsp_tools.error.exceptions import InvalidIngestFileNameError
21
+ from dsp_tools.error.exceptions import PermanentConnectionError
22
+ from dsp_tools.utils.request_utils import RequestParameters
23
+ from dsp_tools.utils.request_utils import log_request
24
+ from dsp_tools.utils.request_utils import log_response
25
+
26
+
27
+ @dataclass(frozen=True)
28
+ class IngestResponse:
29
+ """Wrapper around `internal_filename`"""
30
+
31
+ internal_filename: str
32
+
33
+
34
+ class AssetClient(Protocol):
35
+ """Protocol for asset handling clients."""
36
+
37
+ def get_bitstream_info(self, file_info: ProcessedFileValue) -> BitstreamInfo | None:
38
+ """Uploads the file to the ingest server if applicable, and returns the upload results.
39
+
40
+ Args:
41
+ file_info: Information required for ingesting an asset
42
+ """
43
+
44
+
45
+ @dataclass
46
+ class DspIngestClientLive(AssetClient):
47
+ """Client for uploading assets to the DSP-Ingest."""
48
+
49
+ dsp_ingest_url: str
50
+ authentication_client: AuthenticationClient
51
+ shortcode: str
52
+ imgdir: str
53
+ session: Session = field(init=False)
54
+
55
+ def __post_init__(self) -> None:
56
+ retries = 6
57
+ self.session = Session()
58
+ retry = Retry(
59
+ total=retries,
60
+ read=retries,
61
+ connect=retries,
62
+ backoff_factor=0.3,
63
+ allowed_methods=None, # means all methods
64
+ status_forcelist=[HTTPStatus.INTERNAL_SERVER_ERROR.value],
65
+ )
66
+ adapter = HTTPAdapter(max_retries=retry)
67
+ self.session.mount("http://", adapter)
68
+ self.session.mount("https://", adapter)
69
+
70
+ def _ingest(self, filepath: Path) -> IngestResponse:
71
+ """Uploads a file to the ingest server and returns the IngestResponse.
72
+
73
+ This function sends a POST request to the ingest server with the file to upload.
74
+ It will retry the request 6 times in case of a connection, timeout or internal server error.
75
+
76
+ After all retry attempts are exhausted it will raise exceptions if the upload failed.
77
+ The http status code is also checked and if it is not 200, a PermanentConnectionError is raised.
78
+
79
+ The load balancer on DSP servers currently has a timeout of 10m,
80
+ so we need to use a slightly shorter timeout of 9m.
81
+ See https://linear.app/dasch/issue/INFRA-847/increase-traefik-readtimeout
82
+
83
+ Args:
84
+ filepath: Path to the file to ingest, could be either absolute or relative.
85
+
86
+ Raises:
87
+ BadCredentialsError: If the credentials are invalid.
88
+ PermanentConnectionError: If the connection fails.
89
+
90
+ Returns:
91
+ IngestResponse: The internal filename of the uploaded file.
92
+ """
93
+ filename = urllib.parse.quote(filepath.name)
94
+ url = f"{self.dsp_ingest_url}/projects/{self.shortcode}/assets/ingest/{filename}"
95
+ headers = {
96
+ "Authorization": f"Bearer {self.authentication_client.get_token()}",
97
+ "Content-Type": "application/octet-stream",
98
+ }
99
+ timeout = 9 * 60
100
+ params = RequestParameters(method="POST", url=url, timeout=timeout, headers=headers)
101
+ with open(filepath, "rb") as binary_io:
102
+ try:
103
+ log_request(params)
104
+ res = self.session.post(
105
+ url=params.url,
106
+ headers=params.headers,
107
+ data=binary_io,
108
+ timeout=params.timeout,
109
+ )
110
+ log_response(res)
111
+ except requests.exceptions.RequestException as e:
112
+ raise PermanentConnectionError() from e
113
+
114
+ if res.ok:
115
+ return IngestResponse(internal_filename=res.json()["internalFilename"])
116
+ elif res.status_code == HTTPStatus.FORBIDDEN:
117
+ raise BadCredentialsError("Only SystemAdmins and ProjectAdmins can upload assets.")
118
+ elif res.status_code == HTTPStatus.BAD_REQUEST and res.text == "Invalid value for: path parameter filename":
119
+ raise InvalidIngestFileNameError()
120
+ else:
121
+ raise PermanentConnectionError()
122
+
123
+ def get_bitstream_info(self, file_info: ProcessedFileValue) -> BitstreamInfo | None:
124
+ """Uploads a file to the ingest server and returns the upload results."""
125
+ try:
126
+ res = self._ingest(Path(self.imgdir) / Path(file_info.value))
127
+ logger.info(f"Uploaded file '{file_info.value}'")
128
+ return BitstreamInfo(res.internal_filename, file_info.metadata.permissions)
129
+ except InvalidIngestFileNameError:
130
+ msg = f"Invalid filename: Unable to upload file '{file_info.value}' of resource '{file_info.res_id}'"
131
+ except PermanentConnectionError:
132
+ msg = f"Unable to upload file '{file_info.value}' of resource '{file_info.res_id}'"
133
+ logger.error(msg)
134
+ return None
135
+
136
+
137
+ @dataclass(frozen=True)
138
+ class BulkIngestedAssetClient(AssetClient):
139
+ """Client for handling media info, if the assets were bulk ingested previously."""
140
+
141
+ def get_bitstream_info(self, file_info: ProcessedFileValue) -> BitstreamInfo:
142
+ """Returns the BitstreamInfo of the already ingested file based on the `ProcessedFileValue.value`."""
143
+ return BitstreamInfo(file_info.value, file_info.metadata.permissions)
@@ -0,0 +1,58 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+
5
+ list_separator = "\n - "
6
+ medium_separator = "\n----------------------------\n"
7
+
8
+ HTTP_OK = 200
9
+
10
+
11
+ @dataclass(frozen=True)
12
+ class AllIIIFUriProblems:
13
+ """Information about all problems with IIIF URIs."""
14
+
15
+ problems: list[IIIFUriProblem]
16
+
17
+ def get_msg(self) -> str:
18
+ """Get a message describing all problems with the IIIF URIs."""
19
+ msg = "There were problems with the following IIIF URI(s):"
20
+ all_msg = [problem.get_msg() for problem in self.problems]
21
+ return msg + medium_separator + medium_separator.join(all_msg)
22
+
23
+
24
+ @dataclass(frozen=True)
25
+ class IIIFUriProblem:
26
+ """Information about a problem with an IIIF URI."""
27
+
28
+ uri: str
29
+ regex_has_passed: bool
30
+ status_code: int | None = None
31
+ raised_exception_name: str | None = None
32
+
33
+ def get_msg(self) -> str:
34
+ """Get a message describing the problem with the IIIF URI."""
35
+ msg = [f"URI: {self.uri}"]
36
+ if self.regex_has_passed:
37
+ msg.append("Passed the internal regex check.")
38
+ else:
39
+ msg.append("Did not pass the internal regex check.")
40
+ if self.status_code == HTTP_OK:
41
+ msg.extend(self._good_status_code_bad_regex_msg())
42
+ elif self.status_code is not None:
43
+ msg.extend(self._bad_status_code_msg())
44
+ else:
45
+ msg.append(self._exception_msg())
46
+ return list_separator.join(msg)
47
+
48
+ def _exception_msg(self) -> str:
49
+ return f"An error occurred during the network call: {self.raised_exception_name}"
50
+
51
+ def _bad_status_code_msg(self) -> list[str]:
52
+ return ["The server did not respond as expected.", f"Status code: {self.status_code}"]
53
+
54
+ def _good_status_code_bad_regex_msg(self) -> list[str]:
55
+ return [
56
+ "Although the IIIF-server responded as expected, this URI did not pass validation.",
57
+ "Please contact the dsp-tools development team (at support@dasch.swiss) with this information.",
58
+ ]
@@ -0,0 +1,21 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+
5
+ from rdflib import URIRef
6
+
7
+ from dsp_tools.commands.xmlupload.iri_resolver import IriResolver
8
+ from dsp_tools.commands.xmlupload.models.permission import Permissions
9
+
10
+
11
+ @dataclass
12
+ class XmlReferenceLookups:
13
+ permissions: dict[str, Permissions]
14
+ listnodes: dict[tuple[str, str], str]
15
+ authorships: dict[str, list[str]]
16
+
17
+
18
+ @dataclass
19
+ class IRILookups:
20
+ project_iri: URIRef
21
+ id_to_iri: IriResolver
@@ -0,0 +1,45 @@
1
+ from __future__ import annotations
2
+
3
+ from enum import Enum
4
+ from enum import unique
5
+ from typing import Optional
6
+
7
+
8
+ @unique
9
+ class PermissionValue(Enum):
10
+ RV = 1
11
+ V = 2
12
+ M = 4
13
+ D = 8
14
+ CR = 16
15
+
16
+ def __str__(self) -> str:
17
+ tmp = {
18
+ 1: "RV",
19
+ 2: "V",
20
+ 4: "M",
21
+ 8: "D",
22
+ 16: "CR",
23
+ }
24
+ return tmp[self.value]
25
+
26
+
27
+ class Permissions:
28
+ _permissions: dict[PermissionValue, list[str]]
29
+
30
+ def __init__(self, permissions: Optional[dict[PermissionValue, list[str]]] = None):
31
+ self._permissions = permissions or {}
32
+
33
+ def __str__(self) -> str:
34
+ tmpstr = ""
35
+ for permission, groups in self._permissions.items():
36
+ if tmpstr:
37
+ tmpstr += "|"
38
+ tmpstr += f"{permission!s} " + ",".join(groups)
39
+ return tmpstr
40
+
41
+ def add(self, key: PermissionValue, val: str) -> None:
42
+ if self._permissions.get(key) is None:
43
+ self._permissions[key] = [val]
44
+ else:
45
+ self._permissions[key].append(val)
@@ -0,0 +1,93 @@
1
+ from __future__ import annotations
2
+
3
+ from lxml import etree
4
+
5
+ from dsp_tools.commands.xmlupload.models.permission import Permissions
6
+ from dsp_tools.commands.xmlupload.models.permission import PermissionValue
7
+ from dsp_tools.error.exceptions import XmlUploadError
8
+ from dsp_tools.legacy_models.projectContext import ProjectContext
9
+
10
+
11
+ class XmlPermission:
12
+ """Represents the permission set containing several XmlAllow elements in the XML used for data import"""
13
+
14
+ permission_id: str
15
+ _allows: list[XmlAllow]
16
+
17
+ def __init__(self, node: etree._Element, project_context: ProjectContext) -> None:
18
+ """
19
+ Constructor which parses a XML DOM permissions element representing an named permission set
20
+
21
+ Args:
22
+ node: The DOM node to be processed (representing an a permission set)
23
+ project_context: Context for DOM node traversal
24
+ """
25
+ self._allows = []
26
+ self.permission_id = node.attrib["id"]
27
+ self._allows.extend(XmlAllow(allow_node, project_context) for allow_node in node)
28
+
29
+ def get_permission_instance(self) -> Permissions:
30
+ """Returns a list of allow elements of this permission instance"""
31
+ permissions = Permissions()
32
+ for allow in self._allows:
33
+ permissions.add(allow.permission, allow.group)
34
+ return permissions
35
+
36
+ def __str__(self) -> str:
37
+ allow_str: list[str] = [f"{allow.permission} {allow.group}" for allow in self._allows]
38
+ return "|".join(allow_str)
39
+
40
+
41
+ class XmlAllow:
42
+ """Represents the allow element of the XML used for data import"""
43
+
44
+ _group: str
45
+ _permission: PermissionValue
46
+
47
+ def __init__(self, node: etree._Element, project_context: ProjectContext) -> None:
48
+ """
49
+ Constructor which parses the XML DOM allow element
50
+
51
+ Args:
52
+ node: The DOM node to be processed (represents a single right in a permission set)
53
+ project_context: Context for DOM node traversal
54
+
55
+ Raises:
56
+ XmlUploadError: If an upload fails
57
+ """
58
+ tmp = node.attrib["group"].split(":")
59
+
60
+ sysgroups = ["UnknownUser", "KnownUser", "ProjectMember", "Creator", "ProjectAdmin", "SystemAdmin"]
61
+ if len(tmp) > 1:
62
+ if tmp[0]:
63
+ if tmp[0] == "knora-admin" and tmp[1] in sysgroups:
64
+ self._group = node.attrib["group"]
65
+ else:
66
+ _group = project_context.group_map.get(node.attrib["group"])
67
+ if _group is None:
68
+ raise XmlUploadError(f'Group "{node.attrib["group"]}" is not known: Cannot find project!')
69
+ self._group = _group
70
+ elif project_context.project_name is None:
71
+ raise XmlUploadError("Project shortname has not been set in ProjectContext")
72
+ else:
73
+ prefixed_custom_groupname = f"{project_context.project_name}:{tmp[1]}"
74
+ if _group := project_context.group_map.get(prefixed_custom_groupname):
75
+ self._group = _group
76
+ elif tmp[0] in sysgroups:
77
+ self._group = "knora-admin:" + node.attrib["group"]
78
+ else:
79
+ raise XmlUploadError(f'Group "{node.attrib["group"]}" is not known: ')
80
+
81
+ if not node.text:
82
+ raise XmlUploadError("No permission set specified")
83
+ self._permission = PermissionValue[node.text]
84
+
85
+ @property
86
+ def group(self) -> str:
87
+ """The group specified in the allow element"""
88
+ return self._group
89
+
90
+ @property
91
+ def permission(self) -> PermissionValue:
92
+ """The reference to a set of permissions"""
93
+ return self._permission
@@ -0,0 +1,29 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+
5
+ from dsp_tools.commands.xmlupload.models.permission import Permissions
6
+ from dsp_tools.utils.xml_parsing.models.parsed_resource import KnoraValueType
7
+
8
+
9
+ @dataclass
10
+ class ProcessedFileMetadata:
11
+ license_iri: str
12
+ copyright_holder: str
13
+ authorships: list[str]
14
+ permissions: Permissions | None = None
15
+
16
+
17
+ @dataclass
18
+ class ProcessedFileValue:
19
+ value: str
20
+ file_type: KnoraValueType
21
+ metadata: ProcessedFileMetadata
22
+ res_id: str
23
+ res_label: str
24
+
25
+
26
+ @dataclass
27
+ class ProcessedIIIFUri:
28
+ value: str
29
+ metadata: ProcessedFileMetadata