oarepo-runtime 1.10.3__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.
Files changed (171) hide show
  1. oarepo_runtime/__init__.py +24 -0
  2. oarepo_runtime/api.py +111 -0
  3. oarepo_runtime/cli/__init__.py +10 -21
  4. oarepo_runtime/cli/search.py +34 -0
  5. oarepo_runtime/config.py +86 -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 +59 -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/records/__init__.py +14 -1
  20. oarepo_runtime/services/records/links.py +21 -11
  21. oarepo_runtime/services/records/mapping.py +42 -0
  22. oarepo_runtime/services/results.py +98 -109
  23. oarepo_runtime/services/schema/__init__.py +12 -44
  24. oarepo_runtime/services/schema/i18n.py +47 -22
  25. oarepo_runtime/services/schema/i18n_ui.py +61 -24
  26. {oarepo_runtime-1.10.3.dist-info → oarepo_runtime-2.0.0.dev3.dist-info}/METADATA +9 -21
  27. oarepo_runtime-2.0.0.dev3.dist-info/RECORD +30 -0
  28. {oarepo_runtime-1.10.3.dist-info → oarepo_runtime-2.0.0.dev3.dist-info}/WHEEL +1 -2
  29. oarepo_runtime-2.0.0.dev3.dist-info/entry_points.txt +5 -0
  30. oarepo_runtime/cli/assets.py +0 -145
  31. oarepo_runtime/cli/base.py +0 -25
  32. oarepo_runtime/cli/cf.py +0 -15
  33. oarepo_runtime/cli/check.py +0 -167
  34. oarepo_runtime/cli/configuration.py +0 -51
  35. oarepo_runtime/cli/fixtures.py +0 -167
  36. oarepo_runtime/cli/index.py +0 -272
  37. oarepo_runtime/cli/permissions/__init__.py +0 -6
  38. oarepo_runtime/cli/permissions/base.py +0 -26
  39. oarepo_runtime/cli/permissions/evaluate.py +0 -63
  40. oarepo_runtime/cli/permissions/list.py +0 -239
  41. oarepo_runtime/cli/permissions/search.py +0 -121
  42. oarepo_runtime/cli/validate.py +0 -150
  43. oarepo_runtime/datastreams/__init__.py +0 -38
  44. oarepo_runtime/datastreams/asynchronous.py +0 -247
  45. oarepo_runtime/datastreams/catalogue.py +0 -150
  46. oarepo_runtime/datastreams/datastreams.py +0 -152
  47. oarepo_runtime/datastreams/errors.py +0 -54
  48. oarepo_runtime/datastreams/ext.py +0 -41
  49. oarepo_runtime/datastreams/fixtures.py +0 -265
  50. oarepo_runtime/datastreams/json.py +0 -4
  51. oarepo_runtime/datastreams/readers/__init__.py +0 -39
  52. oarepo_runtime/datastreams/readers/attachments.py +0 -51
  53. oarepo_runtime/datastreams/readers/excel.py +0 -123
  54. oarepo_runtime/datastreams/readers/json.py +0 -27
  55. oarepo_runtime/datastreams/readers/service.py +0 -54
  56. oarepo_runtime/datastreams/readers/yaml.py +0 -14
  57. oarepo_runtime/datastreams/semi_asynchronous.py +0 -91
  58. oarepo_runtime/datastreams/synchronous.py +0 -70
  59. oarepo_runtime/datastreams/transformers.py +0 -18
  60. oarepo_runtime/datastreams/types.py +0 -323
  61. oarepo_runtime/datastreams/utils.py +0 -131
  62. oarepo_runtime/datastreams/writers/__init__.py +0 -21
  63. oarepo_runtime/datastreams/writers/attachments_file.py +0 -92
  64. oarepo_runtime/datastreams/writers/attachments_service.py +0 -118
  65. oarepo_runtime/datastreams/writers/publish.py +0 -70
  66. oarepo_runtime/datastreams/writers/service.py +0 -175
  67. oarepo_runtime/datastreams/writers/utils.py +0 -30
  68. oarepo_runtime/datastreams/writers/validation_errors.py +0 -20
  69. oarepo_runtime/datastreams/writers/yaml.py +0 -56
  70. oarepo_runtime/ext_config.py +0 -67
  71. oarepo_runtime/i18n/__init__.py +0 -3
  72. oarepo_runtime/info/__init__.py +0 -0
  73. oarepo_runtime/info/check.py +0 -95
  74. oarepo_runtime/info/permissions/__init__.py +0 -0
  75. oarepo_runtime/info/permissions/debug.py +0 -191
  76. oarepo_runtime/info/views.py +0 -586
  77. oarepo_runtime/profile.py +0 -60
  78. oarepo_runtime/records/dumpers/__init__.py +0 -8
  79. oarepo_runtime/records/dumpers/edtf_interval.py +0 -38
  80. oarepo_runtime/records/dumpers/multilingual_dumper.py +0 -34
  81. oarepo_runtime/records/entity_resolvers/__init__.py +0 -13
  82. oarepo_runtime/records/entity_resolvers/proxies.py +0 -57
  83. oarepo_runtime/records/mappings/__init__.py +0 -0
  84. oarepo_runtime/records/mappings/rdm_parent_mapping.json +0 -483
  85. oarepo_runtime/records/owners/__init__.py +0 -3
  86. oarepo_runtime/records/owners/registry.py +0 -22
  87. oarepo_runtime/records/relations/__init__.py +0 -22
  88. oarepo_runtime/records/relations/base.py +0 -296
  89. oarepo_runtime/records/relations/internal.py +0 -46
  90. oarepo_runtime/records/relations/lookup.py +0 -28
  91. oarepo_runtime/records/relations/pid_relation.py +0 -102
  92. oarepo_runtime/records/systemfields/featured_file.py +0 -45
  93. oarepo_runtime/records/systemfields/has_draftcheck.py +0 -47
  94. oarepo_runtime/records/systemfields/icu.py +0 -371
  95. oarepo_runtime/records/systemfields/owner.py +0 -115
  96. oarepo_runtime/records/systemfields/record_status.py +0 -35
  97. oarepo_runtime/records/systemfields/selectors.py +0 -98
  98. oarepo_runtime/records/systemfields/synthetic.py +0 -130
  99. oarepo_runtime/resources/__init__.py +0 -4
  100. oarepo_runtime/resources/config.py +0 -12
  101. oarepo_runtime/resources/file_resource.py +0 -15
  102. oarepo_runtime/resources/json_serializer.py +0 -27
  103. oarepo_runtime/resources/localized_ui_json_serializer.py +0 -54
  104. oarepo_runtime/resources/resource.py +0 -53
  105. oarepo_runtime/resources/responses.py +0 -20
  106. oarepo_runtime/services/components.py +0 -429
  107. oarepo_runtime/services/config/draft_link.py +0 -23
  108. oarepo_runtime/services/config/permissions_presets.py +0 -174
  109. oarepo_runtime/services/config/service.py +0 -117
  110. oarepo_runtime/services/custom_fields/__init__.py +0 -80
  111. oarepo_runtime/services/custom_fields/mappings.py +0 -188
  112. oarepo_runtime/services/entity/__init__.py +0 -0
  113. oarepo_runtime/services/entity/config.py +0 -14
  114. oarepo_runtime/services/entity/schema.py +0 -9
  115. oarepo_runtime/services/entity/service.py +0 -48
  116. oarepo_runtime/services/expansions/__init__.py +0 -0
  117. oarepo_runtime/services/expansions/expandable_fields.py +0 -21
  118. oarepo_runtime/services/expansions/service.py +0 -4
  119. oarepo_runtime/services/facets/__init__.py +0 -33
  120. oarepo_runtime/services/facets/base.py +0 -12
  121. oarepo_runtime/services/facets/date.py +0 -72
  122. oarepo_runtime/services/facets/enum.py +0 -11
  123. oarepo_runtime/services/facets/facet_groups_names.py +0 -17
  124. oarepo_runtime/services/facets/max_facet.py +0 -13
  125. oarepo_runtime/services/facets/multilingual_facet.py +0 -33
  126. oarepo_runtime/services/facets/nested_facet.py +0 -32
  127. oarepo_runtime/services/facets/params.py +0 -192
  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.dev3.dist-info}/licenses/LICENSE +0 -0
