oarepo-runtime 1.10.3__py3-none-any.whl → 2.0.0.dev4__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 (171) hide show
  1. oarepo_runtime/__init__.py +24 -0
  2. oarepo_runtime/api.py +210 -0
  3. oarepo_runtime/cli/__init__.py +10 -21
  4. oarepo_runtime/cli/search.py +34 -0
  5. oarepo_runtime/config.py +98 -13
  6. oarepo_runtime/ext.py +64 -82
  7. oarepo_runtime/proxies.py +21 -5
  8. oarepo_runtime/records/__init__.py +11 -50
  9. oarepo_runtime/records/drafts.py +24 -18
  10. oarepo_runtime/records/mapping.py +84 -0
  11. oarepo_runtime/records/pid_providers.py +43 -7
  12. oarepo_runtime/records/systemfields/__init__.py +15 -33
  13. oarepo_runtime/records/systemfields/mapping.py +41 -24
  14. oarepo_runtime/records/systemfields/publication_status.py +61 -0
  15. oarepo_runtime/services/__init__.py +12 -0
  16. oarepo_runtime/services/config/__init__.py +15 -21
  17. oarepo_runtime/services/config/link_conditions.py +69 -75
  18. oarepo_runtime/services/config/permissions.py +62 -0
  19. oarepo_runtime/services/facets/__init__.py +12 -33
  20. oarepo_runtime/services/facets/params.py +45 -110
  21. oarepo_runtime/services/records/__init__.py +14 -1
  22. oarepo_runtime/services/records/links.py +21 -11
  23. oarepo_runtime/services/records/mapping.py +42 -0
  24. oarepo_runtime/services/results.py +98 -109
  25. oarepo_runtime/services/schema/__init__.py +12 -44
  26. oarepo_runtime/services/schema/i18n.py +47 -22
  27. oarepo_runtime/services/schema/i18n_ui.py +61 -24
  28. {oarepo_runtime-1.10.3.dist-info → oarepo_runtime-2.0.0.dev4.dist-info}/METADATA +10 -21
  29. oarepo_runtime-2.0.0.dev4.dist-info/RECORD +32 -0
  30. {oarepo_runtime-1.10.3.dist-info → oarepo_runtime-2.0.0.dev4.dist-info}/WHEEL +1 -2
  31. oarepo_runtime-2.0.0.dev4.dist-info/entry_points.txt +5 -0
  32. oarepo_runtime/cli/assets.py +0 -145
  33. oarepo_runtime/cli/base.py +0 -25
  34. oarepo_runtime/cli/cf.py +0 -15
  35. oarepo_runtime/cli/check.py +0 -167
  36. oarepo_runtime/cli/configuration.py +0 -51
  37. oarepo_runtime/cli/fixtures.py +0 -167
  38. oarepo_runtime/cli/index.py +0 -272
  39. oarepo_runtime/cli/permissions/__init__.py +0 -6
  40. oarepo_runtime/cli/permissions/base.py +0 -26
  41. oarepo_runtime/cli/permissions/evaluate.py +0 -63
  42. oarepo_runtime/cli/permissions/list.py +0 -239
  43. oarepo_runtime/cli/permissions/search.py +0 -121
  44. oarepo_runtime/cli/validate.py +0 -150
  45. oarepo_runtime/datastreams/__init__.py +0 -38
  46. oarepo_runtime/datastreams/asynchronous.py +0 -247
  47. oarepo_runtime/datastreams/catalogue.py +0 -150
  48. oarepo_runtime/datastreams/datastreams.py +0 -152
  49. oarepo_runtime/datastreams/errors.py +0 -54
  50. oarepo_runtime/datastreams/ext.py +0 -41
  51. oarepo_runtime/datastreams/fixtures.py +0 -265
  52. oarepo_runtime/datastreams/json.py +0 -4
  53. oarepo_runtime/datastreams/readers/__init__.py +0 -39
  54. oarepo_runtime/datastreams/readers/attachments.py +0 -51
  55. oarepo_runtime/datastreams/readers/excel.py +0 -123
  56. oarepo_runtime/datastreams/readers/json.py +0 -27
  57. oarepo_runtime/datastreams/readers/service.py +0 -54
  58. oarepo_runtime/datastreams/readers/yaml.py +0 -14
  59. oarepo_runtime/datastreams/semi_asynchronous.py +0 -91
  60. oarepo_runtime/datastreams/synchronous.py +0 -70
  61. oarepo_runtime/datastreams/transformers.py +0 -18
  62. oarepo_runtime/datastreams/types.py +0 -323
  63. oarepo_runtime/datastreams/utils.py +0 -131
  64. oarepo_runtime/datastreams/writers/__init__.py +0 -21
  65. oarepo_runtime/datastreams/writers/attachments_file.py +0 -92
  66. oarepo_runtime/datastreams/writers/attachments_service.py +0 -118
  67. oarepo_runtime/datastreams/writers/publish.py +0 -70
  68. oarepo_runtime/datastreams/writers/service.py +0 -175
  69. oarepo_runtime/datastreams/writers/utils.py +0 -30
  70. oarepo_runtime/datastreams/writers/validation_errors.py +0 -20
  71. oarepo_runtime/datastreams/writers/yaml.py +0 -56
  72. oarepo_runtime/ext_config.py +0 -67
  73. oarepo_runtime/i18n/__init__.py +0 -3
  74. oarepo_runtime/info/__init__.py +0 -0
  75. oarepo_runtime/info/check.py +0 -95
  76. oarepo_runtime/info/permissions/__init__.py +0 -0
  77. oarepo_runtime/info/permissions/debug.py +0 -191
  78. oarepo_runtime/info/views.py +0 -586
  79. oarepo_runtime/profile.py +0 -60
  80. oarepo_runtime/records/dumpers/__init__.py +0 -8
  81. oarepo_runtime/records/dumpers/edtf_interval.py +0 -38
  82. oarepo_runtime/records/dumpers/multilingual_dumper.py +0 -34
  83. oarepo_runtime/records/entity_resolvers/__init__.py +0 -13
  84. oarepo_runtime/records/entity_resolvers/proxies.py +0 -57
  85. oarepo_runtime/records/mappings/__init__.py +0 -0
  86. oarepo_runtime/records/mappings/rdm_parent_mapping.json +0 -483
  87. oarepo_runtime/records/owners/__init__.py +0 -3
  88. oarepo_runtime/records/owners/registry.py +0 -22
  89. oarepo_runtime/records/relations/__init__.py +0 -22
  90. oarepo_runtime/records/relations/base.py +0 -296
  91. oarepo_runtime/records/relations/internal.py +0 -46
  92. oarepo_runtime/records/relations/lookup.py +0 -28
  93. oarepo_runtime/records/relations/pid_relation.py +0 -102
  94. oarepo_runtime/records/systemfields/featured_file.py +0 -45
  95. oarepo_runtime/records/systemfields/has_draftcheck.py +0 -47
  96. oarepo_runtime/records/systemfields/icu.py +0 -371
  97. oarepo_runtime/records/systemfields/owner.py +0 -115
  98. oarepo_runtime/records/systemfields/record_status.py +0 -35
  99. oarepo_runtime/records/systemfields/selectors.py +0 -98
  100. oarepo_runtime/records/systemfields/synthetic.py +0 -130
  101. oarepo_runtime/resources/__init__.py +0 -4
  102. oarepo_runtime/resources/config.py +0 -12
  103. oarepo_runtime/resources/file_resource.py +0 -15
  104. oarepo_runtime/resources/json_serializer.py +0 -27
  105. oarepo_runtime/resources/localized_ui_json_serializer.py +0 -54
  106. oarepo_runtime/resources/resource.py +0 -53
  107. oarepo_runtime/resources/responses.py +0 -20
  108. oarepo_runtime/services/components.py +0 -429
  109. oarepo_runtime/services/config/draft_link.py +0 -23
  110. oarepo_runtime/services/config/permissions_presets.py +0 -174
  111. oarepo_runtime/services/config/service.py +0 -117
  112. oarepo_runtime/services/custom_fields/__init__.py +0 -80
  113. oarepo_runtime/services/custom_fields/mappings.py +0 -188
  114. oarepo_runtime/services/entity/__init__.py +0 -0
  115. oarepo_runtime/services/entity/config.py +0 -14
  116. oarepo_runtime/services/entity/schema.py +0 -9
  117. oarepo_runtime/services/entity/service.py +0 -48
  118. oarepo_runtime/services/expansions/__init__.py +0 -0
  119. oarepo_runtime/services/expansions/expandable_fields.py +0 -21
  120. oarepo_runtime/services/expansions/service.py +0 -4
  121. oarepo_runtime/services/facets/base.py +0 -12
  122. oarepo_runtime/services/facets/date.py +0 -72
  123. oarepo_runtime/services/facets/enum.py +0 -11
  124. oarepo_runtime/services/facets/facet_groups_names.py +0 -17
  125. oarepo_runtime/services/facets/max_facet.py +0 -13
  126. oarepo_runtime/services/facets/multilingual_facet.py +0 -33
  127. oarepo_runtime/services/facets/nested_facet.py +0 -32
  128. oarepo_runtime/services/facets/year_histogram.py +0 -200
  129. oarepo_runtime/services/files/__init__.py +0 -8
  130. oarepo_runtime/services/files/components.py +0 -62
  131. oarepo_runtime/services/files/service.py +0 -16
  132. oarepo_runtime/services/generators.py +0 -10
  133. oarepo_runtime/services/permissions/__init__.py +0 -3
  134. oarepo_runtime/services/permissions/generators.py +0 -103
  135. oarepo_runtime/services/relations/__init__.py +0 -0
  136. oarepo_runtime/services/relations/components.py +0 -15
  137. oarepo_runtime/services/relations/errors.py +0 -18
  138. oarepo_runtime/services/relations/mapping.py +0 -38
  139. oarepo_runtime/services/schema/cf.py +0 -13
  140. oarepo_runtime/services/schema/i18n_validation.py +0 -7
  141. oarepo_runtime/services/schema/marshmallow.py +0 -44
  142. oarepo_runtime/services/schema/marshmallow_to_json_schema.py +0 -72
  143. oarepo_runtime/services/schema/oneofschema.py +0 -192
  144. oarepo_runtime/services/schema/polymorphic.py +0 -21
  145. oarepo_runtime/services/schema/rdm.py +0 -146
  146. oarepo_runtime/services/schema/rdm_ui.py +0 -156
  147. oarepo_runtime/services/schema/ui.py +0 -251
  148. oarepo_runtime/services/schema/validation.py +0 -70
  149. oarepo_runtime/services/search.py +0 -282
  150. oarepo_runtime/services/service.py +0 -61
  151. oarepo_runtime/tasks.py +0 -6
  152. oarepo_runtime/translations/cs/LC_MESSAGES/messages.mo +0 -0
  153. oarepo_runtime/translations/cs/LC_MESSAGES/messages.po +0 -95
  154. oarepo_runtime/translations/default_translations.py +0 -6
  155. oarepo_runtime/translations/en/LC_MESSAGES/messages.mo +0 -0
  156. oarepo_runtime/translations/en/LC_MESSAGES/messages.po +0 -97
  157. oarepo_runtime/translations/messages.pot +0 -100
  158. oarepo_runtime/uow.py +0 -146
  159. oarepo_runtime/utils/__init__.py +0 -0
  160. oarepo_runtime/utils/functools.py +0 -37
  161. oarepo_runtime/utils/identity_utils.py +0 -35
  162. oarepo_runtime/utils/index.py +0 -11
  163. oarepo_runtime/utils/path.py +0 -97
  164. oarepo_runtime-1.10.3.dist-info/RECORD +0 -163
  165. oarepo_runtime-1.10.3.dist-info/entry_points.txt +0 -16
  166. oarepo_runtime-1.10.3.dist-info/top_level.txt +0 -2
  167. tests/marshmallow_to_json/__init__.py +0 -0
  168. tests/marshmallow_to_json/test_datacite_ui_schema.py +0 -1410
  169. tests/marshmallow_to_json/test_simple_schema.py +0 -52
  170. tests/pkg_data/__init__.py +0 -0
  171. {oarepo_runtime-1.10.3.dist-info → oarepo_runtime-2.0.0.dev4.dist-info}/licenses/LICENSE +0 -0
