cmem-cmemc 25.4.0__tar.gz → 25.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/PKG-INFO +6 -4
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/command_group.py +31 -30
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/commands/acl.py +95 -8
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/commands/admin.py +31 -4
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/commands/graph.py +12 -5
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/commands/graph_imports.py +3 -6
- cmem_cmemc-25.5.0/cmem_cmemc/commands/graph_insights.py +382 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/commands/project.py +1 -1
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/commands/query.py +3 -3
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/commands/validation.py +5 -3
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/commands/vocabulary.py +13 -4
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/commands/workflow.py +1 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/completion.py +13 -19
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/context.py +2 -2
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/manual_helper/multi_page.py +3 -4
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/string_processor.py +8 -3
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/utils.py +1 -1
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/pyproject.toml +6 -5
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/LICENSE +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/README-public.md +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/__init__.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/_cmemc.zsh +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/cli.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/command.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/commands/__init__.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/commands/client.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/commands/config.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/commands/dataset.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/commands/manual.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/commands/metrics.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/commands/migration.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/commands/python.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/commands/resource.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/commands/scheduler.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/commands/store.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/commands/user.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/commands/variable.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/commands/workspace.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/config_parser.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/constants.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/exceptions.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/manual_helper/__init__.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/manual_helper/graph.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/manual_helper/single_page.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/migrations/__init__.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/migrations/abc.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/migrations/access_conditions_243.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/migrations/bootstrap_data.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/migrations/remove_noop_triple_251.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/migrations/shapes_widget_integrations_243.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/migrations/sparql_query_texts_242.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/migrations/workspace_configurations.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/object_list.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/parameter_types/__init__.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/parameter_types/path.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/placeholder.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/smart_path/__init__.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/smart_path/clients/__init__.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/smart_path/clients/http.py +0 -0
- {cmem_cmemc-25.4.0 → cmem_cmemc-25.5.0}/cmem_cmemc/title_helper.py +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: cmem-cmemc
|
|
3
|
-
Version: 25.
|
|
3
|
+
Version: 25.5.0
|
|
4
4
|
Summary: Command line client for eccenca Corporate Memory
|
|
5
5
|
License: Apache-2.0
|
|
6
|
+
License-File: LICENSE
|
|
6
7
|
Author: eccenca
|
|
7
8
|
Author-email: cmempy-developer@eccenca.com
|
|
8
9
|
Requires-Python: >=3.10,<4.0
|
|
@@ -21,16 +22,17 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
21
22
|
Classifier: Programming Language :: Python :: 3.11
|
|
22
23
|
Classifier: Programming Language :: Python :: 3.12
|
|
23
24
|
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
26
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
25
27
|
Classifier: Topic :: Database
|
|
26
28
|
Classifier: Topic :: Software Development :: Testing
|
|
27
29
|
Classifier: Topic :: Utilities
|
|
28
30
|
Requires-Dist: beautifulsoup4 (>=4.13.3,<5.0.0)
|
|
29
31
|
Requires-Dist: certifi (>=2024.2.2)
|
|
30
|
-
Requires-Dist: click (>=8.
|
|
32
|
+
Requires-Dist: click (>=8.3.0,<9.0.0)
|
|
31
33
|
Requires-Dist: click-didyoumean (>=0.3.1,<0.4.0)
|
|
32
34
|
Requires-Dist: click-help-colors (>=0.9.4,<0.10.0)
|
|
33
|
-
Requires-Dist: cmem-cmempy (==25.
|
|
35
|
+
Requires-Dist: cmem-cmempy (==25.4.0)
|
|
34
36
|
Requires-Dist: configparser (>=7.2.0,<8.0.0)
|
|
35
37
|
Requires-Dist: jinja2 (>=3.1.6,<4.0.0)
|
|
36
38
|
Requires-Dist: junit-xml (>=1.9,<2.0)
|
|
@@ -24,48 +24,49 @@ class CmemcGroup(HelpColorsGroup, DYMGroup):
|
|
|
24
24
|
kwargs.setdefault(
|
|
25
25
|
"help_options_custom_colors",
|
|
26
26
|
{
|
|
27
|
+
"acl": self.color_for_command_groups,
|
|
28
|
+
"admin": self.color_for_command_groups,
|
|
27
29
|
"bootstrap": self.color_for_writing_commands,
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"upload": self.color_for_writing_commands,
|
|
33
|
-
"import": self.color_for_writing_commands,
|
|
30
|
+
"cache": self.color_for_command_groups,
|
|
31
|
+
"cancel": self.color_for_writing_commands,
|
|
32
|
+
"client": self.color_for_command_groups,
|
|
33
|
+
"config": self.color_for_command_groups,
|
|
34
34
|
"create": self.color_for_writing_commands,
|
|
35
|
-
"
|
|
35
|
+
"dataset": self.color_for_command_groups,
|
|
36
|
+
"delete": self.color_for_writing_commands,
|
|
36
37
|
"disable": self.color_for_writing_commands,
|
|
38
|
+
"enable": self.color_for_writing_commands,
|
|
39
|
+
"eval": self.color_for_writing_commands,
|
|
37
40
|
"execute": self.color_for_writing_commands,
|
|
38
|
-
"
|
|
39
|
-
"
|
|
41
|
+
"graph": self.color_for_command_groups,
|
|
42
|
+
"import": self.color_for_writing_commands,
|
|
43
|
+
"imports": self.color_for_command_groups,
|
|
44
|
+
"insights": self.color_for_command_groups,
|
|
40
45
|
"install": self.color_for_writing_commands,
|
|
41
|
-
"
|
|
42
|
-
"reload": self.color_for_writing_commands,
|
|
43
|
-
"update": self.color_for_writing_commands,
|
|
44
|
-
"eval": self.color_for_writing_commands,
|
|
45
|
-
"cancel": self.color_for_writing_commands,
|
|
46
|
-
"admin": self.color_for_command_groups,
|
|
47
|
-
"user": self.color_for_command_groups,
|
|
48
|
-
"store": self.color_for_command_groups,
|
|
46
|
+
"io": self.color_for_writing_commands,
|
|
49
47
|
"metrics": self.color_for_command_groups,
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
48
|
+
"migrate": self.color_for_writing_commands,
|
|
49
|
+
"migrations": self.color_for_command_groups,
|
|
50
|
+
"password": self.color_for_writing_commands,
|
|
53
51
|
"project": self.color_for_command_groups,
|
|
52
|
+
"python": self.color_for_command_groups,
|
|
54
53
|
"query": self.color_for_command_groups,
|
|
54
|
+
"reload": self.color_for_writing_commands,
|
|
55
|
+
"replay": self.color_for_writing_commands,
|
|
56
|
+
"resource": self.color_for_command_groups,
|
|
55
57
|
"scheduler": self.color_for_command_groups,
|
|
58
|
+
"secret": self.color_for_writing_commands,
|
|
59
|
+
"showcase": self.color_for_writing_commands,
|
|
60
|
+
"store": self.color_for_command_groups,
|
|
61
|
+
"uninstall": self.color_for_writing_commands,
|
|
62
|
+
"update": self.color_for_writing_commands,
|
|
63
|
+
"upload": self.color_for_writing_commands,
|
|
64
|
+
"user": self.color_for_command_groups,
|
|
65
|
+
"validation": self.color_for_command_groups,
|
|
66
|
+
"variable": self.color_for_command_groups,
|
|
56
67
|
"vocabulary": self.color_for_command_groups,
|
|
57
68
|
"workflow": self.color_for_command_groups,
|
|
58
69
|
"workspace": self.color_for_command_groups,
|
|
59
|
-
"python": self.color_for_command_groups,
|
|
60
|
-
"cache": self.color_for_command_groups,
|
|
61
|
-
"resource": self.color_for_command_groups,
|
|
62
|
-
"acl": self.color_for_command_groups,
|
|
63
|
-
"client": self.color_for_command_groups,
|
|
64
|
-
"variable": self.color_for_command_groups,
|
|
65
|
-
"validation": self.color_for_command_groups,
|
|
66
|
-
"migrate": self.color_for_writing_commands,
|
|
67
|
-
"migrations": self.color_for_command_groups,
|
|
68
|
-
"imports": self.color_for_command_groups,
|
|
69
70
|
},
|
|
70
71
|
)
|
|
71
72
|
super().__init__(*args, **kwargs)
|
|
@@ -35,7 +35,26 @@ HELP_TEXTS = {
|
|
|
35
35
|
"read_graph": "Grants read access to a graph.",
|
|
36
36
|
"write_graph": "Grants write access to a graph (includes read access).",
|
|
37
37
|
"action": "Grants usage permissions to an action / functionality.",
|
|
38
|
+
"read_graph_pattern": (
|
|
39
|
+
"Grants management of conditions granting read access on graphs matching the defined "
|
|
40
|
+
"pattern. A pattern consists of a constant string and a wildcard ('*') at the end of "
|
|
41
|
+
"the pattern or the wildcard alone."
|
|
42
|
+
),
|
|
43
|
+
"write_graph_pattern": (
|
|
44
|
+
"Grants management of conditions granting write access on graphs matching the defined "
|
|
45
|
+
"pattern. A pattern consists of a constant string and a wildcard ('*') at the end of "
|
|
46
|
+
"the pattern or the wildcard alone."
|
|
47
|
+
),
|
|
48
|
+
"action_pattern": (
|
|
49
|
+
"Grants management of conditions granting action allowance for actions matching the "
|
|
50
|
+
"defined pattern. A pattern consists of a constant string and a wildcard ('*') at the "
|
|
51
|
+
"end of the pattern or the wildcard alone."
|
|
52
|
+
),
|
|
38
53
|
"query": "Dynamic access condition query (file or the query catalog IRI).",
|
|
54
|
+
"replace": (
|
|
55
|
+
"Replace (overwrite) existing access condition, if present. "
|
|
56
|
+
"Can be used only in combination with '--id'."
|
|
57
|
+
),
|
|
39
58
|
}
|
|
40
59
|
|
|
41
60
|
WARNING_UNKNOWN_USER = "Unknown User or no access to get user info."
|
|
@@ -194,6 +213,27 @@ def inspect_command(app: ApplicationContext, access_condition_id: str, raw: bool
|
|
|
194
213
|
shell_complete=completion.acl_actions,
|
|
195
214
|
help=HELP_TEXTS["action"],
|
|
196
215
|
)
|
|
216
|
+
@click.option(
|
|
217
|
+
"--read-graph-pattern",
|
|
218
|
+
"read_graph_patterns",
|
|
219
|
+
type=click.STRING,
|
|
220
|
+
multiple=True,
|
|
221
|
+
help=HELP_TEXTS["read_graph_pattern"],
|
|
222
|
+
)
|
|
223
|
+
@click.option(
|
|
224
|
+
"--write-graph-pattern",
|
|
225
|
+
"write_graph_patterns",
|
|
226
|
+
type=click.STRING,
|
|
227
|
+
multiple=True,
|
|
228
|
+
help=HELP_TEXTS["write_graph_pattern"],
|
|
229
|
+
)
|
|
230
|
+
@click.option(
|
|
231
|
+
"--action-pattern",
|
|
232
|
+
"action_patterns",
|
|
233
|
+
type=click.STRING,
|
|
234
|
+
multiple=True,
|
|
235
|
+
help=HELP_TEXTS["action_pattern"],
|
|
236
|
+
)
|
|
197
237
|
@click.option(
|
|
198
238
|
"--query",
|
|
199
239
|
"query",
|
|
@@ -219,6 +259,7 @@ def inspect_command(app: ApplicationContext, access_condition_id: str, raw: bool
|
|
|
219
259
|
type=click.STRING,
|
|
220
260
|
help=HELP_TEXTS["description"],
|
|
221
261
|
)
|
|
262
|
+
@click.option("--replace", is_flag=True, help=HELP_TEXTS["replace"])
|
|
222
263
|
@click.pass_obj
|
|
223
264
|
# pylint: disable-msg=too-many-arguments
|
|
224
265
|
def create_command( # noqa: PLR0913
|
|
@@ -231,7 +272,11 @@ def create_command( # noqa: PLR0913
|
|
|
231
272
|
read_graphs: tuple[str],
|
|
232
273
|
write_graphs: tuple[str],
|
|
233
274
|
actions: tuple[str],
|
|
275
|
+
read_graph_patterns: tuple[str],
|
|
276
|
+
write_graph_patterns: tuple[str],
|
|
277
|
+
action_patterns: tuple[str],
|
|
234
278
|
query: str,
|
|
279
|
+
replace: bool,
|
|
235
280
|
) -> None:
|
|
236
281
|
"""Create an access condition.
|
|
237
282
|
|
|
@@ -254,17 +299,29 @@ def create_command( # noqa: PLR0913
|
|
|
254
299
|
|
|
255
300
|
Example: cmemc admin acl create --group local-users --write-graph https://example.org/
|
|
256
301
|
"""
|
|
257
|
-
if
|
|
302
|
+
if replace and not id_:
|
|
303
|
+
raise click.UsageError("To replace an access condition, you must specify an ID.")
|
|
304
|
+
|
|
305
|
+
if (
|
|
306
|
+
not read_graphs
|
|
307
|
+
and not write_graphs
|
|
308
|
+
and not actions
|
|
309
|
+
and not read_graph_patterns
|
|
310
|
+
and not write_graph_patterns
|
|
311
|
+
and not action_patterns
|
|
312
|
+
and not query
|
|
313
|
+
):
|
|
258
314
|
raise click.UsageError(
|
|
259
315
|
"Missing access / usage grant. Use at least one of the following options: "
|
|
260
|
-
"--read-graph, --write-graph, --action
|
|
316
|
+
"--read-graph, --write-graph, --action, --read-graph-pattern, "
|
|
317
|
+
"--write-graph-pattern, --action-pattern or --query."
|
|
261
318
|
)
|
|
262
319
|
query_str = None
|
|
263
320
|
if query:
|
|
264
321
|
query_str = get_query_text(query, {"user", "group", "readGraph", "writeGraph"})
|
|
265
322
|
|
|
266
323
|
if not user and not groups and not query:
|
|
267
|
-
app.echo_warning("Access conditions without a user or group assignment
|
|
324
|
+
app.echo_warning("Access conditions without a user or group assignment affects ALL users.")
|
|
268
325
|
|
|
269
326
|
if not name:
|
|
270
327
|
name = generate_acl_name(user=user, groups=groups, query=query)
|
|
@@ -272,11 +329,11 @@ def create_command( # noqa: PLR0913
|
|
|
272
329
|
if not description:
|
|
273
330
|
description = "This access condition was created with cmemc."
|
|
274
331
|
|
|
275
|
-
|
|
276
|
-
f"
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
332
|
+
if replace and NS_ACL + id_ in [_["iri"] for _ in fetch_all_acls()]:
|
|
333
|
+
app.echo_info(f"Replacing access condition '{id_}' ... ", nl=False)
|
|
334
|
+
delete_access_condition(iri=NS_ACL + id_)
|
|
335
|
+
else:
|
|
336
|
+
app.echo_info(f"Creating access condition '{name}' ... ", nl=False)
|
|
280
337
|
create_access_condition(
|
|
281
338
|
name=name,
|
|
282
339
|
static_id=id_,
|
|
@@ -286,6 +343,9 @@ def create_command( # noqa: PLR0913
|
|
|
286
343
|
read_graphs=list(read_graphs),
|
|
287
344
|
write_graphs=list(write_graphs),
|
|
288
345
|
actions=[convert_qname_to_iri(qname=_, default_ns=NS_ACTION) for _ in actions],
|
|
346
|
+
read_graph_patterns=list(read_graph_patterns),
|
|
347
|
+
write_graph_patterns=list(write_graph_patterns),
|
|
348
|
+
action_patterns=list(action_patterns),
|
|
289
349
|
query=query_str,
|
|
290
350
|
)
|
|
291
351
|
app.echo_success("done")
|
|
@@ -351,6 +411,27 @@ def create_command( # noqa: PLR0913
|
|
|
351
411
|
shell_complete=completion.acl_actions,
|
|
352
412
|
help=HELP_TEXTS["action"],
|
|
353
413
|
)
|
|
414
|
+
@click.option(
|
|
415
|
+
"--read-graph-pattern",
|
|
416
|
+
"read_graph_patterns",
|
|
417
|
+
type=click.STRING,
|
|
418
|
+
multiple=True,
|
|
419
|
+
help=HELP_TEXTS["read_graph_pattern"],
|
|
420
|
+
)
|
|
421
|
+
@click.option(
|
|
422
|
+
"--write-graph-pattern",
|
|
423
|
+
"write_graph_patterns",
|
|
424
|
+
type=click.STRING,
|
|
425
|
+
multiple=True,
|
|
426
|
+
help=HELP_TEXTS["write_graph_pattern"],
|
|
427
|
+
)
|
|
428
|
+
@click.option(
|
|
429
|
+
"--action-pattern",
|
|
430
|
+
"action_patterns",
|
|
431
|
+
type=click.STRING,
|
|
432
|
+
multiple=True,
|
|
433
|
+
help=HELP_TEXTS["action_pattern"],
|
|
434
|
+
)
|
|
354
435
|
@click.option(
|
|
355
436
|
"--query",
|
|
356
437
|
"query",
|
|
@@ -370,6 +451,9 @@ def update_command( # noqa: PLR0913
|
|
|
370
451
|
read_graphs: tuple[str],
|
|
371
452
|
write_graphs: tuple[str],
|
|
372
453
|
actions: tuple[str],
|
|
454
|
+
read_graph_patterns: tuple[str],
|
|
455
|
+
write_graph_patterns: tuple[str],
|
|
456
|
+
action_patterns: tuple[str],
|
|
373
457
|
query: str,
|
|
374
458
|
) -> None:
|
|
375
459
|
"""Update an access condition.
|
|
@@ -396,6 +480,9 @@ def update_command( # noqa: PLR0913
|
|
|
396
480
|
read_graphs=read_graphs,
|
|
397
481
|
write_graphs=write_graphs,
|
|
398
482
|
actions=[convert_qname_to_iri(qname=_, default_ns=NS_ACTION) for _ in actions],
|
|
483
|
+
read_graph_patterns=read_graph_patterns,
|
|
484
|
+
write_graph_patterns=write_graph_patterns,
|
|
485
|
+
action_patterns=action_patterns,
|
|
399
486
|
query=query_str,
|
|
400
487
|
)
|
|
401
488
|
app.echo_success("done")
|
|
@@ -4,6 +4,7 @@ from datetime import datetime, timezone
|
|
|
4
4
|
|
|
5
5
|
import click
|
|
6
6
|
import jwt
|
|
7
|
+
import timeago
|
|
7
8
|
from click import ClickException
|
|
8
9
|
from cmem.cmempy.api import get_access_token, get_token
|
|
9
10
|
from cmem.cmempy.config import get_cmem_base_uri
|
|
@@ -185,8 +186,14 @@ def status_command( # noqa: C901, PLR0912
|
|
|
185
186
|
help="Decode the access token and outputs the raw JSON. Note that the "
|
|
186
187
|
"access token is only decoded and esp. not validated.",
|
|
187
188
|
)
|
|
189
|
+
@click.option(
|
|
190
|
+
"--ttl",
|
|
191
|
+
is_flag=True,
|
|
192
|
+
help="Output information about the lifetime of the access token. "
|
|
193
|
+
"In combination with --raw, it outputs the TTL in seconds.",
|
|
194
|
+
)
|
|
188
195
|
@click.pass_obj
|
|
189
|
-
def token_command(app: ApplicationContext, raw: bool, decode: bool) -> None:
|
|
196
|
+
def token_command(app: ApplicationContext, raw: bool, decode: bool, ttl: bool) -> None:
|
|
190
197
|
"""Fetch and output an access token.
|
|
191
198
|
|
|
192
199
|
This command can be used to check for correct authentication as well as
|
|
@@ -202,9 +209,30 @@ def token_command(app: ApplicationContext, raw: bool, decode: bool) -> None:
|
|
|
202
209
|
# - get_access_token returns the token string which is maybe from conf
|
|
203
210
|
# - get_token fetches a new token incl. envelope from keycloak
|
|
204
211
|
|
|
212
|
+
token = get_access_token()
|
|
213
|
+
decoded_token = jwt.decode(token, options={"verify_signature": False})
|
|
214
|
+
if ttl:
|
|
215
|
+
app.echo_debug(token)
|
|
216
|
+
iat_ts = decoded_token["iat"]
|
|
217
|
+
exp_ts = decoded_token["exp"]
|
|
218
|
+
ttl_in_seconds = exp_ts - iat_ts
|
|
219
|
+
if raw:
|
|
220
|
+
app.echo_info_json(ttl_in_seconds)
|
|
221
|
+
return
|
|
222
|
+
exp_time = datetime.fromtimestamp(exp_ts, tz=timezone.utc)
|
|
223
|
+
now_time = datetime.now(tz=timezone.utc)
|
|
224
|
+
ttl_delta = timeago.format(exp_time, now_time)
|
|
225
|
+
if ttl_delta.startswith("in"):
|
|
226
|
+
app.echo_info(
|
|
227
|
+
f"The provided access token will expire {ttl_delta} "
|
|
228
|
+
f"(TTL is {ttl_in_seconds} seconds)."
|
|
229
|
+
)
|
|
230
|
+
else:
|
|
231
|
+
app.echo_info(
|
|
232
|
+
f"The provided access token expired {ttl_delta} (TTL was {ttl_in_seconds} seconds)."
|
|
233
|
+
)
|
|
234
|
+
return
|
|
205
235
|
if decode:
|
|
206
|
-
token = get_access_token()
|
|
207
|
-
decoded_token = jwt.decode(token, options={"verify_signature": False})
|
|
208
236
|
if raw:
|
|
209
237
|
app.echo_info_json(decoded_token)
|
|
210
238
|
return
|
|
@@ -214,7 +242,6 @@ def token_command(app: ApplicationContext, raw: bool, decode: bool) -> None:
|
|
|
214
242
|
if raw:
|
|
215
243
|
app.echo_info_json(get_token())
|
|
216
244
|
return
|
|
217
|
-
token = get_access_token()
|
|
218
245
|
app.echo_info(token)
|
|
219
246
|
|
|
220
247
|
|
|
@@ -27,6 +27,7 @@ from cmem_cmemc import completion
|
|
|
27
27
|
from cmem_cmemc.command import CmemcCommand
|
|
28
28
|
from cmem_cmemc.command_group import CmemcGroup
|
|
29
29
|
from cmem_cmemc.commands.graph_imports import graph_imports_list, imports_group
|
|
30
|
+
from cmem_cmemc.commands.graph_insights import insights_group
|
|
30
31
|
from cmem_cmemc.commands.validation import validation_group
|
|
31
32
|
from cmem_cmemc.constants import UNKNOWN_GRAPH_ERROR
|
|
32
33
|
from cmem_cmemc.context import ApplicationContext
|
|
@@ -567,10 +568,11 @@ def _get_graph_supported_formats() -> dict[str, str]:
|
|
|
567
568
|
|
|
568
569
|
def _get_buffer_and_content_type(
|
|
569
570
|
triple_file: str, app: ApplicationContext
|
|
570
|
-
) -> tuple[io.BytesIO, str]:
|
|
571
|
-
"""Get the io.BytesIO buffer and the content
|
|
571
|
+
) -> tuple[io.BytesIO, str, None | str]:
|
|
572
|
+
"""Get the io.BytesIO buffer, the content type and the content encoding of a triple_file"""
|
|
572
573
|
smart_file = SmartPath(triple_file)
|
|
573
574
|
content_type, encoding = mimetypes.guess_type(triple_file)
|
|
575
|
+
content_encoding = "gzip" if smart_file.name.endswith(".gz") else None
|
|
574
576
|
if content_type is None:
|
|
575
577
|
content_type = "text/turtle"
|
|
576
578
|
for supported_type, supported_suffix in _get_graph_supported_formats().items():
|
|
@@ -596,7 +598,7 @@ def _get_buffer_and_content_type(
|
|
|
596
598
|
with ClickSmartPath.open(triple_file, transport_params=transport_params) as file_obj:
|
|
597
599
|
buffer.write(file_obj.read())
|
|
598
600
|
buffer.seek(0)
|
|
599
|
-
return buffer, content_type
|
|
601
|
+
return buffer, content_type, content_encoding
|
|
600
602
|
|
|
601
603
|
|
|
602
604
|
def _create_graph_imports(ctx: Context, graphs: list[RdfGraphData]) -> None:
|
|
@@ -748,9 +750,13 @@ def import_command( # noqa: PLR0913
|
|
|
748
750
|
continue
|
|
749
751
|
# prevents re-replacing of graphs in a single run
|
|
750
752
|
_replace = False if graph_iri in processed_graphs else replace
|
|
751
|
-
_buffer, content_type = _get_buffer_and_content_type(triple_file, app)
|
|
753
|
+
_buffer, content_type, content_encoding = _get_buffer_and_content_type(triple_file, app)
|
|
752
754
|
response = graph_api.post_streamed(
|
|
753
|
-
graph_iri,
|
|
755
|
+
graph_iri,
|
|
756
|
+
_buffer,
|
|
757
|
+
replace=_replace,
|
|
758
|
+
content_type=content_type,
|
|
759
|
+
content_encoding=content_encoding,
|
|
754
760
|
)
|
|
755
761
|
request_headers = response.request.headers
|
|
756
762
|
request_headers.pop("Authorization")
|
|
@@ -886,3 +892,4 @@ graph.add_command(import_command)
|
|
|
886
892
|
graph.add_command(open_command)
|
|
887
893
|
graph.add_command(validation_group)
|
|
888
894
|
graph.add_command(imports_group)
|
|
895
|
+
graph.add_command(insights_group)
|
|
@@ -12,7 +12,6 @@ from treelib import Tree
|
|
|
12
12
|
from cmem_cmemc import completion
|
|
13
13
|
from cmem_cmemc.command import CmemcCommand
|
|
14
14
|
from cmem_cmemc.command_group import CmemcGroup
|
|
15
|
-
from cmem_cmemc.completion import escape_colon
|
|
16
15
|
from cmem_cmemc.constants import UNKNOWN_GRAPH_ERROR
|
|
17
16
|
from cmem_cmemc.context import ApplicationContext
|
|
18
17
|
from cmem_cmemc.object_list import DirectValuePropertyFilter, ObjectList
|
|
@@ -299,7 +298,7 @@ def _validate_graphs(from_graph: str | None, to_graph: str | None) -> None:
|
|
|
299
298
|
def _from_graph_uris(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
300
299
|
"""Provide auto completion items for delete command from-graph argument"""
|
|
301
300
|
imports = get_imports_list(ctx)
|
|
302
|
-
from_graphs = {
|
|
301
|
+
from_graphs = {_["from_graph"] for _ in imports}
|
|
303
302
|
return [
|
|
304
303
|
_
|
|
305
304
|
for _ in completion.graph_uris(ctx=ctx, param=param, incomplete=incomplete)
|
|
@@ -311,15 +310,13 @@ def _to_graph_uris(ctx: Context, param: Argument, incomplete: str) -> list[Compl
|
|
|
311
310
|
"""Provide auto completion items for create/delete command to-graph argument"""
|
|
312
311
|
from_graph = ctx.params["from_graph"]
|
|
313
312
|
imports = graph_imports_list.apply_filters(ctx=ctx, filter_=[("from-graph", from_graph)])
|
|
314
|
-
to_graphs = {
|
|
313
|
+
to_graphs = {_["to_graph"] for _ in imports}
|
|
315
314
|
command = ctx.command.name
|
|
316
315
|
return [
|
|
317
316
|
_
|
|
318
317
|
for _ in completion.graph_uris(ctx=ctx, param=param, incomplete=incomplete)
|
|
319
318
|
if (command == "delete" and _.value in to_graphs)
|
|
320
|
-
or (
|
|
321
|
-
command == "create" and _.value not in to_graphs and _.value != escape_colon(from_graph)
|
|
322
|
-
)
|
|
319
|
+
or (command == "create" and _.value not in to_graphs and _.value != from_graph)
|
|
323
320
|
]
|
|
324
321
|
|
|
325
322
|
|