@@ -1,167 +0,0 @@
1
- import click
2
- import tqdm
3
- from flask import current_app
4
- from flask.cli import with_appcontext
5
- from flask_principal import Identity, RoleNeed, UserNeed
6
- from invenio_access.permissions import any_user, authenticated_user, system_identity
7
- from invenio_accounts.models import User
8
-
9
- from oarepo_runtime.cli import oarepo
10
- from oarepo_runtime.datastreams import SynchronousDataStream
11
- from oarepo_runtime.datastreams.asynchronous import AsynchronousDataStream
12
- from oarepo_runtime.datastreams.fixtures import (
13
- FixturesCallback,
14
- dump_fixtures,
15
- fixtures_asynchronous_callback,
16
- load_fixtures,
17
- )
18
- from oarepo_runtime.datastreams.types import StatsKeepingDataStreamCallback
19
-
20
-
21
- @oarepo.group()
22
- def fixtures():
23
- """Load and dump fixtures"""
24
-
25
-
26
- @fixtures.command()
27
- @click.argument("fixture_dir_or_catalogue", required=False)
28
- @click.option("--include", multiple=True)
29
- @click.option("--exclude", multiple=True)
30
- @click.option("--system-fixtures/--no-system-fixtures", default=True, is_flag=True)
31
- @click.option("--verbose", is_flag=True)
32
- @click.option("--on-background", is_flag=True)
33
- @click.option(
34
- "--bulk-size",
35
- default=100,
36
- type=int,
37
- help="Size for bulk indexing - this number of records "
38
- "will be committed in a single transaction and indexed together",
39
- )
40
- @click.option("--batch-size", help="Alias for --bulk-size", type=int)
41
- @click.option(
42
- "--identity", help="Email of the identity that will be used to import the data"
43
- )
44
- @with_appcontext
45
- def load(
46
- fixture_dir_or_catalogue=None,
47
- include=None,
48
- exclude=None,
49
- system_fixtures=None,
50
- verbose=False,
51
- bulk_size=100,
52
- on_background=False,
53
- batch_size=None,
54
- identity=None,
55
- ):
56
- """Loads fixtures"""
57
- if batch_size:
58
- bulk_size = batch_size
59
- if not on_background:
60
- callback = TQDMCallback(verbose=verbose)
61
- else:
62
- callback = fixtures_asynchronous_callback.s()
63
-
64
- if fixture_dir_or_catalogue:
65
- system_fixtures = False
66
-
67
- if not identity:
68
- user = None
69
- identity = system_identity
70
- else:
71
- # identity is user email
72
- user = User.query.filter_by(email=identity).one()
73
- identity = Identity(user.id)
74
-
75
- # TODO: add provides. How to do it better? It seems that we can not use
76
- # flask signals to add these, as they depend on request context that is
77
- # not available here
78
- identity.provides.add(any_user)
79
- identity.provides.add(authenticated_user)
80
- identity.provides.add(UserNeed(user.id))
81
- for role in getattr(user, "roles", []):
82
- identity.provides.add(RoleNeed(role.name))
83
- # TODO: community roles ...
84
-
85
- with current_app.wsgi_app.mounts["/api"].app_context():
86
- load_fixtures(
87
- fixture_dir_or_catalogue,
88
- _make_list(include),
89
- _make_list(exclude),
90
- system_fixtures=system_fixtures,
91
- callback=callback,
92
- batch_size=bulk_size,
93
- datastreams_impl=(
94
- AsynchronousDataStream if on_background else SynchronousDataStream
95
- ),
96
- identity=identity,
97
- )
98
- if not on_background:
99
- _show_stats(callback, "Load fixtures")
100
-
101
-
102
- @fixtures.command()
103
- @click.option("--include", multiple=True)
104
- @click.option("--exclude", multiple=True)
105
- @click.argument("fixture_dir", required=True)
106
- @click.option("--verbose", is_flag=True)
107
- @with_appcontext
108
- def dump(fixture_dir, include, exclude, verbose):
109
- """Dump fixtures"""
110
- callback = TQDMCallback(verbose=verbose)
111
-
112
- with current_app.wsgi_app.mounts["/api"].app_context():
113
- dump_fixtures(
114
- fixture_dir,
115
- _make_list(include),
116
- _make_list(exclude),
117
- callback=TQDMCallback(verbose=verbose),
118
- )
119
- _show_stats(callback, "Dump fixtures")
120
-
121
-
122
- def _make_list(lst):
123
- return [
124
- item.strip() for lst_item in lst for item in lst_item.split(",") if item.strip()
125
- ]
126
-
127
-
128
- def _show_stats(callback: StatsKeepingDataStreamCallback, title: str):
129
- print("\n\n")
130
- print(f"{title} stats:")
131
- print(callback.stats())
132
-
133
-
134
- class TQDMCallback(FixturesCallback):
135
- def __init__(self, message_prefix="Loading ", verbose=False):
136
- super().__init__()
137
- self._tqdm = tqdm.tqdm(unit=" item(s)")
138
- self._message_prefix = message_prefix
139
- self._verbose = verbose
140
-
141
- def fixture_started(self, fixture_name):
142
- self._tqdm.set_description(f"{self._message_prefix}{fixture_name} running")
143
-
144
- def fixture_finished(self, fixture_name):
145
- self._tqdm.set_description(f"{self._message_prefix}{fixture_name} finished")
146
-
147
- def batch_finished(self, batch):
148
- super().batch_finished(batch)
149
- self._tqdm.update(len(batch.entries))
150
- for err in batch.errors:
151
- self._tqdm.write("Failed batch: {}: {}".format(err, batch))
152
- if self._verbose:
153
- for entry in batch.entries:
154
- if entry.errors:
155
- self._tqdm.write("Failed entry: {}".format(entry))
156
-
157
- def reader_error(self, reader, exception):
158
- super().reader_error(reader, exception)
159
- self._tqdm.write("Reader error:{}: {}".format(reader, exception))
160
-
161
- def transformer_error(self, batch, transformer, exception):
162
- super().transformer_error(batch, transformer, exception)
163
- self._tqdm.write("Transformer error: {}: {}".format(transformer, exception))
164
-
165
- def writer_error(self, batch, writer, exception):
166
- super().writer_error(batch, writer, exception)
167
- self._tqdm.write("Writer error: {}: {}".format(writer, exception))
@@ -1,272 +0,0 @@
1
- import sys
2
- import traceback
3
- from io import StringIO
4
-
5
- import click
6
- import yaml
7
- from flask.cli import with_appcontext
8
- from invenio_db import db
9
- from invenio_records_resources.proxies import current_service_registry
10
- from invenio_search.proxies import current_search
11
- from werkzeug.utils import ImportStringError, import_string
12
-
13
- try:
14
- from tqdm import tqdm
15
- except ImportError:
16
-
17
- def tqdm(generator):
18
- yield from generator
19
-
20
-
21
- from .base import oarepo
22
-
23
-
24
- @oarepo.group()
25
- def index():
26
- "OARepo indexing addons"
27
-
28
-
29
- @index.command(
30
- help="Create all indices that do not exist yet. "
31
- "This is like 'invenio index init' but does not throw "
32
- "an exception if some indices already exist"
33
- )
34
- @with_appcontext
35
- def init():
36
- click.secho("Creating indexes...", fg="green", bold=True, file=sys.stderr)
37
- all_indices = list(gather_all_indices())
38
- new_indices = []
39
- with click.progressbar(all_indices, label="Checking which indices exist") as bar:
40
- for name, alias in bar:
41
- if not current_search.client.indices.exists(alias):
42
- new_indices.append(name)
43
- if new_indices:
44
- with click.progressbar(
45
- current_search.create(
46
- ignore=[400], ignore_existing=True, index_list=new_indices
47
- ),
48
- length=len(new_indices),
49
- ) as bar:
50
- for name, response in bar:
51
- bar.label = name
52
-
53
-
54
- def gather_all_indices():
55
- """Yield index_file, index_name for all indices."""
56
-
57
- # partially copied from invenio-search
58
- def _build(tree_or_filename, alias=None):
59
- """Build a list of index/alias actions to perform."""
60
- for name, value in tree_or_filename.items():
61
- if isinstance(value, dict):
62
- yield from _build(value, alias=name)
63
- else:
64
- index_result, alias_result = current_search.create_index(
65
- name, dry_run=True
66
- )
67
- yield name, alias_result[0]
68
-
69
- yield from _build(current_search.active_aliases)
70
-
71
-
72
- def record_or_service(model):
73
- # TODO: is this still used (maybe from somewhere else?)
74
- try:
75
- service = current_service_registry.get(model)
76
- except KeyError:
77
- service = None
78
- if service and getattr(service, "config", None):
79
- record = getattr(service.config, "record_cls", None)
80
- else:
81
- try:
82
- record = import_string(model)
83
- except ImportStringError:
84
- record = None
85
-
86
- if record is None:
87
- click.secho(
88
- "Service or model not found. Known services: ",
89
- fg="red",
90
- bold=True,
91
- file=sys.stderr,
92
- )
93
- for svc in sorted(current_service_registry._services):
94
- click.secho(f" {svc}", file=sys.stderr)
95
- sys.exit(1)
96
- return record
97
-
98
-
99
- @index.command()
100
- @with_appcontext
101
- @click.argument("model", required=False)
102
- @click.option("--bulk-size", required=False, default=5000, type=int)
103
- @click.option("--verbose/--no-verbose", default=False)
104
- def reindex(model, bulk_size, verbose):
105
- if not model:
106
- services = list(current_service_registry._services.keys())
107
- else:
108
- services = [model]
109
- services = sort_services(services)
110
- for service_id in services:
111
- click.secho(f"Preparing to index {service_id}", file=sys.stderr)
112
-
113
- try:
114
- service = current_service_registry.get(service_id)
115
- except KeyError:
116
- click.secho(f"Service {service_id} not in known services:", color="red")
117
- for known_service_id, known_service in sorted(
118
- current_service_registry._services.items()
119
- ):
120
- click.secho(
121
- f" {known_service_id} -> {type(known_service).__module__}.{type(known_service).__name__}",
122
- color="red",
123
- )
124
- sys.exit(1)
125
- record_class = getattr(service.config, "record_cls", None)
126
-
127
- id_generators = []
128
-
129
- record_generator = RECORD_GENERATORS.get(service_id, model_records_generator)
130
-
131
- if record_class and hasattr(service, "indexer"):
132
- try:
133
- id_generators.append(record_generator(record_class))
134
- except Exception as e:
135
- click.secho(
136
- f"Could not get record ids for {service_id}, exception {e}",
137
- file=sys.stderr,
138
- )
139
-
140
- draft_class = getattr(service.config, "draft_cls", None)
141
-
142
- if draft_class and hasattr(service, "indexer"):
143
- try:
144
- id_generators.append(record_generator(draft_class))
145
- except Exception as e:
146
- click.secho(
147
- f"Could not get draft record ids for {service_id}, exception {e}",
148
- file=sys.stderr,
149
- )
150
-
151
- click.secho(f"Indexing {service_id}", file=sys.stderr)
152
- count = 0
153
- errors = 0
154
- for gen in id_generators:
155
- for bulk in generate_bulk_data(gen, service.indexer, bulk_size=bulk_size):
156
- index_result = service.indexer.client.bulk(bulk)
157
- count += len(bulk) // 2
158
- for index_item_result in index_result["items"]:
159
- result = index_item_result["index"]
160
- if result["status"] not in (200, 201):
161
- errors += 1
162
- click.secho(
163
- f"Error indexing record with id {result['_id']}",
164
- fg="red",
165
- file=sys.stderr,
166
- )
167
- click.secho(
168
- dump_yaml(result.get("error")), fg="red", file=sys.stderr
169
- )
170
- if verbose:
171
- click.secho("Record:", file=sys.stderr)
172
- rec = [
173
- bulk[idx + 1]
174
- for idx in range(0, len(bulk), 2)
175
- if bulk[idx]["index"]["_id"] == result["_id"]
176
- ]
177
- if rec:
178
- click.secho(dump_yaml(rec[0]))
179
- else:
180
- click.secho("<no record found>")
181
-
182
- if count:
183
- service.indexer.refresh()
184
-
185
- if errors:
186
- click.secho(
187
- f"Indexing {service_id} failed, indexed {count - errors} records, failed {errors} records.",
188
- fg="red",
189
- file=sys.stderr,
190
- )
191
- if not verbose:
192
- click.secho("Run with --verbose to see information about the errors")
193
- else:
194
- click.secho(
195
- f"Indexing {service_id} finished, indexed {count} records",
196
- fg="green",
197
- file=sys.stderr,
198
- )
199
-
200
-
201
- def generate_bulk_data(record_generator, record_indexer, bulk_size):
202
- data = []
203
- n = 0
204
- for record in tqdm(record_generator):
205
- try:
206
- index = record_indexer.record_to_index(record)
207
- body = record_indexer._prepare_record(record, index)
208
- index = record_indexer._prepare_index(index)
209
- data.append(
210
- {
211
- "index": {
212
- "_index": index,
213
- "version": record.revision_id,
214
- "version_type": "external_gte",
215
- "_id": body["uuid"],
216
- }
217
- }
218
- )
219
- data.append(body)
220
- if len(data) >= bulk_size:
221
- yield data
222
- data = []
223
- except:
224
- traceback.print_exc()
225
- if data:
226
- yield data
227
-
228
-
229
- def dump_yaml(data):
230
- io = StringIO()
231
- yaml.dump(data, io, allow_unicode=True)
232
- return io.getvalue()
233
-
234
-
235
- def model_records_generator(model_class):
236
- try:
237
- for x in db.session.query(model_class.model_cls.id).filter(
238
- model_class.model_cls.is_deleted.is_(False)
239
- ):
240
- rec_id = x[0]
241
- yield model_class.get_record(rec_id)
242
- except Exception as e:
243
- click.secho(f"Could not index {model_class}: {e}", fg="red", file=sys.stderr)
244
-
245
-
246
- def users_record_generator(model_class):
247
- from invenio_accounts.models import User
248
- from invenio_users_resources.records.api import UserAggregate
249
-
250
- try:
251
- for x in db.session.query(User.id):
252
- rec_id = x[0]
253
- yield UserAggregate.get_record(rec_id)
254
- except Exception as e:
255
- click.secho(f"Could not index {model_class}: {e}", fg="red", file=sys.stderr)
256
-
257
-
258
- priorities = ["vocabular", "users", "groups"]
259
-
260
-
261
- def sort_services(services):
262
- def idx(x):
263
- for idx, p in enumerate(priorities):
264
- if p in x:
265
- return idx, x
266
- return len(priorities), x
267
-
268
- services.sort(key=idx)
269
- return services
270
-
271
-
272
- RECORD_GENERATORS = {"users": users_record_generator}
@@ -1,6 +0,0 @@
1
- from .base import permissions
2
- from .evaluate import evaluate_permissions # noqa
3
- from .list import list_permissions # noqa
4
- from .search import search_permissions # noqa
5
-
6
- __all__ = ["permissions"]
@@ -1,26 +0,0 @@
1
- from flask import current_app
2
- from flask_principal import Identity, UserNeed, identity_loaded
3
- from invenio_access.models import User
4
-
5
- from ..base import oarepo
6
-
7
-
8
- @oarepo.group()
9
- def permissions():
10
- """Commands for checking and explaining permissions."""
11
-
12
-
13
- def get_user_and_identity(user_id_or_email):
14
- try:
15
- user_id = int(user_id_or_email)
16
- user = User.query.filter_by(id=user_id).one()
17
- except ValueError:
18
- user = User.query.filter_by(email=user_id_or_email).one()
19
-
20
- identity = Identity(user.id)
21
- identity.provides.add(UserNeed(str(user.id)))
22
- api_app = current_app.wsgi_app.mounts["/api"]
23
- with api_app.app_context():
24
- with current_app.test_request_context("/api"):
25
- identity_loaded.send(api_app, identity=identity)
26
- return user, identity
@@ -1,63 +0,0 @@
1
- import json
2
-
3
- import click
4
- from invenio_records_permissions.policies.records import RecordPermissionPolicy
5
- from invenio_records_resources.proxies import current_service_registry
6
-
7
- from oarepo_runtime.info.permissions.debug import add_debugging
8
-
9
- from .base import get_user_and_identity, permissions
10
-
11
-
12
- @permissions.command(name="evaluate")
13
- @click.argument("user_id_or_email")
14
- @click.argument("service_name")
15
- @click.argument("record_id", required=False)
16
- @click.option("--data", "-d", help="Data to pass to the policy check")
17
- @click.option("--explain/--no-explain", default=False)
18
- @click.option("--draft/--published", default=False)
19
- def evaluate_permissions(
20
- user_id_or_email: str,
21
- service_name: str,
22
- record_id: str | None = None,
23
- data: str | None = None,
24
- explain: bool = False,
25
- draft: bool = False,
26
- ):
27
- """Evaluate permissions for a given workflow, community or service."""
28
- service = current_service_registry.get(service_name)
29
- user, identity = get_user_and_identity(user_id_or_email)
30
-
31
- over = {}
32
- if record_id:
33
- if draft:
34
- over["record"] = service.config.draft_cls.pid.resolve(
35
- record_id, registered_only=False
36
- )
37
- else:
38
- over["record"] = service.config.record_cls.pid.resolve(record_id)
39
- if data:
40
- over["data"] = json.loads(data)
41
-
42
- if explain:
43
- over["debug_identity"] = identity
44
- add_debugging()
45
-
46
- policy_cls = service.config.permission_policy_cls
47
- click.secho(f"Policy: {policy_cls}")
48
-
49
- for action_name in dir(policy_cls):
50
- if not action_name.startswith("can_"):
51
- continue
52
-
53
- policy: RecordPermissionPolicy = policy_cls(action_name[4:], **over)
54
- if explain:
55
- click.secho()
56
- click.secho(f"## {action_name}")
57
- try:
58
- if policy.allows(identity):
59
- click.secho(f"{action_name}: True", fg="green")
60
- else:
61
- click.secho(f"{action_name}: False", fg="red")
62
- except Exception as e:
63
- click.secho(f"{action_name}: {e}", fg="yellow")