@@ -1,50 +1,11 @@
1
- from typing import Type
2
-
3
- from deprecated import deprecated
4
- from invenio_records_resources.records import Record
5
-
6
-
7
- def select_record_for_update(record_cls: Type[Record], persistent_identifier):
8
- """Select a record for update."""
9
- resolved_record = record_cls.pid.resolve(persistent_identifier)
10
- model_id = resolved_record.model.id
11
- obj = record_cls.model_cls.query.filter_by(id=model_id).with_for_update().one()
12
- return record_cls(obj.data, model=obj)
13
-
14
-
15
- @deprecated("Moved to oarepo_runtime.services.config.link_conditions")
16
- def is_published_record_function():
17
- """Shortcut for links to determine if record is a published.
18
-
19
- This function is deprecated. Use oarepo_runtime.services.config.is_published_record instead.
20
- """
21
- from oarepo_runtime.services.config.link_conditions import is_published_record
22
-
23
- return is_published_record()
24
-
25
-
26
- @deprecated("Moved to oarepo_runtime.services.config.link_conditions")
27
- def is_draft_record_function():
28
- """Shortcut for links to determine if record is a draft record.
29
-
30
- This function is deprecated. Use oarepo_runtime.services.config.is_draft_record instead.
31
- """
32
- from oarepo_runtime.services.config.link_conditions import is_draft_record
33
-
34
- return is_draft_record()
35
-
36
-
37
- @deprecated("Moved to oarepo_runtime.services.config.link_conditions")
38
- def has_draft_function():
39
- """Shortcut for links to determine if record is either a draft or a published one with a draft associated.
40
-
41
- This function is deprecated. Use oarepo_runtime.services.config.has_draft instead.
42
- """
43
- from oarepo_runtime.services.config.link_conditions import has_draft
44
-
45
- return has_draft()
46
-
47
-
48
- is_published_record = is_published_record_function()
49
- is_draft = is_draft_record_function()
50
- has_draft = has_draft_function()
1
+ #
2
+ # Copyright (c) 2025 CESNET z.s.p.o.
3
+ #
4
+ # This file is a part of oarepo-runtime (see http://github.com/oarepo/oarepo-runtime).
5
+ #
6
+ # oarepo-runtime is free software; you can redistribute it and/or modify it
7
+ # under the terms of the MIT License; see LICENSE file for more details.
8
+ #
9
+ """Records module."""
10
+
11
+ from __future__ import annotations
@@ -1,13 +1,29 @@
1
- from invenio_records_resources.records.api import Record
1
+ #
2
+ # Copyright (c) 2025 CESNET z.s.p.o.
3
+ #
4
+ # This file is a part of oarepo-runtime (see http://github.com/oarepo/oarepo-runtime).
5
+ #
6
+ # oarepo-runtime is free software; you can redistribute it and/or modify it
7
+ # under the terms of the MIT License; see LICENSE file for more details.
8
+ #
9
+ """Record drafts."""
2
10
 
