oarepo-runtime 1.5.88__tar.gz → 1.5.90__tar.gz

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 (151) hide show
  1. {oarepo_runtime-1.5.88/oarepo_runtime.egg-info → oarepo_runtime-1.5.90}/PKG-INFO +1 -1
  2. oarepo_runtime-1.5.90/oarepo_runtime/services/components.py +276 -0
  3. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/schema/validation.py +7 -1
  4. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90/oarepo_runtime.egg-info}/PKG-INFO +1 -1
  5. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/setup.cfg +1 -1
  6. oarepo_runtime-1.5.88/oarepo_runtime/services/components.py +0 -128
  7. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/LICENSE +0 -0
  8. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/MANIFEST.in +0 -0
  9. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/README.md +0 -0
  10. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/__init__.py +0 -0
  11. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/cli/__init__.py +0 -0
  12. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/cli/assets.py +0 -0
  13. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/cli/base.py +0 -0
  14. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/cli/cf.py +0 -0
  15. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/cli/check.py +0 -0
  16. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/cli/configuration.py +0 -0
  17. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/cli/fixtures.py +0 -0
  18. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/cli/index.py +0 -0
  19. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/cli/validate.py +0 -0
  20. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/__init__.py +0 -0
  21. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/asynchronous.py +0 -0
  22. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/catalogue.py +0 -0
  23. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/datastreams.py +0 -0
  24. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/errors.py +0 -0
  25. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/ext.py +0 -0
  26. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/fixtures.py +0 -0
  27. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/json.py +0 -0
  28. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/readers/__init__.py +0 -0
  29. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/readers/attachments.py +0 -0
  30. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/readers/excel.py +0 -0
  31. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/readers/json.py +0 -0
  32. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/readers/service.py +0 -0
  33. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/readers/yaml.py +0 -0
  34. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/semi_asynchronous.py +0 -0
  35. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/synchronous.py +0 -0
  36. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/transformers.py +0 -0
  37. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/types.py +0 -0
  38. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/utils.py +0 -0
  39. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/writers/__init__.py +0 -0
  40. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/writers/attachments_file.py +0 -0
  41. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/writers/attachments_service.py +0 -0
  42. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/writers/service.py +0 -0
  43. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/writers/utils.py +0 -0
  44. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/writers/validation_errors.py +0 -0
  45. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/datastreams/writers/yaml.py +0 -0
  46. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/ext.py +0 -0
  47. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/ext_config.py +0 -0
  48. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/i18n/__init__.py +0 -0
  49. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/info/__init__.py +0 -0
  50. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/info/check.py +0 -0
  51. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/info/views.py +0 -0
  52. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/profile.py +0 -0
  53. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/proxies.py +0 -0
  54. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/records/__init__.py +0 -0
  55. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/records/dumpers/__init__.py +0 -0
  56. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/records/dumpers/edtf_interval.py +0 -0
  57. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/records/dumpers/multilingual_dumper.py +0 -0
  58. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/records/entity_resolvers/__init__.py +0 -0
  59. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/records/entity_resolvers/proxies.py +0 -0
  60. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/records/mappings/__init__.py +0 -0
  61. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/records/mappings/rdm_parent_mapping.json +0 -0
  62. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/records/owners/__init__.py +0 -0
  63. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/records/owners/registry.py +0 -0
  64. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/records/relations/__init__.py +0 -0
  65. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/records/relations/base.py +0 -0
  66. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/records/relations/internal.py +0 -0
  67. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/records/relations/lookup.py +0 -0
  68. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/records/relations/pid_relation.py +0 -0
  69. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/records/systemfields/__init__.py +0 -0
  70. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/records/systemfields/featured_file.py +0 -0
  71. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/records/systemfields/has_draftcheck.py +0 -0
  72. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/records/systemfields/icu.py +0 -0
  73. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/records/systemfields/mapping.py +0 -0
  74. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/records/systemfields/owner.py +0 -0
  75. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/records/systemfields/record_status.py +0 -0
  76. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/records/systemfields/selectors.py +0 -0
  77. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/records/systemfields/synthetic.py +0 -0
  78. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/resources/__init__.py +0 -0
  79. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/resources/file_resource.py +0 -0
  80. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/resources/json_serializer.py +0 -0
  81. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/resources/localized_ui_json_serializer.py +0 -0
  82. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/__init__.py +0 -0
  83. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/config/__init__.py +0 -0
  84. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/config/link_conditions.py +0 -0
  85. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/config/permissions_presets.py +0 -0
  86. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/config/service.py +0 -0
  87. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/custom_fields/__init__.py +0 -0
  88. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/custom_fields/mappings.py +0 -0
  89. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/entity/__init__.py +0 -0
  90. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/entity/config.py +0 -0
  91. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/entity/schema.py +0 -0
  92. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/entity/service.py +0 -0
  93. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/expansions/__init__.py +0 -0
  94. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/expansions/expandable_fields.py +0 -0
  95. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/expansions/service.py +0 -0
  96. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/facets/__init__.py +0 -0
  97. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/facets/base.py +0 -0
  98. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/facets/date.py +0 -0
  99. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/facets/enum.py +0 -0
  100. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/facets/facet_groups_names.py +0 -0
  101. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/facets/max_facet.py +0 -0
  102. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/facets/nested_facet.py +0 -0
  103. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/facets/params.py +0 -0
  104. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/facets/year_histogram.py +0 -0
  105. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/files/__init__.py +0 -0
  106. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/files/components.py +0 -0
  107. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/files/service.py +0 -0
  108. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/generators.py +0 -0
  109. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/permissions/__init__.py +0 -0
  110. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/permissions/generators.py +0 -0
  111. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/records/__init__.py +0 -0
  112. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/records/links.py +0 -0
  113. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/relations/__init__.py +0 -0
  114. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/relations/components.py +0 -0
  115. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/relations/errors.py +0 -0
  116. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/relations/mapping.py +0 -0
  117. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/results.py +0 -0
  118. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/schema/__init__.py +0 -0
  119. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/schema/cf.py +0 -0
  120. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/schema/i18n.py +0 -0
  121. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/schema/i18n_ui.py +0 -0
  122. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/schema/i18n_validation.py +0 -0
  123. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/schema/marshmallow.py +0 -0
  124. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/schema/marshmallow_to_json_schema.py +0 -0
  125. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/schema/oneofschema.py +0 -0
  126. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/schema/polymorphic.py +0 -0
  127. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/schema/rdm.py +0 -0
  128. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/schema/ui.py +0 -0
  129. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/services/search.py +0 -0
  130. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/tasks.py +0 -0
  131. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/translations/cs/LC_MESSAGES/messages.mo +0 -0
  132. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/translations/cs/LC_MESSAGES/messages.po +0 -0
  133. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/translations/default_translations.py +0 -0
  134. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/translations/en/LC_MESSAGES/messages.mo +0 -0
  135. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/translations/en/LC_MESSAGES/messages.po +0 -0
  136. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/translations/messages.pot +0 -0
  137. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/uow.py +0 -0
  138. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/utils/__init__.py +0 -0
  139. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/utils/functools.py +0 -0
  140. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime/utils/path.py +0 -0
  141. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime.egg-info/SOURCES.txt +0 -0
  142. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime.egg-info/dependency_links.txt +0 -0
  143. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime.egg-info/entry_points.txt +0 -0
  144. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime.egg-info/requires.txt +0 -0
  145. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/oarepo_runtime.egg-info/top_level.txt +0 -0
  146. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/pyproject.toml +0 -0
  147. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/setup.py +0 -0
  148. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/tests/marshmallow_to_json/__init__.py +0 -0
  149. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/tests/marshmallow_to_json/test_datacite_ui_schema.py +0 -0
  150. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/tests/marshmallow_to_json/test_simple_schema.py +0 -0
  151. {oarepo_runtime-1.5.88 → oarepo_runtime-1.5.90}/tests/pkg_data/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: oarepo-runtime
