oarepo-runtime 1.10.2__py3-none-any.whl → 2.0.0.dev3__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.
- oarepo_runtime/__init__.py +24 -0
- oarepo_runtime/api.py +111 -0
- oarepo_runtime/cli/__init__.py +10 -21
- oarepo_runtime/cli/search.py +34 -0
- oarepo_runtime/config.py +86 -13
- oarepo_runtime/ext.py +64 -82
- oarepo_runtime/proxies.py +21 -5
- oarepo_runtime/records/__init__.py +11 -50
- oarepo_runtime/records/drafts.py +24 -18
- oarepo_runtime/records/mapping.py +84 -0
- oarepo_runtime/records/pid_providers.py +43 -7
- oarepo_runtime/records/systemfields/__init__.py +15 -33
- oarepo_runtime/records/systemfields/mapping.py +41 -24
- oarepo_runtime/records/systemfields/publication_status.py +59 -0
- oarepo_runtime/services/__init__.py +12 -0
- oarepo_runtime/services/config/__init__.py +15 -21
- oarepo_runtime/services/config/link_conditions.py +69 -75
- oarepo_runtime/services/config/permissions.py +62 -0
- oarepo_runtime/services/records/__init__.py +14 -1
- oarepo_runtime/services/records/links.py +21 -11
- oarepo_runtime/services/records/mapping.py +42 -0
- oarepo_runtime/services/results.py +98 -109
- oarepo_runtime/services/schema/__init__.py +12 -44
- oarepo_runtime/services/schema/i18n.py +47 -22
- oarepo_runtime/services/schema/i18n_ui.py +61 -24
- {oarepo_runtime-1.10.2.dist-info → oarepo_runtime-2.0.0.dev3.dist-info}/METADATA +9 -21
- oarepo_runtime-2.0.0.dev3.dist-info/RECORD +30 -0
- {oarepo_runtime-1.10.2.dist-info → oarepo_runtime-2.0.0.dev3.dist-info}/WHEEL +1 -2
- oarepo_runtime-2.0.0.dev3.dist-info/entry_points.txt +5 -0
- oarepo_runtime/cli/assets.py +0 -145
- oarepo_runtime/cli/base.py +0 -25
- oarepo_runtime/cli/cf.py +0 -15
- oarepo_runtime/cli/check.py +0 -167
- oarepo_runtime/cli/configuration.py +0 -51
- oarepo_runtime/cli/fixtures.py +0 -167
- oarepo_runtime/cli/index.py +0 -272
- oarepo_runtime/cli/permissions/__init__.py +0 -6
- oarepo_runtime/cli/permissions/base.py +0 -26
- oarepo_runtime/cli/permissions/evaluate.py +0 -63
- oarepo_runtime/cli/permissions/list.py +0 -239
- oarepo_runtime/cli/permissions/search.py +0 -121
- oarepo_runtime/cli/validate.py +0 -150
- oarepo_runtime/datastreams/__init__.py +0 -38
- oarepo_runtime/datastreams/asynchronous.py +0 -247
- oarepo_runtime/datastreams/catalogue.py +0 -150
- oarepo_runtime/datastreams/datastreams.py +0 -152
- oarepo_runtime/datastreams/errors.py +0 -54
- oarepo_runtime/datastreams/ext.py +0 -41
- oarepo_runtime/datastreams/fixtures.py +0 -265
- oarepo_runtime/datastreams/json.py +0 -4
- oarepo_runtime/datastreams/readers/__init__.py +0 -39
- oarepo_runtime/datastreams/readers/attachments.py +0 -51
- oarepo_runtime/datastreams/readers/excel.py +0 -123
- oarepo_runtime/datastreams/readers/json.py +0 -27
- oarepo_runtime/datastreams/readers/service.py +0 -54
- oarepo_runtime/datastreams/readers/yaml.py +0 -14
- oarepo_runtime/datastreams/semi_asynchronous.py +0 -91
- oarepo_runtime/datastreams/synchronous.py +0 -70
- oarepo_runtime/datastreams/transformers.py +0 -18
- oarepo_runtime/datastreams/types.py +0 -323
- oarepo_runtime/datastreams/utils.py +0 -131
- oarepo_runtime/datastreams/writers/__init__.py +0 -21
- oarepo_runtime/datastreams/writers/attachments_file.py +0 -92
- oarepo_runtime/datastreams/writers/attachments_service.py +0 -118
- oarepo_runtime/datastreams/writers/publish.py +0 -70
- oarepo_runtime/datastreams/writers/service.py +0 -175
- oarepo_runtime/datastreams/writers/utils.py +0 -30
- oarepo_runtime/datastreams/writers/validation_errors.py +0 -20
- oarepo_runtime/datastreams/writers/yaml.py +0 -56
- oarepo_runtime/ext_config.py +0 -67
- oarepo_runtime/i18n/__init__.py +0 -3
- oarepo_runtime/info/__init__.py +0 -0
- oarepo_runtime/info/check.py +0 -95
- oarepo_runtime/info/permissions/__init__.py +0 -0
- oarepo_runtime/info/permissions/debug.py +0 -191
- oarepo_runtime/info/views.py +0 -586
- oarepo_runtime/profile.py +0 -60
- oarepo_runtime/records/dumpers/__init__.py +0 -8
- oarepo_runtime/records/dumpers/edtf_interval.py +0 -38
- oarepo_runtime/records/dumpers/multilingual_dumper.py +0 -34
- oarepo_runtime/records/entity_resolvers/__init__.py +0 -13
- oarepo_runtime/records/entity_resolvers/proxies.py +0 -57
- oarepo_runtime/records/mappings/__init__.py +0 -0
- oarepo_runtime/records/mappings/rdm_parent_mapping.json +0 -483
- oarepo_runtime/records/owners/__init__.py +0 -3
- oarepo_runtime/records/owners/registry.py +0 -22
- oarepo_runtime/records/relations/__init__.py +0 -22
- oarepo_runtime/records/relations/base.py +0 -296
- oarepo_runtime/records/relations/internal.py +0 -46
- oarepo_runtime/records/relations/lookup.py +0 -28
- oarepo_runtime/records/relations/pid_relation.py +0 -102
- oarepo_runtime/records/systemfields/featured_file.py +0 -45
- oarepo_runtime/records/systemfields/has_draftcheck.py +0 -47
- oarepo_runtime/records/systemfields/icu.py +0 -371
- oarepo_runtime/records/systemfields/owner.py +0 -115
- oarepo_runtime/records/systemfields/record_status.py +0 -35
- oarepo_runtime/records/systemfields/selectors.py +0 -98
- oarepo_runtime/records/systemfields/synthetic.py +0 -130
- oarepo_runtime/resources/__init__.py +0 -4
- oarepo_runtime/resources/config.py +0 -12
- oarepo_runtime/resources/file_resource.py +0 -15
- oarepo_runtime/resources/json_serializer.py +0 -27
- oarepo_runtime/resources/localized_ui_json_serializer.py +0 -54
- oarepo_runtime/resources/resource.py +0 -53
- oarepo_runtime/resources/responses.py +0 -20
- oarepo_runtime/services/components.py +0 -429
- oarepo_runtime/services/config/draft_link.py +0 -23
- oarepo_runtime/services/config/permissions_presets.py +0 -174
- oarepo_runtime/services/config/service.py +0 -117
- oarepo_runtime/services/custom_fields/__init__.py +0 -80
- oarepo_runtime/services/custom_fields/mappings.py +0 -188
- oarepo_runtime/services/entity/__init__.py +0 -0
- oarepo_runtime/services/entity/config.py +0 -14
- oarepo_runtime/services/entity/schema.py +0 -9
- oarepo_runtime/services/entity/service.py +0 -48
- oarepo_runtime/services/expansions/__init__.py +0 -0
- oarepo_runtime/services/expansions/expandable_fields.py +0 -21
- oarepo_runtime/services/expansions/service.py +0 -4
- oarepo_runtime/services/facets/__init__.py +0 -33
- oarepo_runtime/services/facets/base.py +0 -12
- oarepo_runtime/services/facets/date.py +0 -72
- oarepo_runtime/services/facets/enum.py +0 -11
- oarepo_runtime/services/facets/facet_groups_names.py +0 -17
- oarepo_runtime/services/facets/max_facet.py +0 -13
- oarepo_runtime/services/facets/multilingual_facet.py +0 -33
- oarepo_runtime/services/facets/nested_facet.py +0 -32
- oarepo_runtime/services/facets/params.py +0 -192
- oarepo_runtime/services/facets/year_histogram.py +0 -200
- oarepo_runtime/services/files/__init__.py +0 -8
- oarepo_runtime/services/files/components.py +0 -62
- oarepo_runtime/services/files/service.py +0 -16
- oarepo_runtime/services/generators.py +0 -10
- oarepo_runtime/services/permissions/__init__.py +0 -3
- oarepo_runtime/services/permissions/generators.py +0 -103
- oarepo_runtime/services/relations/__init__.py +0 -0
- oarepo_runtime/services/relations/components.py +0 -15
- oarepo_runtime/services/relations/errors.py +0 -18
- oarepo_runtime/services/relations/mapping.py +0 -38
- oarepo_runtime/services/schema/cf.py +0 -13
- oarepo_runtime/services/schema/i18n_validation.py +0 -7
- oarepo_runtime/services/schema/marshmallow.py +0 -44
- oarepo_runtime/services/schema/marshmallow_to_json_schema.py +0 -72
- oarepo_runtime/services/schema/oneofschema.py +0 -192
- oarepo_runtime/services/schema/polymorphic.py +0 -21
- oarepo_runtime/services/schema/rdm.py +0 -75
- oarepo_runtime/services/schema/rdm_ui.py +0 -156
- oarepo_runtime/services/schema/ui.py +0 -251
- oarepo_runtime/services/schema/validation.py +0 -70
- oarepo_runtime/services/search.py +0 -282
- oarepo_runtime/services/service.py +0 -61
- oarepo_runtime/tasks.py +0 -6
- oarepo_runtime/translations/cs/LC_MESSAGES/messages.mo +0 -0
- oarepo_runtime/translations/cs/LC_MESSAGES/messages.po +0 -85
- oarepo_runtime/translations/default_translations.py +0 -6
- oarepo_runtime/translations/en/LC_MESSAGES/messages.mo +0 -0
- oarepo_runtime/translations/en/LC_MESSAGES/messages.po +0 -89
- oarepo_runtime/translations/messages.pot +0 -91
- oarepo_runtime/uow.py +0 -146
- oarepo_runtime/utils/__init__.py +0 -0
- oarepo_runtime/utils/functools.py +0 -37
- oarepo_runtime/utils/identity_utils.py +0 -35
- oarepo_runtime/utils/index.py +0 -11
- oarepo_runtime/utils/path.py +0 -97
- oarepo_runtime-1.10.2.dist-info/RECORD +0 -163
- oarepo_runtime-1.10.2.dist-info/entry_points.txt +0 -16
- oarepo_runtime-1.10.2.dist-info/top_level.txt +0 -2
- tests/marshmallow_to_json/__init__.py +0 -0
- tests/marshmallow_to_json/test_datacite_ui_schema.py +0 -1410
- tests/marshmallow_to_json/test_simple_schema.py +0 -52
- tests/pkg_data/__init__.py +0 -0
- {oarepo_runtime-1.10.2.dist-info → oarepo_runtime-2.0.0.dev3.dist-info}/licenses/LICENSE +0 -0
@@ -1,117 +0,0 @@
|
|
1
|
-
import inspect
|
2
|
-
import re
|
3
|
-
from typing import List, Type
|
4
|
-
|
5
|
-
from flask import current_app
|
6
|
-
from invenio_records_permissions import BasePermissionPolicy
|
7
|
-
|
8
|
-
from oarepo_runtime.utils.functools import class_property
|
9
|
-
|
10
|
-
|
11
|
-
class PermissionsPresetsConfigMixin:
|
12
|
-
components = tuple()
|
13
|
-
PERMISSIONS_PRESETS_CONFIG_KEY = None
|
14
|
-
# PERMISSIONS_PRESETS = [] # noqa (omitted here because of the order of mixins)
|
15
|
-
|
16
|
-
@class_property
|
17
|
-
def permission_policy_cls(cls):
|
18
|
-
"""
|
19
|
-
Returns a class that contains all permissions from the presets.
|
20
|
-
|
21
|
-
Needs to be a class property as invenio-vocabularies, unlike other invenio records,
|
22
|
-
do not instantiate the service configuration class, but use it as a class.
|
23
|
-
"""
|
24
|
-
presets = cls._get_preset_classes()
|
25
|
-
|
26
|
-
permissions = {}
|
27
|
-
for preset_class in presets:
|
28
|
-
for permission_name, permission_needs in cls._get_permissions_from_preset(
|
29
|
-
preset_class
|
30
|
-
):
|
31
|
-
target = permissions.setdefault(permission_name, [])
|
32
|
-
for need in permission_needs:
|
33
|
-
if need not in target:
|
34
|
-
target.append(need)
|
35
|
-
|
36
|
-
return type(f"{cls.__name__}Permissions", tuple(presets), permissions)
|
37
|
-
|
38
|
-
@staticmethod
|
39
|
-
def _get_permissions_from_preset(preset_class):
|
40
|
-
for permission_name, permission_needs in inspect.getmembers(preset_class):
|
41
|
-
if not permission_name.startswith("can_"):
|
42
|
-
continue
|
43
|
-
if not isinstance(permission_needs, (list, tuple)):
|
44
|
-
continue
|
45
|
-
yield permission_name, permission_needs
|
46
|
-
|
47
|
-
@classmethod
|
48
|
-
def _get_preset_classes(cls) -> List[Type[BasePermissionPolicy]]:
|
49
|
-
"""
|
50
|
-
Returns a list of permission presets classes to be used for this service.
|
51
|
-
|
52
|
-
The list is read from the configuration, if it exists, otherwise it returns
|
53
|
-
the default value from the class attribute PERMISSIONS_PRESETS.
|
54
|
-
"""
|
55
|
-
registered_preset_classes = current_app.config["OAREPO_PERMISSIONS_PRESETS"]
|
56
|
-
preset_classes = []
|
57
|
-
for x in cls._get_permissions_presets():
|
58
|
-
if isinstance(x, str):
|
59
|
-
preset_classes.append(registered_preset_classes[x])
|
60
|
-
else:
|
61
|
-
preset_classes.append(x)
|
62
|
-
|
63
|
-
if hasattr(cls, "base_permission_policy_cls"):
|
64
|
-
preset_classes.insert(0, cls.base_permission_policy_cls)
|
65
|
-
return preset_classes
|
66
|
-
|
67
|
-
@classmethod
|
68
|
-
def _get_permissions_presets(cls):
|
69
|
-
"""
|
70
|
-
Returns a list of names of permissions presets to be used for this service.
|
71
|
-
|
72
|
-
The list is read from the configuration, if it exists, otherwise it returns
|
73
|
-
the default value from the class attribute PERMISSIONS_PRESETS.
|
74
|
-
"""
|
75
|
-
config_key = cls._get_presents_config_key()
|
76
|
-
if config_key in current_app.config:
|
77
|
-
return current_app.config[config_key]
|
78
|
-
return (
|
79
|
-
cls.PERMISSIONS_PRESETS
|
80
|
-
) # noqa (omitted here because of the order of mixins)
|
81
|
-
|
82
|
-
@classmethod
|
83
|
-
def _get_presents_config_key(cls):
|
84
|
-
"""
|
85
|
-
Returns the name of the configuration key that contains the list of
|
86
|
-
permissions presets to be used for this service.
|
87
|
-
|
88
|
-
The key is read from the class attribute PERMISSIONS_PRESETS_CONFIG_KEY.
|
89
|
-
If it is not set, the key is generated from the name of the service
|
90
|
-
configuration class (MyServiceConfig becomes MY_SERVICE_PERMISSIONS_PRESETS).
|
91
|
-
"""
|
92
|
-
if cls.PERMISSIONS_PRESETS_CONFIG_KEY:
|
93
|
-
return cls.PERMISSIONS_PRESETS_CONFIG_KEY
|
94
|
-
|
95
|
-
# use the base class of the service config file (e.g. MyServiceConfig),
|
96
|
-
# remove the "Config" part and convert it to snake uppercase.
|
97
|
-
# add "_PERMISSIONS_PRESETS" at the end.
|
98
|
-
name = cls.__name__
|
99
|
-
if name.endswith("Config"):
|
100
|
-
name = name[:-6]
|
101
|
-
name = re.sub(r"(?<!^)(?=[A-Z])", "_", name).upper()
|
102
|
-
return f"{name}_PERMISSIONS_PRESETS"
|
103
|
-
|
104
|
-
class SearchAllConfigMixin:
|
105
|
-
@property
|
106
|
-
def search_all(self):
|
107
|
-
from invenio_rdm_records.services.search_params import MyDraftsParam
|
108
|
-
if hasattr(self, "search_drafts"):
|
109
|
-
class AllSearchOptions(self.search_drafts):
|
110
|
-
@class_property
|
111
|
-
def params_interpreters_cls(cls):
|
112
|
-
param_interpreters = [*super().params_interpreters_cls]
|
113
|
-
param_interpreters.remove(MyDraftsParam)
|
114
|
-
return param_interpreters
|
115
|
-
return AllSearchOptions
|
116
|
-
else:
|
117
|
-
return self.search
|
@@ -1,80 +0,0 @@
|
|
1
|
-
from typing import List
|
2
|
-
|
3
|
-
from flask import current_app
|
4
|
-
from invenio_records.systemfields import DictField, SystemField
|
5
|
-
from invenio_records_resources.services.custom_fields import BaseCF
|
6
|
-
|
7
|
-
from oarepo_runtime.records.systemfields.mapping import MappingSystemFieldMixin
|
8
|
-
|
9
|
-
|
10
|
-
class CustomFieldsMixin(MappingSystemFieldMixin):
|
11
|
-
def __init__(self, config_key, *args, **kwargs) -> None:
|
12
|
-
super().__init__(*args, **kwargs)
|
13
|
-
self.config_key = config_key
|
14
|
-
|
15
|
-
@property
|
16
|
-
def mapping(self):
|
17
|
-
custom_fields: List[BaseCF] = current_app.config[self.config_key]
|
18
|
-
return {cf.name: cf.mapping for cf in custom_fields}
|
19
|
-
|
20
|
-
@property
|
21
|
-
def mapping_settings(self):
|
22
|
-
return {}
|
23
|
-
|
24
|
-
def search_dump(self, data, record):
|
25
|
-
custom_fields = current_app.config.get(self.config_key, {})
|
26
|
-
|
27
|
-
for cf in custom_fields:
|
28
|
-
cf.dump(data, cf_key=self.key)
|
29
|
-
return data
|
30
|
-
|
31
|
-
def search_load(self, data, record_cls):
|
32
|
-
custom_fields = current_app.config.get(self.config_key, {})
|
33
|
-
|
34
|
-
for cf in custom_fields:
|
35
|
-
cf.load(data, cf_key=self.key)
|
36
|
-
return data
|
37
|
-
|
38
|
-
|
39
|
-
class CustomFields(CustomFieldsMixin, DictField):
|
40
|
-
@property
|
41
|
-
def mapping(self):
|
42
|
-
return {self.key: {"type": "object", "properties": super().mapping}}
|
43
|
-
|
44
|
-
|
45
|
-
class InlinedCustomFields(CustomFieldsMixin, SystemField):
|
46
|
-
|
47
|
-
def __get__(self, record, owner=None):
|
48
|
-
"""Getting the attribute value."""
|
49
|
-
if record is None:
|
50
|
-
return self
|
51
|
-
return self.get_dictkey(record)
|
52
|
-
|
53
|
-
def __set__(self, record, value):
|
54
|
-
"""Setting a new value."""
|
55
|
-
self.set_dictkey(record, value)
|
56
|
-
|
57
|
-
|
58
|
-
class InlinedCustomFieldsSchemaMixin:
|
59
|
-
CUSTOM_FIELDS_VAR = None
|
60
|
-
CUSTOM_FIELDS_FIELD_PROPERTY = "field"
|
61
|
-
|
62
|
-
def __init__(self, *args, **kwargs) -> None:
|
63
|
-
super().__init__(*args, **kwargs)
|
64
|
-
|
65
|
-
if self.CUSTOM_FIELDS_VAR is None:
|
66
|
-
raise AttributeError(
|
67
|
-
"CUSTOM_FIELDS_VAR field must be set to the name of config variable containing an array of custom fields"
|
68
|
-
)
|
69
|
-
custom_fields = current_app.config.get(self.CUSTOM_FIELDS_VAR, [])
|
70
|
-
if not isinstance(custom_fields, (list, tuple)):
|
71
|
-
raise AttributeError("CUSTOM_FIELDS_VAR must be a list or tuple")
|
72
|
-
for cf in custom_fields:
|
73
|
-
self.declared_fields[cf.name] = getattr(
|
74
|
-
cf, self.CUSTOM_FIELDS_FIELD_PROPERTY
|
75
|
-
)
|
76
|
-
self._init_fields()
|
77
|
-
|
78
|
-
|
79
|
-
class InlinedUICustomFieldsSchemaMixin(InlinedCustomFieldsSchemaMixin):
|
80
|
-
CUSTOM_FIELDS_FIELD_PROPERTY = "ui_field"
|
@@ -1,188 +0,0 @@
|
|
1
|
-
import inspect
|
2
|
-
from typing import Iterable
|
3
|
-
|
4
|
-
import click
|
5
|
-
import deepmerge
|
6
|
-
from invenio_records_resources.proxies import current_service_registry
|
7
|
-
from invenio_records_resources.services.custom_fields.mappings import (
|
8
|
-
Mapping as InvenioMapping,
|
9
|
-
)
|
10
|
-
from invenio_records_resources.services.records.config import RecordServiceConfig
|
11
|
-
from invenio_records_resources.services.records.service import RecordService
|
12
|
-
from invenio_search.engine import search
|
13
|
-
from deepmerge import always_merger
|
14
|
-
from oarepo_runtime.records.systemfields.mapping import MappingSystemFieldMixin
|
15
|
-
import json
|
16
|
-
|
17
|
-
from pathlib import Path
|
18
|
-
|
19
|
-
from oarepo_runtime.utils.index import prefixed_index
|
20
|
-
|
21
|
-
|
22
|
-
class Mapping(InvenioMapping):
|
23
|
-
@classmethod
|
24
|
-
def properties_for_fields(
|
25
|
-
cls, given_fields_names, available_fields, field_name="custom_fields"
|
26
|
-
):
|
27
|
-
"""Prepare search mapping properties for each field."""
|
28
|
-
|
29
|
-
properties = {}
|
30
|
-
for field in cls._get_fields(given_fields_names, available_fields):
|
31
|
-
if field_name:
|
32
|
-
properties[f"{field_name}.{field.name}"] = field.mapping
|
33
|
-
else:
|
34
|
-
properties[field.name] = field.mapping
|
35
|
-
|
36
|
-
return properties
|
37
|
-
|
38
|
-
@classmethod
|
39
|
-
def settings_for_fields(
|
40
|
-
cls, given_fields_names, available_fields, field_name="custom_fields"
|
41
|
-
):
|
42
|
-
"""Prepare mapping settings for each field."""
|
43
|
-
|
44
|
-
settings = {}
|
45
|
-
for field in cls._get_fields(given_fields_names, available_fields):
|
46
|
-
if not hasattr(field, "mapping_settings"):
|
47
|
-
continue
|
48
|
-
settings = deepmerge.always_merger.merge(settings, field.mapping_settings)
|
49
|
-
|
50
|
-
return settings
|
51
|
-
|
52
|
-
@classmethod
|
53
|
-
def _get_fields(cls, given_fields_names, available_fields):
|
54
|
-
fields = []
|
55
|
-
if given_fields_names: # create only specified fields
|
56
|
-
given_fields_names = set(given_fields_names)
|
57
|
-
for a_field in available_fields:
|
58
|
-
if a_field.name in given_fields_names:
|
59
|
-
fields.append(a_field)
|
60
|
-
given_fields_names.remove(a_field.name)
|
61
|
-
if len(given_fields_names) == 0:
|
62
|
-
break
|
63
|
-
else: # create all fields
|
64
|
-
fields = available_fields
|
65
|
-
return fields
|
66
|
-
|
67
|
-
|
68
|
-
# pieces taken from https://github.com/inveniosoftware/invenio-rdm-records/blob/master/invenio_rdm_records/cli.py
|
69
|
-
# as cf initialization is not supported directly in plain invenio
|
70
|
-
def prepare_cf_indices():
|
71
|
-
service: RecordService
|
72
|
-
for service in current_service_registry._services.values():
|
73
|
-
config: RecordServiceConfig = service.config
|
74
|
-
record_class = getattr(config, "record_cls", None)
|
75
|
-
if record_class:
|
76
|
-
prepare_cf_index(record_class, config)
|
77
|
-
parent_class = getattr(record_class, "parent_record_cls", None)
|
78
|
-
prepare_parent_mapping(parent_class, config)
|
79
|
-
prepare_cf_index(parent_class, config, path=["parent", "properties"])
|
80
|
-
|
81
|
-
|
82
|
-
def prepare_cf_index(record_class, config, path=[]):
|
83
|
-
if not record_class:
|
84
|
-
return
|
85
|
-
|
86
|
-
for fld in get_mapping_fields(record_class):
|
87
|
-
# get mapping
|
88
|
-
mapping = fld.mapping
|
89
|
-
settings = fld.mapping_settings
|
90
|
-
dynamic_templates = fld.dynamic_templates
|
91
|
-
|
92
|
-
for pth in reversed(path):
|
93
|
-
mapping = {pth: mapping}
|
94
|
-
|
95
|
-
# upload mapping
|
96
|
-
try:
|
97
|
-
record_index = prefixed_index(config.record_cls.index)
|
98
|
-
update_index(record_index, settings, mapping)
|
99
|
-
|
100
|
-
if hasattr(config, "draft_cls"):
|
101
|
-
draft_index = prefixed_index(config.draft_cls.index)
|
102
|
-
update_index(draft_index, settings, mapping, dynamic_templates)
|
103
|
-
|
104
|
-
except search.RequestError as e:
|
105
|
-
click.secho("An error occurred while creating custom fields.", fg="red")
|
106
|
-
click.secho(e.info["error"]["reason"], fg="red")
|
107
|
-
|
108
|
-
|
109
|
-
def prepare_parent_mapping(parent_class, config):
|
110
|
-
if not parent_class:
|
111
|
-
return
|
112
|
-
|
113
|
-
if not config.record_cls.index._name:
|
114
|
-
return
|
115
|
-
|
116
|
-
script_dir = str(Path(__file__).resolve().parent)
|
117
|
-
path_parts = script_dir.split('/')
|
118
|
-
path_parts = path_parts[:-2]
|
119
|
-
base_path = '/'.join(path_parts)
|
120
|
-
mapping_path = f"{base_path}/records/mappings/rdm_parent_mapping.json"
|
121
|
-
|
122
|
-
with open(mapping_path, 'r') as f:
|
123
|
-
rdm_parent = json.load(f)
|
124
|
-
|
125
|
-
parent_mapping = {
|
126
|
-
"parent": {
|
127
|
-
"type": "object",
|
128
|
-
"properties": {
|
129
|
-
"created": {
|
130
|
-
"type": "date",
|
131
|
-
"format": "strict_date_time||strict_date_time_no_millis||basic_date_time||basic_date_time_no_millis||basic_date||strict_date||strict_date_hour_minute_second||strict_date_hour_minute_second_fraction",
|
132
|
-
},
|
133
|
-
"id": {"type": "keyword", "ignore_above": 1024},
|
134
|
-
"pid": {
|
135
|
-
"properties": {
|
136
|
-
"obj_type": {"type": "keyword", "ignore_above": 1024},
|
137
|
-
"pid_type": {"type": "keyword", "ignore_above": 1024},
|
138
|
-
"pk": {"type": "long"},
|
139
|
-
"status": {"type": "keyword", "ignore_above": 1024},
|
140
|
-
}
|
141
|
-
},
|
142
|
-
"updated": {
|
143
|
-
"type": "date",
|
144
|
-
"format": "strict_date_time||strict_date_time_no_millis||basic_date_time||basic_date_time_no_millis||basic_date||strict_date||strict_date_hour_minute_second||strict_date_hour_minute_second_fraction",
|
145
|
-
},
|
146
|
-
"uuid": {"type": "keyword", "ignore_above": 1024},
|
147
|
-
"version_id": {"type": "long"},
|
148
|
-
},
|
149
|
-
}
|
150
|
-
}
|
151
|
-
parent_mapping_merged = always_merger.merge(parent_mapping, {
|
152
|
-
"parent": {
|
153
|
-
"properties": rdm_parent
|
154
|
-
}
|
155
|
-
})
|
156
|
-
# upload mapping
|
157
|
-
try:
|
158
|
-
record_index = prefixed_index(config.record_cls.index)
|
159
|
-
update_index(record_index, {}, parent_mapping_merged)
|
160
|
-
|
161
|
-
if hasattr(config, "draft_cls"):
|
162
|
-
draft_index = prefixed_index(config.draft_cls.index) # draft index isn't used; this was a bug a suppose
|
163
|
-
update_index(draft_index, {}, parent_mapping_merged)
|
164
|
-
|
165
|
-
except search.RequestError as e:
|
166
|
-
click.secho("An error occurred while creating parent mapping.", fg="red")
|
167
|
-
click.secho(e.info["error"]["reason"], fg="red")
|
168
|
-
|
169
|
-
|
170
|
-
def update_index(record_index, settings, mapping, dynamic_templates=None):
|
171
|
-
if settings:
|
172
|
-
record_index.close()
|
173
|
-
record_index.put_settings(body=settings)
|
174
|
-
record_index.open()
|
175
|
-
body = {}
|
176
|
-
if mapping:
|
177
|
-
body["properties"] = mapping
|
178
|
-
if dynamic_templates:
|
179
|
-
body["dynamic_templates"] = dynamic_templates
|
180
|
-
if body:
|
181
|
-
record_index.put_mapping(body=body)
|
182
|
-
|
183
|
-
|
184
|
-
def get_mapping_fields(record_class) -> Iterable[MappingSystemFieldMixin]:
|
185
|
-
for cfg_name, cfg_value in inspect.getmembers(
|
186
|
-
record_class, lambda x: isinstance(x, MappingSystemFieldMixin)
|
187
|
-
):
|
188
|
-
yield cfg_value
|
File without changes
|
@@ -1,14 +0,0 @@
|
|
1
|
-
from invenio_records_resources.services.base.config import ServiceConfig
|
2
|
-
|
3
|
-
from ..results import ArrayRecordItem, ArrayRecordList
|
4
|
-
from .schema import KeywordEntitySchema
|
5
|
-
|
6
|
-
|
7
|
-
class EntityServiceConfig(ServiceConfig):
|
8
|
-
links_item = {}
|
9
|
-
result_item_cls = ArrayRecordItem
|
10
|
-
result_list_cls = ArrayRecordList
|
11
|
-
|
12
|
-
|
13
|
-
class KeywordEntityServiceConfig(EntityServiceConfig):
|
14
|
-
schema = KeywordEntitySchema
|
@@ -1,48 +0,0 @@
|
|
1
|
-
import abc
|
2
|
-
from typing import Iterable
|
3
|
-
|
4
|
-
from invenio_records_resources.services.base.links import LinksTemplate
|
5
|
-
from invenio_records_resources.services.base.service import Service
|
6
|
-
from invenio_records_resources.services.records.schema import ServiceSchemaWrapper
|
7
|
-
|
8
|
-
|
9
|
-
class EntityService(Service):
|
10
|
-
@property
|
11
|
-
def links_item_tpl(self):
|
12
|
-
"""Item links template."""
|
13
|
-
return LinksTemplate(
|
14
|
-
self.config.links_item,
|
15
|
-
)
|
16
|
-
|
17
|
-
@property
|
18
|
-
def schema(self):
|
19
|
-
"""Returns the data schema instance."""
|
20
|
-
return ServiceSchemaWrapper(self, schema=self.config.schema)
|
21
|
-
|
22
|
-
@abc.abstractmethod
|
23
|
-
def read(self, identity, id_, **kwargs):
|
24
|
-
raise NotImplementedError()
|
25
|
-
|
26
|
-
@abc.abstractmethod
|
27
|
-
def read_many(self, identity, ids: Iterable[str], fields=None, **kwargs):
|
28
|
-
raise NotImplementedError()
|
29
|
-
|
30
|
-
|
31
|
-
class KeywordEntityService(EntityService):
|
32
|
-
|
33
|
-
def read(self, identity, id_, **kwargs):
|
34
|
-
result = {"keyword": self.config.keyword, "id": id_}
|
35
|
-
return self.result_item(
|
36
|
-
self, identity, record=result, links_tpl=self.links_item_tpl
|
37
|
-
)
|
38
|
-
|
39
|
-
def read_many(self, identity, ids: Iterable[str], fields=None, **kwargs):
|
40
|
-
if not ids:
|
41
|
-
return []
|
42
|
-
results = [{"keyword": self.config.keyword, "id": id} for id in ids]
|
43
|
-
return self.result_list(
|
44
|
-
self,
|
45
|
-
identity,
|
46
|
-
results=results,
|
47
|
-
links_item_tpl=self.links_item_tpl,
|
48
|
-
)
|
File without changes
|
@@ -1,21 +0,0 @@
|
|
1
|
-
from invenio_records.dictutils import dict_lookup, dict_set
|
2
|
-
from invenio_records_resources.services.records.results import ExpandableField
|
3
|
-
|
4
|
-
|
5
|
-
class ReferencedRecordExpandableField(ExpandableField):
|
6
|
-
def __init__(self, field_name, keys, service, pid_field="id"):
|
7
|
-
super().__init__(field_name)
|
8
|
-
self.keys = keys
|
9
|
-
self.pid_field = pid_field
|
10
|
-
self.service = service
|
11
|
-
|
12
|
-
def get_value_service(self, value):
|
13
|
-
if self.pid_field is None:
|
14
|
-
return value, self.service
|
15
|
-
return dict_lookup(value, self.pid_field), self.service
|
16
|
-
|
17
|
-
def pick(self, identity, resolved_rec):
|
18
|
-
ret = {}
|
19
|
-
for key in self.keys:
|
20
|
-
dict_set(ret, key, dict_lookup(resolved_rec, key))
|
21
|
-
return ret
|
@@ -1,33 +0,0 @@
|
|
1
|
-
from .base import LabelledValuesTermsFacet
|
2
|
-
from .date import (
|
3
|
-
AutoDateHistogramFacet,
|
4
|
-
DateFacet,
|
5
|
-
DateIntervalFacet,
|
6
|
-
DateTimeFacet,
|
7
|
-
EDTFIntervalFacet,
|
8
|
-
TimeFacet,
|
9
|
-
)
|
10
|
-
from .enum import EnumTermsFacet
|
11
|
-
from .facet_groups_names import facet_groups_names
|
12
|
-
from .max_facet import MaxFacet
|
13
|
-
from .nested_facet import NestedLabeledFacet
|
14
|
-
from .params import FilteredFacetsParam, GroupedFacetsParam
|
15
|
-
from .year_histogram import YearAutoHistogramFacet
|
16
|
-
from .multilingual_facet import MultilingualFacet
|
17
|
-
__all__ = [
|
18
|
-
"LabelledValuesTermsFacet",
|
19
|
-
"DateFacet",
|
20
|
-
"TimeFacet",
|
21
|
-
"DateTimeFacet",
|
22
|
-
"AutoDateHistogramFacet",
|
23
|
-
"EDTFIntervalFacet",
|
24
|
-
"DateIntervalFacet",
|
25
|
-
"EnumTermsFacet",
|
26
|
-
"facet_groups_names",
|
27
|
-
"MaxFacet",
|
28
|
-
"NestedLabeledFacet",
|
29
|
-
"GroupedFacetsParam",
|
30
|
-
"FilteredFacetsParam",
|
31
|
-
"YearAutoHistogramFacet",
|
32
|
-
"MultilingualFacet"
|
33
|
-
]
|
@@ -1,12 +0,0 @@
|
|
1
|
-
from invenio_records_resources.services.records.facets import TermsFacet
|
2
|
-
|
3
|
-
|
4
|
-
class LabelledValuesTermsFacet(TermsFacet):
|
5
|
-
def __init__(self, *args, **kwargs):
|
6
|
-
super().__init__(*args, **{"value_labels": self.value_labels, **kwargs})
|
7
|
-
|
8
|
-
def localized_value_labels(self, values, locale):
|
9
|
-
return {val: val for val in values}
|
10
|
-
|
11
|
-
def value_labels(self, values):
|
12
|
-
return {val: val for val in values}
|
@@ -1,72 +0,0 @@
|
|
1
|
-
import re
|
2
|
-
|
3
|
-
from invenio_records_resources.services.records.facets.facets import LabelledFacetMixin
|
4
|
-
from invenio_search.engine import dsl
|
5
|
-
|
6
|
-
from oarepo_runtime.services.schema.ui import (
|
7
|
-
LocalizedDate,
|
8
|
-
LocalizedDateTime,
|
9
|
-
LocalizedEDTF,
|
10
|
-
LocalizedEDTFInterval,
|
11
|
-
LocalizedTime,
|
12
|
-
)
|
13
|
-
|
14
|
-
from .base import LabelledValuesTermsFacet
|
15
|
-
|
16
|
-
|
17
|
-
class DateFacet(LabelledValuesTermsFacet):
|
18
|
-
def localized_value_labels(self, values, locale):
|
19
|
-
return {val: LocalizedDate(locale=locale).format_value(val) for val in values}
|
20
|
-
|
21
|
-
|
22
|
-
class TimeFacet(LabelledValuesTermsFacet):
|
23
|
-
def localized_value_labels(self, values, locale):
|
24
|
-
return {val: LocalizedTime(locale=locale).format_value(val) for val in values}
|
25
|
-
|
26
|
-
|
27
|
-
class DateTimeFacet(LabelledValuesTermsFacet):
|
28
|
-
def localized_value_labels(self, values, locale):
|
29
|
-
return {
|
30
|
-
val: LocalizedDateTime(locale=locale).format_value(val) for val in values
|
31
|
-
}
|
32
|
-
|
33
|
-
|
34
|
-
class EDTFFacet(LabelledValuesTermsFacet):
|
35
|
-
def localized_value_labels(self, values, locale):
|
36
|
-
return {
|
37
|
-
val: LocalizedEDTF(locale=locale).format_value(convert_to_edtf(val))
|
38
|
-
for val in values
|
39
|
-
}
|
40
|
-
|
41
|
-
|
42
|
-
class AutoDateHistogramFacet(dsl.DateHistogramFacet):
|
43
|
-
agg_type = "auto_date_histogram"
|
44
|
-
|
45
|
-
def __init__(self, **kwargs):
|
46
|
-
# skip DateHistogramFacet constructor
|
47
|
-
super(dsl.DateHistogramFacet, self).__init__(**kwargs)
|
48
|
-
|
49
|
-
|
50
|
-
class EDTFIntervalFacet(LabelledFacetMixin, AutoDateHistogramFacet):
|
51
|
-
# auto_date_histogram
|
52
|
-
def __init__(self, *args, **kwargs):
|
53
|
-
super().__init__(*args, **kwargs)
|
54
|
-
|
55
|
-
def localized_value_labels(self, values, locale):
|
56
|
-
return {
|
57
|
-
val: LocalizedEDTFInterval(locale=locale).format_value(convert_to_edtf(val))
|
58
|
-
for val in values
|
59
|
-
}
|
60
|
-
|
61
|
-
|
62
|
-
class DateIntervalFacet(EDTFIntervalFacet):
|
63
|
-
pass
|
64
|
-
|
65
|
-
|
66
|
-
def convert_to_edtf(val):
|
67
|
-
if "/" in val:
|
68
|
-
# interval
|
69
|
-
return "/".join(convert_to_edtf(x) for x in val.split("/"))
|
70
|
-
val = re.sub(r"T.*", "", val) # replace T12:00:00.000Z with nothing
|
71
|
-
print(val)
|
72
|
-
return val
|
@@ -1,11 +0,0 @@
|
|
1
|
-
from .base import LabelledValuesTermsFacet
|
2
|
-
|
3
|
-
|
4
|
-
class EnumTermsFacet(LabelledValuesTermsFacet):
|
5
|
-
# TODO: https://github.com/oarepo/oarepo-runtime/issues/43
|
6
|
-
pass
|
7
|
-
# def value_labels(self, values):
|
8
|
-
# field = self._params["field"]
|
9
|
-
# field_path = field.replace(".", "/")
|
10
|
-
# field_enum = f"{field_path}.enum."
|
11
|
-
# return {val: lazy_gettext(f"{field_enum}{val}") for val in values}
|
@@ -1,17 +0,0 @@
|
|
1
|
-
from typing import List
|
2
|
-
|
3
|
-
from flask_principal import Identity
|
4
|
-
from invenio_records_resources.services import SearchOptions as InvenioSearchOptions
|
5
|
-
|
6
|
-
|
7
|
-
def facet_groups_names(
|
8
|
-
identity: Identity, search_options: InvenioSearchOptions, params
|
9
|
-
) -> List[str]:
|
10
|
-
"""
|
11
|
-
Default implementation for Flask-principal identity.
|
12
|
-
"""
|
13
|
-
|
14
|
-
if hasattr(identity, "provides"):
|
15
|
-
return [need.value for need in identity.provides if need.method == "role"]
|
16
|
-
|
17
|
-
return []
|
@@ -1,13 +0,0 @@
|
|
1
|
-
from invenio_records_resources.services.records.facets.facets import LabelledFacetMixin
|
2
|
-
from opensearch_dsl import Facet
|
3
|
-
|
4
|
-
|
5
|
-
class MaxFacet(LabelledFacetMixin, Facet):
|
6
|
-
agg_type = "max"
|
7
|
-
|
8
|
-
def get_labelled_values(self, data, filter_values):
|
9
|
-
value = None
|
10
|
-
if "value_as_string" in data:
|
11
|
-
value = data["value_as_string"]
|
12
|
-
|
13
|
-
return {"label": str(self._label), "value": value}
|