3
- from oarepo_runtime.datastreams.utils import get_record_service_for_record
11
+ from __future__ import annotations
4
12
 
13
+ from typing import TYPE_CHECKING
5
14
 
6
- def has_draft(record: Record) -> bool:
15
+ if TYPE_CHECKING:
16
+ from invenio_records_resources.records.api import RecordBase
17
+
18
+ from oarepo_runtime.proxies import current_runtime
19
+
20
+
21
+ def has_draft(record: RecordBase) -> bool:
22
+ """Check if record has draft."""
7
23
  return get_draft(record) is not None
8
24
 
9
25
 
10
- def get_draft(record: Record) -> Record | None:
26
+ def get_draft(record: RecordBase) -> RecordBase | None:
11
27
  """Get the draft of a published record, if it exists.
12
28
 
13
29
  A record can have a draft if:
@@ -19,24 +35,14 @@ def get_draft(record: Record) -> Record | None:
19
35
  """
20
36
  if getattr(record, "is_draft", False):
21
37
  return record
22
- if not hasattr(record, "parent"):
23
- return None
24
- if not hasattr(record, "has_draft"):
38
+ if not hasattr(record, "parent") or not hasattr(record, "has_draft"):
25
39
  return None
26
40
 
27
- record_service = get_record_service_for_record(record)
28
- if not record_service:
29
- return None
41
+ record_service = current_runtime.get_record_service_for_record(record)
30
42
 
