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.
- oarepo_runtime/__init__.py +24 -0
- oarepo_runtime/api.py +210 -0
- oarepo_runtime/cli/__init__.py +10 -21
- oarepo_runtime/cli/search.py +34 -0
- oarepo_runtime/config.py +98 -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 +61 -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/facets/__init__.py +12 -33
- oarepo_runtime/services/facets/params.py +45 -110
- 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.3.dist-info → oarepo_runtime-2.0.0.dev4.dist-info}/METADATA +10 -21
- oarepo_runtime-2.0.0.dev4.dist-info/RECORD +32 -0
- {oarepo_runtime-1.10.3.dist-info → oarepo_runtime-2.0.0.dev4.dist-info}/WHEEL +1 -2
- oarepo_runtime-2.0.0.dev4.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/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/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 -146
- 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 -95
- 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 -97
- oarepo_runtime/translations/messages.pot +0 -100
- 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.3.dist-info/RECORD +0 -163
- oarepo_runtime-1.10.3.dist-info/entry_points.txt +0 -16
- oarepo_runtime-1.10.3.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.3.dist-info → oarepo_runtime-2.0.0.dev4.dist-info}/licenses/LICENSE +0 -0
@@ -1,32 +0,0 @@
|
|
1
|
-
from invenio_search.engine import dsl
|
2
|
-
|
3
|
-
|
4
|
-
class NestedLabeledFacet(dsl.Facet):
|
5
|
-
agg_type = "nested"
|
6
|
-
|
7
|
-
def __init__(self, path, nested_facet, label=""):
|
8
|
-
self._path = path
|
9
|
-
self._inner = nested_facet
|
10
|
-
self._label = label
|
11
|
-
super(NestedLabeledFacet, self).__init__(
|
12
|
-
path=path,
|
13
|
-
aggs={
|
14
|
-
"inner": nested_facet.get_aggregation(),
|
15
|
-
},
|
16
|
-
)
|
17
|
-
|
18
|
-
def get_values(self, data, filter_values):
|
19
|
-
return self._inner.get_values(data.inner, filter_values)
|
20
|
-
|
21
|
-
def add_filter(self, filter_values):
|
22
|
-
inner_q = self._inner.add_filter(filter_values)
|
23
|
-
if inner_q:
|
24
|
-
return dsl.Nested(path=self._path, query=inner_q)
|
25
|
-
|
26
|
-
def get_labelled_values(self, data, filter_values):
|
27
|
-
"""Get a labelled version of a bucket."""
|
28
|
-
try:
|
29
|
-
out = data["buckets"]
|
30
|
-
except KeyError:
|
31
|
-
out = []
|
32
|
-
return {"buckets": out, "label": str(self._label)}
|
@@ -1,200 +0,0 @@
|
|
1
|
-
import re
|
2
|
-
from typing import Dict, List
|
3
|
-
|
4
|
-
from invenio_records_resources.services.records.facets.facets import LabelledFacetMixin
|
5
|
-
from invenio_search.engine import dsl
|
6
|
-
|
7
|
-
|
8
|
-
class YearAutoHistogramFacet(LabelledFacetMixin, dsl.Facet):
|
9
|
-
"""Histogram facet.
|
10
|
-
|
11
|
-
.. code-block:: python
|
12
|
-
|
13
|
-
facets = {
|
14
|
-
'year': IntegerHistogramFacet(
|
15
|
-
field='year',
|
16
|
-
label=_('Year'),
|
17
|
-
size=1000000
|
18
|
-
)
|
19
|
-
}
|
20
|
-
|
21
|
-
Usage in the oarepo model together with SyntheticSystemField::
|
22
|
-
record:
|
23
|
-
record:
|
24
|
-
imports:
|
25
|
-
- import: oarepo_runtime.records.systemfields.SyntheticSystemField
|
26
|
-
- import: oarepo_runtime.records.systemfields.PathSelector
|
27
|
-
fields:
|
28
|
-
year: |
|
29
|
-
SyntheticSystemField(
|
30
|
-
selector=PathSelector("metadata.date"),
|
31
|
-
key="year",
|
32
|
-
filter=lambda x: len(x) >= 4,
|
33
|
-
map=lambda x: x[:4]
|
34
|
-
)
|
35
|
-
properties:
|
36
|
-
year:
|
37
|
-
facets:
|
38
|
-
facet-class: oarepo_runtime.services.facets.year_histogram.YearAutoHistogramFacet
|
39
|
-
type: edtf
|
40
|
-
"""
|
41
|
-
|
42
|
-
agg_type = "auto_date_histogram"
|
43
|
-
|
44
|
-
def __init__(self, **kwargs):
|
45
|
-
self._min_doc_count = kwargs.pop("min_doc_count", 0)
|
46
|
-
buckets = kwargs.pop("buckets", 20)
|
47
|
-
# TODO: the minimum interval should be year, but opensearch does not support it yet
|
48
|
-
super().__init__(
|
49
|
-
**kwargs, buckets=buckets, format="yyyy", minimum_interval="month"
|
50
|
-
)
|
51
|
-
|
52
|
-
def get_value_filter(self, filter_value):
|
53
|
-
if "/" in filter_value:
|
54
|
-
start, end = filter_value.split("/")
|
55
|
-
return dsl.query.Range(
|
56
|
-
_expand__to_dot=False,
|
57
|
-
**{
|
58
|
-
self._params["field"]: {
|
59
|
-
"gte": f"{start}-01-01",
|
60
|
-
"lte": f"{end}-12-31",
|
61
|
-
}
|
62
|
-
},
|
63
|
-
)
|
64
|
-
return dsl.query.Term(
|
65
|
-
_expand__to_dot=False,
|
66
|
-
**{
|
67
|
-
self._params["field"]: {
|
68
|
-
"gte": f"{filter_value}-01-01",
|
69
|
-
"lte": f"{filter_value}-12-31",
|
70
|
-
}
|
71
|
-
},
|
72
|
-
)
|
73
|
-
|
74
|
-
def add_filter(self, filter_values):
|
75
|
-
ret = super().add_filter(filter_values)
|
76
|
-
return ret
|
77
|
-
|
78
|
-
def get_labelled_values(self, data, filter_values):
|
79
|
-
"""Get a labelled version of a bucket."""
|
80
|
-
|
81
|
-
# fix for opensearch bug
|
82
|
-
data = self.fix_yearly_interval(data)
|
83
|
-
|
84
|
-
interval = data["interval"]
|
85
|
-
|
86
|
-
interval_in_years = int(re.sub(r"\D", "", interval))
|
87
|
-
|
88
|
-
buckets = data["buckets"]
|
89
|
-
|
90
|
-
for bucket in buckets:
|
91
|
-
bucket["interval"] = interval_in_years
|
92
|
-
|
93
|
-
if self._min_doc_count > 0:
|
94
|
-
buckets = self._merge_small_buckets(buckets)
|
95
|
-
|
96
|
-
out_buckets = []
|
97
|
-
for i, bucket in enumerate(buckets):
|
98
|
-
value = int(bucket["key_as_string"].split("-")[0])
|
99
|
-
|
100
|
-
out_buckets.append(
|
101
|
-
{
|
102
|
-
**bucket,
|
103
|
-
"interval": f"{bucket['interval']}y",
|
104
|
-
"start": str(value),
|
105
|
-
}
|
106
|
-
)
|
107
|
-
if i > 0:
|
108
|
-
out_buckets[i - 1]["end"] = str(value - 1)
|
109
|
-
|
110
|
-
if out_buckets:
|
111
|
-
out_buckets[-1]["end"] = str(
|
112
|
-
int(out_buckets[-1]["start"]) + interval_in_years - 1
|
113
|
-
)
|
114
|
-
|
115
|
-
return {
|
116
|
-
"buckets": out_buckets,
|
117
|
-
"label": str(self._label),
|
118
|
-
"interval": interval,
|
119
|
-
}
|
120
|
-
|
121
|
-
def merge_buckets(self, buckets):
|
122
|
-
merged = {}
|
123
|
-
|
124
|
-
for bucket in buckets:
|
125
|
-
key = bucket["key_as_string"]
|
126
|
-
if key not in merged:
|
127
|
-
merged[key] = {
|
128
|
-
"key_as_string": key,
|
129
|
-
"key": bucket["key"],
|
130
|
-
"doc_count": 0,
|
131
|
-
}
|
132
|
-
|
133
|
-
merged[key]["doc_count"] += bucket["doc_count"]
|
134
|
-
|
135
|
-
result = list(merged.values())
|
136
|
-
return result
|
137
|
-
|
138
|
-
def fix_yearly_interval(self, data) -> Dict:
|
139
|
-
"""
|
140
|
-
Currently opensearch has a bug that does not allow to set minimum_interval to year.
|
141
|
-
This function will fix the interval to be yearly if the minimum_interval is has lower value.
|
142
|
-
"""
|
143
|
-
data = data.to_dict()
|
144
|
-
|
145
|
-
interval = data["interval"]
|
146
|
-
|
147
|
-
if interval.endswith("y"):
|
148
|
-
# no need to fix the interval, as it is in years
|
149
|
-
return data
|
150
|
-
|
151
|
-
# make sure it is in years
|
152
|
-
data["interval"] = "1y"
|
153
|
-
|
154
|
-
buckets = data["buckets"]
|
155
|
-
data["buckets"] = out_buckets = []
|
156
|
-
|
157
|
-
by_year = {}
|
158
|
-
|
159
|
-
# there might be several buckets returned with the same year - merge them
|
160
|
-
for bucket in buckets:
|
161
|
-
key = bucket["key_as_string"]
|
162
|
-
if key not in by_year:
|
163
|
-
by_year[key] = {
|
164
|
-
"key_as_string": key,
|
165
|
-
"key": bucket["key"],
|
166
|
-
"doc_count": 0,
|
167
|
-
}
|
168
|
-
out_buckets.append(by_year[key])
|
169
|
-
|
170
|
-
by_year[key]["doc_count"] += bucket["doc_count"]
|
171
|
-
|
172
|
-
return data
|
173
|
-
|
174
|
-
def _merge_small_buckets(self, buckets: List[Dict]):
|
175
|
-
"""
|
176
|
-
Merges small buckets into the previous bucket. If the small bucket is the first one,
|
177
|
-
merge it with subsequent buckets until the first non-small bucket is found.
|
178
|
-
"""
|
179
|
-
ret = []
|
180
|
-
initial_small_buckets = 0
|
181
|
-
initial_small_interval = 0
|
182
|
-
for bucket in buckets:
|
183
|
-
if bucket["doc_count"] < self._min_doc_count:
|
184
|
-
if ret:
|
185
|
-
ret[-1]["doc_count"] += bucket["doc_count"]
|
186
|
-
ret[-1]["interval"] += bucket["interval"]
|
187
|
-
else:
|
188
|
-
initial_small_buckets += bucket["doc_count"]
|
189
|
-
initial_small_interval += bucket["interval"]
|
190
|
-
else:
|
191
|
-
ret.append(bucket)
|
192
|
-
|
193
|
-
if ret and initial_small_buckets:
|
194
|
-
doc_count = ret[0]["doc_count"] + initial_small_buckets
|
195
|
-
interval = ret[0]["interval"] + initial_small_interval
|
196
|
-
ret[0] = buckets[0]
|
197
|
-
ret[0]["doc_count"] = doc_count
|
198
|
-
ret[0]["interval"] = interval
|
199
|
-
|
200
|
-
return ret
|
@@ -1,62 +0,0 @@
|
|
1
|
-
import mimetypes
|
2
|
-
import os
|
3
|
-
|
4
|
-
from invenio_records_resources.services.files.components import FileServiceComponent
|
5
|
-
from marshmallow.exceptions import ValidationError
|
6
|
-
|
7
|
-
|
8
|
-
class AllowedFileTypesComponent(FileServiceComponent):
|
9
|
-
def guess_content_type(self, filename: str | None) -> str | None:
|
10
|
-
if filename:
|
11
|
-
return mimetypes.guess_type(filename)[0] or "application/octet-stream"
|
12
|
-
return None
|
13
|
-
|
14
|
-
@property
|
15
|
-
def allowed_mimetypes(self):
|
16
|
-
"""Returns files attribute (field) key."""
|
17
|
-
return getattr(self.service.config, "allowed_mimetypes", [])
|
18
|
-
|
19
|
-
def guess_extension(self, file, mimetype):
|
20
|
-
"""File extension."""
|
21
|
-
# The ``ext`` property is used to in search to aggregate file types, and we want e.g. both ``.jpeg`` and
|
22
|
-
# ``.jpg`` to be aggregated under ``.jpg``
|
23
|
-
ext_guessed = mimetypes.guess_extension(mimetype)
|
24
|
-
|
25
|
-
# Check if a valid extension is guessed and it's not the default mimetype
|
26
|
-
if ext_guessed is not None and mimetype != "application/octet-stream":
|
27
|
-
return ext_guessed[1:]
|
28
|
-
|
29
|
-
# Support non-standard file extensions that cannot be guessed
|
30
|
-
_, ext = os.path.splitext(file)
|
31
|
-
if ext and len(ext) <= 5:
|
32
|
-
return ext[1:].lower()
|
33
|
-
|
34
|
-
if ext_guessed:
|
35
|
-
return ext_guessed[1:]
|
36
|
-
|
37
|
-
@property
|
38
|
-
def allowed_extensions(self):
|
39
|
-
"""Returns files attribute (field) key."""
|
40
|
-
return getattr(self.service.config, "allowed_extensions", [])
|
41
|
-
|
42
|
-
def init_files(self, identity, id_, data, uow=None):
|
43
|
-
"""Initialize the file upload for the record."""
|
44
|
-
list_files = list(data.files.entries)
|
45
|
-
|
46
|
-
for file in list_files:
|
47
|
-
allowed_type = self.guess_content_type(file)
|
48
|
-
allowed_ext = self.guess_extension(file, allowed_type)
|
49
|
-
if (
|
50
|
-
len(self.allowed_mimetypes) > 0
|
51
|
-
and allowed_type not in self.allowed_mimetypes
|
52
|
-
):
|
53
|
-
raise ValidationError(
|
54
|
-
f"Mimetype not supported, supported mimetypes: {self.allowed_mimetypes}"
|
55
|
-
)
|
56
|
-
elif (
|
57
|
-
len(self.allowed_extensions) > 0
|
58
|
-
and allowed_ext not in self.allowed_extensions
|
59
|
-
):
|
60
|
-
raise ValidationError(
|
61
|
-
f"Extension not supported, supported extensions: {self.allowed_extensions}"
|
62
|
-
)
|
@@ -1,16 +0,0 @@
|
|
1
|
-
from invenio_records_resources.services.uow import unit_of_work
|
2
|
-
|
3
|
-
from oarepo_runtime.datastreams.utils import get_record_service_for_file_service
|
4
|
-
|
5
|
-
|
6
|
-
class FeaturedFileServiceMixin:
|
7
|
-
@unit_of_work()
|
8
|
-
def commit_file(self, identity, id_, file_key, uow=None):
|
9
|
-
super().commit_file(identity, id_, file_key, uow=uow)
|
10
|
-
|
11
|
-
record = self._get_record(id_, identity, "read", file_key=file_key)
|
12
|
-
record_service = get_record_service_for_file_service(self, record=record)
|
13
|
-
indexer = record_service.indexer
|
14
|
-
if indexer:
|
15
|
-
indexer.index(record)
|
16
|
-
indexer.refresh()
|
@@ -1,103 +0,0 @@
|
|
1
|
-
from typing import Literal
|
2
|
-
|
3
|
-
from flask import current_app
|
4
|
-
from flask_principal import RoleNeed, UserNeed
|
5
|
-
from invenio_records_permissions.generators import (
|
6
|
-
ConditionalGenerator,
|
7
|
-
Disable,
|
8
|
-
Generator,
|
9
|
-
)
|
10
|
-
from invenio_search.engine import dsl
|
11
|
-
|
12
|
-
|
13
|
-
class RecordOwners(Generator):
|
14
|
-
"""Allows record owners."""
|
15
|
-
|
16
|
-
def needs(self, record=None, **kwargs):
|
17
|
-
"""Enabling Needs."""
|
18
|
-
if record is None:
|
19
|
-
# 'record' is required, so if not passed we default to empty array,
|
20
|
-
# i.e. superuser-access.
|
21
|
-
return []
|
22
|
-
if current_app.config.get("INVENIO_RDM_ENABLED", False):
|
23
|
-
owners = getattr(record.parent.access, "owned_by", None)
|
24
|
-
if owners is not None:
|
25
|
-
owners_list = owners if isinstance(owners, list) else [owners]
|
26
|
-
return [UserNeed(owner.owner_id) for owner in owners_list]
|
27
|
-
else:
|
28
|
-
owners = getattr(record.parent, "owners", None)
|
29
|
-
if owners is not None:
|
30
|
-
return [UserNeed(owner.id) for owner in owners]
|
31
|
-
return []
|
32
|
-
|
33
|
-
def query_filter(self, identity=None, **kwargs):
|
34
|
-
"""Filters for current identity as owner."""
|
35
|
-
users = [n.value for n in identity.provides if n.method == "id"]
|
36
|
-
if users:
|
37
|
-
if current_app.config.get("INVENIO_RDM_ENABLED", False):
|
38
|
-
return dsl.Q("terms", **{"parent.access.owned_by.user": users})
|
39
|
-
else:
|
40
|
-
return dsl.Q("terms", **{"parent.owners.user": users})
|
41
|
-
return dsl.Q("match_none")
|
42
|
-
|
43
|
-
|
44
|
-
class UserWithRole(Generator):
|
45
|
-
def __init__(self, *roles):
|
46
|
-
self.roles = roles
|
47
|
-
|
48
|
-
def needs(self, **kwargs):
|
49
|
-
return [RoleNeed(role) for role in self.roles]
|
50
|
-
|
51
|
-
def query_filter(self, identity=None, **kwargs):
|
52
|
-
if not identity:
|
53
|
-
return dsl.Q("match_none")
|
54
|
-
for provide in identity.provides:
|
55
|
-
if provide.method == "role" and provide.value in self.roles:
|
56
|
-
return dsl.Q("match_all")
|
57
|
-
return dsl.Q("match_none")
|
58
|
-
|
59
|
-
|
60
|
-
class IfDraftType(ConditionalGenerator):
|
61
|
-
def __init__(
|
62
|
-
self,
|
63
|
-
draft_types: (
|
64
|
-
list[Literal["initial"] | Literal["metadata"] | Literal["new_version"]]
|
65
|
-
| Literal["initial"]
|
66
|
-
| Literal["metadata"]
|
67
|
-
| Literal["new_version"]
|
68
|
-
),
|
69
|
-
then_=None,
|
70
|
-
else_=None,
|
71
|
-
):
|
72
|
-
if not isinstance(draft_types, (list, tuple)):
|
73
|
-
draft_types = [draft_types]
|
74
|
-
self._draft_types = draft_types
|
75
|
-
if not then_:
|
76
|
-
then_ = [Disable()]
|
77
|
-
if not else_:
|
78
|
-
else_ = [Disable()]
|
79
|
-
if not isinstance(then_, (list, tuple)):
|
80
|
-
then_ = [then_]
|
81
|
-
if not isinstance(else_, (list, tuple)):
|
82
|
-
else_ = [else_]
|
83
|
-
super().__init__(then_, else_)
|
84
|
-
|
85
|
-
def _condition(self, record=None, **kwargs):
|
86
|
-
if not record:
|
87
|
-
return False
|
88
|
-
|
89
|
-
index = record.versions.index
|
90
|
-
is_latest = record.versions.is_latest
|
91
|
-
is_draft = record.is_draft
|
92
|
-
|
93
|
-
if not is_draft:
|
94
|
-
return False
|
95
|
-
|
96
|
-
if index == 1 and not is_latest:
|
97
|
-
draft_type = "initial"
|
98
|
-
elif index > 1 and not is_latest:
|
99
|
-
draft_type = "new_version"
|
100
|
-
else:
|
101
|
-
draft_type = "metadata"
|
102
|
-
|
103
|
-
return draft_type in self._draft_types
|
File without changes
|
@@ -1,15 +0,0 @@
|
|
1
|
-
from invenio_records_resources.services.records.components import ServiceComponent
|
2
|
-
|
3
|
-
from oarepo_runtime.uow import CachingUnitOfWork
|
4
|
-
|
5
|
-
|
6
|
-
class CachingRelationsComponent(ServiceComponent):
|
7
|
-
def create(self, identity, *, record, **kwargs):
|
8
|
-
"""Create handler."""
|
9
|
-
# skutecny jmeno relations atributu
|
10
|
-
if isinstance(self.uow, CachingUnitOfWork) and hasattr(record, "relations"):
|
11
|
-
record.relations.set_cache(self.uow.cache)
|
12
|
-
|
13
|
-
def update(self, identity, *, record, **kwargs):
|
14
|
-
"""Update handler."""
|
15
|
-
self.create(identity, record=record, **kwargs)
|
@@ -1,18 +0,0 @@
|
|
1
|
-
class InvalidRelationError(KeyError):
|
2
|
-
def __init__(self, message, related_id, location):
|
3
|
-
self.related_id = related_id
|
4
|
-
self.location = location
|
5
|
-
super().__init__(message)
|
6
|
-
|
7
|
-
|
8
|
-
class MultipleInvalidRelationErrors(Exception):
|
9
|
-
"""
|
10
|
-
Records multiple validation errors of a relation field.
|
11
|
-
self.errors is a list of pairs (path, Error)
|
12
|
-
"""
|
13
|
-
|
14
|
-
def __init__(self, errors):
|
15
|
-
super().__init__(
|
16
|
-
"; ".join([f"{e[0]}: {type(e[1]).__name__}({e[1]})" for e in errors])
|
17
|
-
)
|
18
|
-
self.errors = errors
|
@@ -1,38 +0,0 @@
|
|
1
|
-
class RelationsMapping:
|
2
|
-
"""Helper class for managing relation fields."""
|
3
|
-
|
4
|
-
def __init__(self, record, fields):
|
5
|
-
"""Initialize the relations mapping."""
|
6
|
-
# Needed because we overwrite __setattr__
|
7
|
-
cache = {}
|
8
|
-
self._fields = fields
|
9
|
-
for name, fld in fields.items():
|
10
|
-
field_value = fld.get_value(record, cache)
|
11
|
-
setattr(self, name, field_value)
|
12
|
-
|
13
|
-
def __iter__(self):
|
14
|
-
"""Iterate over the relations fields."""
|
15
|
-
return iter(self._fields)
|
16
|
-
|
17
|
-
def validate(self, fields=None):
|
18
|
-
"""Validates all relations in the record."""
|
19
|
-
for name in fields or self:
|
20
|
-
getattr(self, name).validate()
|
21
|
-
|
22
|
-
def dereference(self, fields=None):
|
23
|
-
"""Dereferences relation fields."""
|
24
|
-
for name in fields or self:
|
25
|
-
getattr(self, name).dereference()
|
26
|
-
|
27
|
-
def clean(self, fields=None):
|
28
|
-
"""Clean dereferenced relation fields."""
|
29
|
-
for name in fields or self:
|
30
|
-
getattr(self, name).clean()
|
31
|
-
|
32
|
-
def set_cache(self, cache):
|
33
|
-
from oarepo_runtime.records.relations import PIDRelation
|
34
|
-
|
35
|
-
for key, fld in self._fields.items():
|
36
|
-
if isinstance(fld, PIDRelation):
|
37
|
-
fld.cache = cache
|
38
|
-
getattr(self, key).cache = cache
|
@@ -1,13 +0,0 @@
|
|
1
|
-
from invenio_records_resources.services.custom_fields.schema import (
|
2
|
-
CustomFieldsSchemaUI as InvenioCustomFieldsSchemaUI,
|
3
|
-
)
|
4
|
-
|
5
|
-
|
6
|
-
class CustomFieldsSchemaUI(InvenioCustomFieldsSchemaUI):
|
7
|
-
def _serialize(self, obj, **kwargs):
|
8
|
-
self._schema.context.update(self.context)
|
9
|
-
return super()._serialize(obj, **kwargs)
|
10
|
-
|
11
|
-
def _deserialize(self, data, **kwargs):
|
12
|
-
self._schema.context.update(self.context)
|
13
|
-
return super()._deserialize(data, **kwargs)
|
@@ -1,44 +0,0 @@
|
|
1
|
-
import typing
|
2
|
-
|
3
|
-
from invenio_rdm_records.services.schemas.record import RDMRecordSchema
|
4
|
-
from invenio_records_resources.services.records.schema import (
|
5
|
-
BaseRecordSchema as InvenioBaseRecordSchema,
|
6
|
-
)
|
7
|
-
|
8
|
-
import marshmallow as ma
|
9
|
-
|
10
|
-
|
11
|
-
class BaseRecordSchema(InvenioBaseRecordSchema):
|
12
|
-
"""Base record schema - in addition to invenio exposes $schema as well."""
|
13
|
-
|
14
|
-
_schema = ma.fields.Str(attribute="$schema", data_key="$schema")
|
15
|
-
|
16
|
-
|
17
|
-
class RDMBaseRecordSchema(RDMRecordSchema):
|
18
|
-
"""Base record schema - in addition to invenio exposes $schema as well."""
|
19
|
-
|
20
|
-
_schema = ma.fields.Str(attribute="$schema", data_key="$schema")
|
21
|
-
|
22
|
-
|
23
|
-
class DictOnlySchema(ma.Schema):
|
24
|
-
def get_attribute(self, obj: typing.Any, attr: str, default: typing.Any):
|
25
|
-
if not isinstance(attr, int) and "." in attr:
|
26
|
-
return _get_value_for_keys_dict_only(obj, attr.split("."), default)
|
27
|
-
else:
|
28
|
-
return _get_value_for_key_dict_only(obj, attr, default)
|
29
|
-
|
30
|
-
|
31
|
-
def _get_value_for_keys_dict_only(obj, keys, default):
|
32
|
-
if len(keys) == 1:
|
33
|
-
return _get_value_for_key_dict_only(obj, keys[0], default)
|
34
|
-
else:
|
35
|
-
return _get_value_for_keys_dict_only(
|
36
|
-
_get_value_for_key_dict_only(obj, keys[0], default), keys[1:], default
|
37
|
-
)
|
38
|
-
|
39
|
-
|
40
|
-
def _get_value_for_key_dict_only(obj, key, default):
|
41
|
-
try:
|
42
|
-
return obj[key]
|
43
|
-
except (KeyError, IndexError, TypeError, AttributeError):
|
44
|
-
return default
|
@@ -1,72 +0,0 @@
|
|
1
|
-
from marshmallow import Schema, fields
|
2
|
-
from oarepo_runtime.services.schema.ui import (
|
3
|
-
LocalizedEDTFTime,
|
4
|
-
LocalizedDateTime,
|
5
|
-
LocalizedEDTF,
|
6
|
-
LocalizedEDTFInterval,
|
7
|
-
LocalizedEDTFTimeInterval,
|
8
|
-
LocalizedTime
|
9
|
-
)
|
10
|
-
|
11
|
-
field_type_converters = {
|
12
|
-
fields.String : lambda field: {"type" : "string"},
|
13
|
-
fields.Integer: lambda field: {"type": "integer"},
|
14
|
-
fields.Float: lambda field: {"type": "number"},
|
15
|
-
fields.Boolean: lambda field: {"type": "boolean"},
|
16
|
-
fields.List: lambda field: {
|
17
|
-
"type": "array",
|
18
|
-
"items": convert_field_to_json_schema(field.inner)
|
19
|
-
},
|
20
|
-
fields.Nested: lambda field: {
|
21
|
-
"type": "object",
|
22
|
-
"properties": marshmallow_to_json_schema(field.schema)["properties"]
|
23
|
-
},
|
24
|
-
fields.Raw: lambda field: {
|
25
|
-
"type": "object",
|
26
|
-
'additionalProperties' : True
|
27
|
-
},
|
28
|
-
LocalizedEDTFTime: lambda field: {
|
29
|
-
"type": "string",
|
30
|
-
"format": "date-time",
|
31
|
-
},
|
32
|
-
LocalizedDateTime: lambda field: {
|
33
|
-
"type": "string",
|
34
|
-
"format": "date-time",
|
35
|
-
},
|
36
|
-
LocalizedTime: lambda field: {
|
37
|
-
"type": "string",
|
38
|
-
"format": "time",
|
39
|
-
},
|
40
|
-
LocalizedEDTF: lambda field: {
|
41
|
-
"type": "string",
|
42
|
-
"format": "date",
|
43
|
-
},
|
44
|
-
LocalizedEDTFInterval: lambda field: {
|
45
|
-
"type": "string",
|
46
|
-
"format": "date-time",
|
47
|
-
},
|
48
|
-
LocalizedEDTFTimeInterval: lambda field: {
|
49
|
-
"type": "string",
|
50
|
-
"format": "date-time",
|
51
|
-
}
|
52
|
-
}
|
53
|
-
|
54
|
-
def marshmallow_to_json_schema(schema:Schema) -> dict:
|
55
|
-
json_schema = {
|
56
|
-
'type': 'object',
|
57
|
-
'properties': {}
|
58
|
-
}
|
59
|
-
|
60
|
-
for field_name, field in schema.fields.items():
|
61
|
-
json_schema["properties"][field_name] = convert_field_to_json_schema(field)
|
62
|
-
|
63
|
-
return json_schema
|
64
|
-
|
65
|
-
|
66
|
-
def convert_field_to_json_schema(field:fields) -> dict:
|
67
|
-
for field_type in type(field).mro():
|
68
|
-
if field_type in field_type_converters:
|
69
|
-
return field_type_converters[field_type](field)
|
70
|
-
|
71
|
-
# no converter found, just string
|
72
|
-
return {"type":"string"}
|