3
- Version: 1.5.88
3
+ Version: 1.5.90
4
4
  Summary: A set of runtime extensions of Invenio repository
5
5
  Description-Content-Type: text/markdown
6
6
  License-File: LICENSE
@@ -0,0 +1,276 @@
1
+ from __future__ import annotations
2
+
3
+ import inspect
4
+ from collections import defaultdict
5
+ from dataclasses import dataclass, field
6
+ from typing import Type
7
+
8
+ from flask import current_app
9
+ from invenio_accounts.models import User
10
+ from invenio_drafts_resources.services.records.config import (
11
+ RecordServiceConfig as DraftsRecordServiceConfig,
12
+ )
13
+ from invenio_rdm_records.services.config import RDMRecordServiceConfig
14
+ from invenio_records import Record
15
+ from invenio_records_resources.services import FileServiceConfig
16
+ from invenio_records_resources.services.records.config import (
17
+ RecordServiceConfig as RecordsRecordServiceConfig,
18
+ )
19
+
20
+ from oarepo_runtime.services.custom_fields import (
21
+ CustomFields,
22
+ CustomFieldsMixin,
23
+ InlinedCustomFields,
24
+ )
25
+ from oarepo_runtime.services.generators import RecordOwners
26
+
27
+ try:
28
+ from invenio_drafts_resources.services.records.uow import ParentRecordCommitOp
29
+ except ImportError:
30
+ from invenio_records_resources.services.uow import (
31
+ RecordCommitOp as ParentRecordCommitOp,
32
+ )
33
+
34
+ from invenio_records_resources.services.records.components import ServiceComponent
35
+
36
+
37
+ class OwnersComponent(ServiceComponent):
38
+ def create(self, identity, *, record, **kwargs):
39
+ """Create handler."""
40
+ self.add_owner(identity, record)
41
+
42
+ def add_owner(self, identity, record, commit=False):
43
+ if not hasattr(identity, "id") or not isinstance(identity.id, int):
44
+ return
45
+
46
+ owners = getattr(record.parent, "owners", None)
47
+ if owners is not None:
48
+ user = User.query.filter_by(id=identity.id).first()
49
+ record.parent.owners.add(user)
50
+ if commit:
51
+ self.uow.register(ParentRecordCommitOp(record.parent))
52
+
53
+ def update(self, identity, *, record, **kwargs):
54
+ """Update handler."""
55
+ self.add_owner(identity, record, commit=True)
56
+
57
+ def update_draft(self, identity, *, record, **kwargs):
58
+ """Update handler."""
59
+ self.add_owner(identity, record, commit=True)
60
+
61
+ def search_drafts(self, identity, search, params, **kwargs):
62
+ new_term = RecordOwners().query_filter(identity)
63
+ if new_term:
64
+ return search.filter(new_term)
65
+ return search
66
+
67
+
68
+ from datetime import datetime
69
+
70
+
71
+ class DateIssuedComponent(ServiceComponent):
72
+ def publish(self, identity, data=None, record=None, errors=None, **kwargs):
73
+ """Create a new record."""
74
+ if "dateIssued" not in record["metadata"]:
75
+ record["metadata"]["dateIssued"] = datetime.today().strftime("%Y-%m-%d")
76
+
77
+
78
+ class CFRegistry:
79
+ def __init__(self):
80
+ self.custom_field_names = defaultdict(list)
81
+
82
+ def lookup(self, record_type: Type[Record]):
83
+ if record_type not in self.custom_field_names:
84
+ for fld in inspect.getmembers(
85
+ record_type, lambda x: isinstance(x, CustomFieldsMixin)
86
+ ):
87
+ self.custom_field_names[record_type].append(fld[1])
88
+ return self.custom_field_names[record_type]
89
+
90
+
91
+ cf_registry = CFRegistry()
92
+
93
+
94
+ class CustomFieldsComponent(ServiceComponent):
95
+ def create(self, identity, data=None, record=None, **kwargs):
96
+ """Create a new record."""
97
+ self._set_cf_to_record(record, data)
98
+
99
+ def update(self, identity, data=None, record=None, **kwargs):
100
+ """Update a record."""
101
+ self._set_cf_to_record(record, data)
102
+
103
+ def _set_cf_to_record(self, record, data):
104
+ for cf in cf_registry.lookup(type(record)):
105
+ if isinstance(cf, CustomFields):
106
+ setattr(record, cf.attr_name, data.get(cf.key, {}))
107
+ elif isinstance(cf, InlinedCustomFields):
108
+ config = current_app.config.get(cf.config_key, {})
109
+ for c in config:
110
+ record[c.name] = data.get(c.name)
111
+
112
+
113
+ def process_service_configs(service_config, *additional_components):
114
+ processed_components = []
115
+ target_classes = {
116
+ RDMRecordServiceConfig,
117
+ DraftsRecordServiceConfig,
118
+ RecordsRecordServiceConfig,
119
+ FileServiceConfig,
120
+ }
121
+
122
+ for end_index, cls in enumerate(type(service_config).mro()):
123
+ if cls in target_classes:
124
+ break
125
+
126
+ # We need this because if the "build" function is present in service_config,
127
+ # there are two service_config instances in the MRO (Method Resolution Order) output.
128
+ start_index = 2 if hasattr(service_config, "build") else 1
129
+
130
+ service_configs = type(service_config).mro()[start_index : end_index + 1]
131
+ for config in service_configs:
132
+ if hasattr(config, "build"):
133
+ config = config.build(current_app)
134
+
135
+ if hasattr(config, "components"):
136
+ component_property = config.components
137
+ if isinstance(component_property, list):
138
+ processed_components.extend(component_property)
139
+ elif isinstance(component_property, tuple):
140
+ processed_components.extend(list(component_property))
141
+ else:
142
+ raise ValueError(f"{config} component's definition is not supported")
143
+
144
+ processed_components.extend(additional_components)
145
+ processed_components = _sort_components(processed_components)
146
+ return processed_components
147
+
148
+
149
+ @dataclass
150
+ class ComponentPlacement:
151
+ """Component placement in the list of components.
152
+
153
+ This is a helper class used in the component ordering algorithm.
154
+ """
155
+
156
+ component: Type[ServiceComponent]
157
+ """Component to be ordered."""
158
+
159
+ depends_on: list[ComponentPlacement] = field(default_factory=list)
160
+ """List of components this one depends on.
161
+
162
+ The components must be classes of ServiceComponent or '*' to denote
163
+ that this component depends on all other components and should be placed last.
164
+ """
165
+
166
+ affects: list[ComponentPlacement] = field(default_factory=list)
167
+ """List of components that depend on this one.
168
+
169
+ This is a temporary list used for evaluation of '*' dependencies
170
+ but does not take part in the sorting algorithm."""
171
+
172
+ def __hash__(self) -> int:
173
+ return id(self.component)
174
+
175
+ def __eq__(self, other: ComponentPlacement) -> bool:
176
+ return self.component is other.component
177
+
178
+
179
+ def _sort_components(components):
180
+ """Sort components based on their dependencies while trying to
181
+ keep the initial order as far as possible."""
182
+
183
+ placements: list[ComponentPlacement] = _prepare_component_placement(components)
184
+ placements = _propagate_dependencies(placements)
185
+
186
+ ret = []
187
+ while placements:
188
+ without_dependencies = [p for p in placements if not p.depends_on]
189
+ if not without_dependencies:
190
+ raise ValueError("Circular dependency detected in components.")
191
+ for p in without_dependencies:
192
+ ret.append(p.component)
193
+ placements.remove(p)
194
+ for p2 in placements:
195
+ if p in p2.depends_on:
196
+ p2.depends_on.remove(p)
197
+ return ret
198
+
199
+
200
+ def _matching_placements(placements, dep_class_or_factory):
201
+ for pl in placements:
202
+ pl_component = pl.component
203
+ if not inspect.isclass(pl_component):
204
+ pl_component = type(pl_component(service=object()))
205
+ if issubclass(pl_component, dep_class_or_factory):
206
+ yield pl
207
+
208
+
209
+ def _prepare_component_placement(components) -> list[ComponentPlacement]:
210
+ """Convert components to ComponentPlacement instances and resolve dependencies."""
211
+ placements = []
212
+ for idx, c in enumerate(components):
213
+ placement = ComponentPlacement(component=c)
214
+ placements.append(placement)
215
+
216
+ # direct dependencies
217
+ for idx, placement in enumerate(placements):
218
+ placements_without_this = placements[:idx] + placements[idx + 1 :]
219
+ for dep in getattr(placement.component, "depends_on", []):
220
+ if dep == "*":
221
+ continue
222
+ for pl in _matching_placements(placements_without_this, dep):
223
+ placement.depends_on.append(pl)
224
+ pl.affects.append(placement)
225
+
226
+ for dep in getattr(placement.component, "affects", []):
227
+ if dep == "*":
228
+ continue
229
+ for pl in _matching_placements(placements_without_this, dep):
230
+ placement.affects.append(pl)
231
+ pl.depends_on.append(placement)
232
+
233
+ # star dependencies
234
+ for idx, placement in enumerate(placements):
235
+ placements_without_this = placements[:idx] + placements[idx + 1 :]
236
+ if "*" in getattr(placement.component, "depends_on", []):
237
+ for pl in placements_without_this:
238
+ # if this placement is not in placements that pl depends on
239
+ # (added via direct dependencies above), add it
240
+ if placement not in pl.depends_on:
241
+ placement.depends_on.append(pl)
242
+ pl.affects.append(placement)
243
+
244
+ if "*" in getattr(placement.component, "affects", []):
245
+ for pl in placements_without_this:
246
+ # if this placement is not in placements that pl affects
247
+ # (added via direct dependencies above), add it
248
+ if placement not in pl.affects:
249
+ placement.affects.append(pl)
250
+ pl.depends_on.append(placement)
251
+ return placements
252
+
253
+
254
+ def _propagate_dependencies(
255
+ placements: list[ComponentPlacement],
256
+ ) -> list[ComponentPlacement]:
257
+ # now propagate dependencies
258
+ dependency_propagated = True
259
+ while dependency_propagated:
260
+ dependency_propagated = False
261
+ for placement in placements:
262
+ for dep in placement.depends_on:
263
+ for dep_of_dep in dep.depends_on:
264
+ if dep_of_dep not in placement.depends_on:
265
+ placement.depends_on.append(dep_of_dep)
266
+ dep_of_dep.affects.append(placement)
267
+ dependency_propagated = True
268
+
269
+ for dep in placement.affects:
270
+ for dep_of_dep in dep.affects:
271
+ if dep_of_dep not in placement.affects:
272
+ placement.affects.append(dep_of_dep)
273
+ dep_of_dep.depends_on.append(placement)
274
+ dependency_propagated = True
275
+
276
+ return placements
@@ -2,6 +2,7 @@ import functools
2
2
  import re