31
43
  try:
32
- # if there is no record service, we cannot check for draft
33
- if not record_service:
34
- return None
35
- return next(
36
- record_service.config.draft_cls.get_records_by_parent(
37
- record.parent, with_deleted=False
38
- )
39
- )
44
+ parent = getattr(record, "parent", None)
45
+ return next(record_service.config.draft_cls.get_records_by_parent(parent, with_deleted=False))
40
46
  except StopIteration:
41
47
  # no draft found
42
48
  return None
@@ -0,0 +1,84 @@
1
+ #
2
+ # Copyright (c) 2025 CESNET z.s.p.o.
3
+ #
4
+ # This file is a part of oarepo-runtime (see http://github.com/oarepo/oarepo-runtime).
5
+ #
6
+ # oarepo-runtime is free software; you can redistribute it and/or modify it
7
+ # under the terms of the MIT License; see LICENSE file for more details.
8
+ #
9
+ """Module to update the mapping of system fields in a record class."""
10
+
11
+ from __future__ import annotations
12
+
13
+ import inspect
14
+ from collections.abc import Iterable
15
+ from typing import TYPE_CHECKING, Any
16
+
17
+ from invenio_search import current_search_client
18
+ from invenio_search.engine import dsl
19
+ from invenio_search.utils import build_alias_name
20
+
21
+ from oarepo_runtime.records.systemfields.mapping import MappingSystemFieldMixin
22
+
23
+ if TYPE_CHECKING:
24
+ from collections.abc import Iterable
25
+
26
+ from invenio_records.api import RecordBase
27
+
28
+
29
+ def prefixed_index(index: dsl.Index) -> dsl.Index:
30
+ """Return a prefixed index for the given index."""
31
+ return dsl.Index(
32
+ build_alias_name(
33
+ index._name, # type: ignore[attr-defined] # noqa: SLF001
34
+ ),
35
+ using=current_search_client, # pyright: ignore[reportArgumentType]
36
+ )
37
+
38
+
39
+ def update_record_system_fields_mapping(record_class: type[RecordBase]) -> None:
40
+ """Update mapping for system fields in the record class.
41
+
42
+ :param record_class: The record class which index mapping should be updated.
43
+ :raise search.RequestError: If there is an error while updating the mapping.
44
+ """
45
+ index = getattr(record_class, "index", None)
46
+ if not index:
47
+ return
48
+
49
+ for fld in get_mapping_fields(record_class):
50
+ # get mapping
51
+ mapping = fld.mapping
52
+ settings = fld.mapping_settings
53
+ dynamic_templates = fld.dynamic_templates
54
+
55
+ # upload mapping
56
+ update_record_index(prefixed_index(index), settings, mapping, dynamic_templates)
57
+
58
+
59
+ def update_record_index(
60
+ record_index: dsl.Index,
61
+ settings: dict,
62
+ mapping: dict,
63
+ dynamic_templates: list | None = None,
64
+ ) -> None:
65
+ """Update the index mapping for the given record index."""
66
+ if settings:
67
+ record_index.close()
68
+ record_index.put_settings(body=settings)
69
+ record_index.open()
70
+
71
+ body: dict[str, Any] = {}
72
+ if mapping:
73
+ body["properties"] = mapping
74
+ if dynamic_templates:
75
+ body["dynamic_templates"] = dynamic_templates
76
+ if body:
77
+ record_index.put_mapping(body=body)
78
+
79
+
80
+ def get_mapping_fields(
81
+ record_class: type[RecordBase],
82
+ ) -> Iterable[MappingSystemFieldMixin]:
83
+ """Get all mapping fields from the record class."""
84
+ return (attr for _, attr in inspect.getmembers(record_class, lambda x: isinstance(x, MappingSystemFieldMixin)))
@@ -1,17 +1,53 @@
1
+ #
2
+ # Copyright (c) 2025 CESNET z.s.p.o.
3
+ #
4
+ # This file is a part of oarepo-runtime (see http://github.com/oarepo/oarepo-runtime).
5
+ #
6
+ # oarepo-runtime is free software; you can redistribute it and/or modify it
7
+ # under the terms of the MIT License; see LICENSE file for more details.
8
+ #
9
+ """PID providers."""
10
+
11
+ from __future__ import annotations
12
+
13
+ from typing import TYPE_CHECKING, Any, Self, cast
14
+
1
15
  from invenio_pidstore.models import PersistentIdentifier, PIDStatus