3
3
  from datetime import datetime
4
4
  from idutils import normalize_pid
5
+ from isbnlib import canonical, mask
5
6
 
6
7
  from marshmallow.exceptions import ValidationError
7
8
  from marshmallow_utils.fields.edtfdatestring import EDTFValidator
@@ -11,6 +12,11 @@ from invenio_i18n import gettext as _
11
12
 
12
13
  def validate_identifier(value):
13
14
  try:
15
+ if value["scheme"].lower() == "isbn":
16
+ canonical_isbn = canonical(value["identifier"])
17
+ value["identifier"] = mask(canonical_isbn)
18
+ return value["identifier"]
19
+
14
20
  original_identifier = (value["identifier"] or '').strip()
15
21
  normalized_identifier = normalize_pid(
16
22
  value["identifier"], value["scheme"].lower()
@@ -57,4 +63,4 @@ class CachedMultilayerEDTFValidator(EDTFValidator):
57
63
  datetime.strptime(value, "%Y-%m-%d")
58
64
  return value
59
65
  except:
60
- return super().__call__(value)
66
+ return super().__call__(value)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: oarepo-runtime
3
- Version: 1.5.88
3
+ Version: 1.5.90
4
4
  Summary: A set of runtime extensions of Invenio repository
5
5
  Description-Content-Type: text/markdown
6
6
  License-File: LICENSE
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = oarepo-runtime
3
- version = 1.5.88
3
+ version = 1.5.90
4
4
  description = A set of runtime extensions of Invenio repository
5
5
  authors = Alzbeta Pokorna
6
6
  readme = README.md
@@ -1,128 +0,0 @@
1
- import inspect
2
- from collections import defaultdict
3
- from typing import Type
4
-
5
- from flask import current_app
6
- from invenio_accounts.models import User
7
- from invenio_records import Record
8
-
9
- from oarepo_runtime.services.custom_fields import CustomFieldsMixin, CustomFields, InlinedCustomFields
10
- from oarepo_runtime.services.generators import RecordOwners
11
- from invenio_rdm_records.services.config import RDMRecordServiceConfig
12
- from invenio_drafts_resources.services.records.config import RecordServiceConfig as DraftsRecordServiceConfig
13
- from invenio_records_resources.services.records.config import RecordServiceConfig as RecordsRecordServiceConfig
14
- from invenio_records_resources.services import FileServiceConfig
15
- try:
16
- from invenio_drafts_resources.services.records.uow import ParentRecordCommitOp
17
- except ImportError:
18
- from invenio_records_resources.services.uow import (
19
- RecordCommitOp as ParentRecordCommitOp,
20
- )
21
-
22
- from invenio_records_resources.services.records.components import ServiceComponent
23
-
24
-
25
- class OwnersComponent(ServiceComponent):
26
- def create(self, identity, *, record, **kwargs):
27
- """Create handler."""
28
- self.add_owner(identity, record)
29
-
30
- def add_owner(self, identity, record, commit=False):
31
- if not hasattr(identity, "id") or not isinstance(identity.id, int):
32
- return
33
-
34
- owners = getattr(record.parent, "owners", None)
35
- if owners is not None:
36
- user = User.query.filter_by(id=identity.id).first()
37
- record.parent.owners.add(user)
38
- if commit:
39
- self.uow.register(ParentRecordCommitOp(record.parent))
40
-
41
- def update(self, identity, *, record, **kwargs):
42
- """Update handler."""
43
- self.add_owner(identity, record, commit=True)
44
-
45
- def update_draft(self, identity, *, record, **kwargs):
46
- """Update handler."""
47
- self.add_owner(identity, record, commit=True)
48
-
49
- def search_drafts(self, identity, search, params, **kwargs):
50
- new_term = RecordOwners().query_filter(identity)
51
- if new_term:
52
- return search.filter(new_term)
53
- return search
54
-
55
-
56
- from datetime import datetime
57
-
58
-
59
- class DateIssuedComponent(ServiceComponent):
60
- def publish(self, identity, data=None, record=None, errors=None, **kwargs):
61
- """Create a new record."""
62
- if "dateIssued" not in record["metadata"]:
63
- record["metadata"]["dateIssued"] = datetime.today().strftime("%Y-%m-%d")
64
-
65
- class CFRegistry:
66
- def __init__(self):
67
- self.custom_field_names = defaultdict(list)
68
-
69
- def lookup(self, record_type: Type[Record]):
70
- if record_type not in self.custom_field_names:
71
- for fld in inspect.getmembers(record_type, lambda x: isinstance(x, CustomFieldsMixin)):
72
- self.custom_field_names[record_type].append(fld[1])
73
- return self.custom_field_names[record_type]
74
-
75
- cf_registry = CFRegistry()
76
-
77
- class CustomFieldsComponent(ServiceComponent):
78
- def create(self, identity, data=None, record=None, **kwargs):
79
- """Create a new record."""
80
- self._set_cf_to_record(record, data)
81
-
82
- def update(self, identity, data=None, record=None, **kwargs):
83
- """Update a record."""
84
- self._set_cf_to_record(record, data)
85
-
86
- def _set_cf_to_record(self, record, data):
87
- for cf in cf_registry.lookup(type(record)):
88
- if isinstance(cf, CustomFields):
89
- setattr(record, cf.attr_name, data.get(cf.key, {}))
90
- elif isinstance(cf, InlinedCustomFields):
91
- config = current_app.config.get(cf.config_key, {})
92
- for c in config:
93
- record[c.name] =data.get(c.name)
94
-
95
- def process_service_configs(service_config):
96
-
97
- processed_components = []
98
- target_classes = {
99
- RDMRecordServiceConfig,
100
- DraftsRecordServiceConfig,
101
- RecordsRecordServiceConfig,
102
- FileServiceConfig
103
- }
104
-
105
- for end_index, cls in enumerate(type(service_config).mro()):
106
- if cls in target_classes:
107
- break
108
-
109
- # We need this because if the "build" function is present in service_config,
110
- # there are two service_config instances in the MRO (Method Resolution Order) output.
111
- start_index = 2 if hasattr(service_config, "build") else 1
112
-
113
- service_configs = type(service_config).mro()[start_index:end_index + 1]
114
- for config in service_configs:
115
-
116
- if hasattr(config, "build"):
117
- config = config.build(current_app)
118
-
119
- if hasattr(config, 'components'):
120
- component_property = config.components
121
- if isinstance(component_property, list):
122
- processed_components.extend(component_property)
123
- elif isinstance(component_property, tuple):
124
- processed_components.extend(list (component_property))
125
- else:
126
- raise ValueError(f"{config} component's definition is not supported")
127
-
128
- return processed_components
File without changes