2
16
 
17
+ if TYPE_CHECKING:
18
+ from invenio_pidstore.providers.recordid_v2 import RecordIdProviderV2
19
+ else:
20
+ RecordIdProviderV2 = object
21
+
22
+
23
+ class UniversalPIDMixin(RecordIdProviderV2):
24
+ """Mixin class to handle creation and management of universal PIDs for records."""
3
25
 
4
- class UniversalPIDMixin:
5
26
  unpid_pid_type = "unpid"
6
27
  unpid_default_status = PIDStatus.REGISTERED
7
28
 
8
29
  @classmethod
9
- def create(cls, object_type=None, object_uuid=None, options=None, **kwargs):
10
- pid = super().create(
11
- object_type=object_type, object_uuid=object_uuid, options=options, **kwargs
30
+ def create( # type: ignore[override]
31
+ cls,
32
+ object_type: str | None = None,
33
+ object_uuid: str | None = None,
34
+ options: dict | None = None,
35
+ **kwargs: Any,
36
+ ) -> Self:
37
+ """Create PID for a given object and store it."""
38
+ pid = cast(
39
+ "Self",
40
+ super().create(
41
+ object_type=object_type,
42
+ object_uuid=object_uuid,
43
+ options=options,
44
+ **kwargs,
45
+ ),
12
46
  )
13
- assert pid.pid.pid_value is not None
14
- control_pid = PersistentIdentifier.create(
47
+ if pid.pid.pid_value is None:
48
+ raise ValueError("PID value cannot be None.") # pragma: no cover
49
+
50
+ PersistentIdentifier.create(
15
51
  cls.unpid_pid_type,
16
52
  pid.pid.pid_value,
17
53
  pid_provider=None,
@@ -19,4 +55,4 @@ class UniversalPIDMixin:
19
55
  object_uuid=object_uuid,
20
56
  status=cls.unpid_default_status,
21
57
  )
22
- return pid
58
+ return pid
@@ -1,34 +1,16 @@
1
- from .icu import (
2
- FulltextIndexField,
3
- ICUField,
4
- ICUSearchField,
5
- ICUSortField,
6
- ICUSuggestField,
7
- TermIndexField,
8
- )
9
- from .mapping import MappingSystemFieldMixin, SystemFieldDumperExt
10
- from .selectors import (
11
- FilteredSelector,
12
- FirstItemSelector,
13
- MultiSelector,
14
- PathSelector,
15
- Selector,
16
- )
17
- from .synthetic import SyntheticSystemField
1
+ #
2
+ # Copyright (c) 2025 CESNET z.s.p.o.
3
+ #
4
+ # This file is a part of oarepo-runtime (see http://github.com/oarepo/oarepo-runtime).
5
+ #
6
+ # oarepo-runtime is free software; you can redistribute it and/or modify it
7
+ # under the terms of the MIT License; see LICENSE file for more details.
8
+ #
9
+ """Records system fields."""
18
10
 
19
- __all__ = (
20
- "ICUField",
21
- "ICUSuggestField",
22
- "ICUSortField",
23
- "ICUSearchField",
24
- "FulltextIndexField",
25
- "MappingSystemFieldMixin",
26
- "SystemFieldDumperExt",
27
- "SyntheticSystemField",
28
- "PathSelector",
29
- "Selector",
30
- "FirstItemSelector",
31
- "FilteredSelector",
32
- "MultiSelector",
33
- "TermIndexField",
34
- )
11
+ from __future__ import annotations
12
+
13
+ from .mapping import MappingSystemFieldMixin
14
+ from .publication_status import PublicationStatusSystemField
15
+
16
+ __all__ = ("MappingSystemFieldMixin", "PublicationStatusSystemField")
@@ -1,39 +1,56 @@
1
- import inspect
1
+ #
2
+ # Copyright (c) 2025 CESNET z.s.p.o.
3
+ #
4
+ # This file is a part of oarepo-runtime (see http://github.com/oarepo/oarepo-runtime).
5
+ #
6
+ # oarepo-runtime is free software; you can redistribute it and/or modify it
7
+ # under the terms of the MIT License; see LICENSE file for more details.
8
+ #
9
+ """System fields mapping."""
2
10
 
3
- from invenio_records.dumpers import SearchDumperExt
11
+ from __future__ import annotations
4
12
 
13
+ from typing import TYPE_CHECKING, override
14
+
15
+ if TYPE_CHECKING:
16
+ from invenio_records.api import RecordBase
17
+ from invenio_records.dumpers import Dumper
18
+ from invenio_records.systemfields import SystemField
19
+ else:
20
+ SystemField = object
21
+
22
+
23
+ class MappingSystemFieldMixin(SystemField):
24
+ """Mixin class that provides default mapping, mapping settings, and dynamic templates for system fields."""
5
25
 
6
- class MappingSystemFieldMixin:
7
26
  @property
8
- def mapping(self):
27
+ def mapping(self) -> dict:
28
+ """Return the default mapping for the system field."""
9
29
  return {}
10
30
 
11
31
  @property
12
- def mapping_settings(self):
32
+ def mapping_settings(self) -> dict:
33
+ """Return the default mapping settings for the system field."""
13
34
  return {}
14
35
 
15
36
  @property
16
- def dynamic_templates(self):
37
+ def dynamic_templates(self) -> list:
38
+ """Return the default dynamic templates for the system field."""
17
39
  return []
18
40
 
19
- def search_dump(self, data, record):
20
- """Dump custom field."""
21
-
22
- def search_load(self, data, record_cls):
23
- """Load custom field."""
41
+ # The following methods are added just for typing purposes.
42
+ @override
43
+ def pre_dump(self, record: RecordBase, data: dict, dumper: Dumper | None = None) -> None: # type: ignore[misc]
44
+ """Dump record to the data - pre-dump phase."""
24
45
 
46
+ @override
47
+ def post_dump(self, record: RecordBase, data: dict, dumper: Dumper | None = None) -> None: # type: ignore[misc]
48
+ """Dump record to the data - post-dump phase."""
25
49
 
26
- class SystemFieldDumperExt(SearchDumperExt):
27
- def dump(self, record, data):
28
- """Dump custom fields."""
29
- for cf in inspect.getmembers(
30
- type(record), lambda x: isinstance(x, MappingSystemFieldMixin)
31
- ):
32
- cf[1].search_dump(data, record=record)
50
+ @override
51
+ def pre_load(self, data: dict, loader: Dumper | None = None) -> None: # type: ignore[misc]
52
+ """Load record from the data - pre-load phase."""
33
53
 
34
- def load(self, data, record_cls):
35
- """Load custom fields."""
36
- for cf in inspect.getmembers(
37
- record_cls, lambda x: isinstance(x, MappingSystemFieldMixin)
38
- ):
39
- cf[1].search_load(data, record_cls=record_cls)
54
+ @override
55
+ def post_load(self, record: RecordBase, data: dict, loader: Dumper | None = None) -> None: # type: ignore[misc]
56
+ """Load record from the data - post-load phase."""
@@ -0,0 +1,61 @@
1
+ #
2
+ # Copyright (c) 2025 CESNET z.s.p.o.
3
+ #
4
+ # This file is a part of oarepo-runtime (see http://github.com/oarepo/oarepo-runtime).
5
+ #
6
+ # oarepo-runtime is free software; you can redistribute it and/or modify it
7
+ # under the terms of the MIT License; see LICENSE file for more details.
8
+ #
9
+ """Record status module."""
10
+
11
+ from __future__ import annotations
12
+
13
+ from typing import TYPE_CHECKING, Any, override
14
+
15
+ from invenio_records.systemfields import SystemField
16
+
17
+ from .mapping import MappingSystemFieldMixin
18
+
19
+ if TYPE_CHECKING:
20
+ from invenio_records.api import RecordBase
21
+ from invenio_records.dumpers import Dumper
22
+
23
+
24
+ class PublicationStatusSystemField(MappingSystemFieldMixin, SystemField):
25
+ """A system field to track the status of a record (either 'draft' or 'published').
26
+
27
+ The default key for this field is 'publication_status', but it can be customized.
28
+ """
29
+
30
+ def __init__(self, key: str | None = "publication_status"):
31
+ """Initialize the system field with an optional key."""
32
+ super().__init__(key)
33
+
34
+ @property
35
+ def mapping(self) -> dict:
36
+ """Return the mapping for the field in the search index."""
37
+ return {
38
+ self.key: {
39
+ "type": "keyword",
40
+ },
41
+ }
42
+
43
+ @override
44
+ def post_load(self, record: RecordBase, data: dict, loader: Dumper | None = None) -> None:
45
+ data.pop(self.key, None)
46
+
47
+ @override
48
+ def post_dump(self, record: RecordBase, data: dict, dumper: Dumper | None = None) -> None:
49
+ if self.key is None:
50
+ return # pragma: no cover
51
+ if not self.attr_name:
52
+ raise ValueError( # pragma: no cover
53
+ "attr_name must be set for PublicationStatusSystemField"
54
+ )
55
+ data[self.key] = getattr(record, self.attr_name)
56
+
57
+ def __get__(self, record: RecordBase | None, owner: Any = None) -> Any:
58
+ """Access the attribute."""
59
+ if record is None:
60
+ return self
61
+ return "draft" if getattr(record, "is_draft", False) else "published"
@@ -0,0 +1,12 @@
1
+ #
2
+ # Copyright (c) 2025 CESNET z.s.p.o.
3
+ #
4
+ # This file is a part of oarepo-runtime (see http://github.com/oarepo/oarepo-runtime).
5
+ #
6
+ # oarepo-runtime is free software; you can redistribute it and/or modify it
7
+ # under the terms of the MIT License; see LICENSE file for more details.
8
+ #
9
+
10
+ """Services module."""
11
+
12
+ from __future__ import annotations
@@ -1,35 +1,29 @@
1
- from .draft_link import DraftLink
1
+ #
2
+ # Copyright (c) 2025 CESNET z.s.p.o.
3
+ #
4
+ # This file is a part of oarepo-runtime (see http://github.com/oarepo/oarepo-runtime).
5
+ #
6
+ # oarepo-runtime is free software; you can redistribute it and/or modify it
7
+ # under the terms of the MIT License; see LICENSE file for more details.
8
+ #
9
+ """Service config module."""
10
+
11
+ from __future__ import annotations
12
+
2
13
  from .link_conditions import (
3
14
  has_draft,
4
15
  has_draft_permission,
5
- has_file_permission,
6
16
  has_permission,
7
- has_permission_file_service,
8
17
  has_published_record,
9
- is_draft_record,
10
18
  is_published_record,
11
19
  )
12
- from .permissions_presets import (
13
- AuthenticatedPermissionPolicy,
14
- EveryonePermissionPolicy,
15
- OaiHarvesterPermissionPolicy,
16
- ReadOnlyPermissionPolicy,
17
- )
18
- from .service import PermissionsPresetsConfigMixin
20
+ from .permissions import EveryonePermissionPolicy
19
21
 
20
22
  __all__ = (
21
- "PermissionsPresetsConfigMixin",
22
- "OaiHarvesterPermissionPolicy",
23
- "ReadOnlyPermissionPolicy",
24
23
  "EveryonePermissionPolicy",
25
- "AuthenticatedPermissionPolicy",
26
- "is_published_record",
27
- "is_draft_record",
28
24
  "has_draft",
25
+ "has_draft_permission",
29
26
  "has_permission",
30
- "has_permission_file_service",
31
- "has_file_permission",
32
27
  "has_published_record",
33
- "has_draft_permission",
34
- "DraftLink",
28
+ "is_published_record",
35
29
  )