tabsdata-cli 2.0.0__cp312-abi3-win_amd64.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.
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/__init__.py +5 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/_registry.py +78 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/assets/manifest/BANNER +5 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/assets/manifest/LICENSE +3 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/assets/manifest/README-PyPi.md +8 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/assets/manifest/RELEASE-NOTES +1 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/assets/manifest/THIRD-PARTY +3 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/assets/manifest/VERSION +1 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/cli_utils.py +993 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/shell.py +390 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/__init__.py +3 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/auth_group.py +197 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/cli.py +508 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/collection_group.py +458 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/config_utils.py +93 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/connection_group.py +159 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/examples_group.py +206 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/execution_utils.py +429 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/fn_group.py +1109 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/fnrun_group.py +285 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/group_group.py +184 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/metrics_group.py +323 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/permission_group.py +259 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/plan_group.py +324 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/project_group.py +170 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/role_group.py +630 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/settings_group.py +344 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/table_group.py +600 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/trigger_group.py +338 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/trx_group.py +329 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/user_group.py +200 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/worker_group.py +185 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/template.py +781 -0
- tabsdata_cli-2.0.0.data/purelib/tabsdatak/py.typed +0 -0
- tabsdata_cli-2.0.0.dist-info/METADATA +39 -0
- tabsdata_cli-2.0.0.dist-info/RECORD +39 -0
- tabsdata_cli-2.0.0.dist-info/WHEEL +5 -0
- tabsdata_cli-2.0.0.dist-info/licenses/src/main/python/tabsdatak/cli/assets/manifest/LICENSE +3 -0
- tabsdata_cli-2.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,630 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright 2026 Tabsdata Inc.
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
import rich_click as click
|
|
7
|
+
from rich.table import Table
|
|
8
|
+
|
|
9
|
+
from tabsdatak.cli._registry import cli_command
|
|
10
|
+
from tabsdatak.cli.cli_utils import (
|
|
11
|
+
MutuallyExclusiveOption,
|
|
12
|
+
echo_more_results,
|
|
13
|
+
get_currently_pinned_object,
|
|
14
|
+
get_pin,
|
|
15
|
+
hint_common_solutions,
|
|
16
|
+
logical_prompt,
|
|
17
|
+
make_console,
|
|
18
|
+
max_result_option,
|
|
19
|
+
set_pin,
|
|
20
|
+
store_cli_options,
|
|
21
|
+
take,
|
|
22
|
+
verify_login_or_prompt,
|
|
23
|
+
)
|
|
24
|
+
from tabsdatak.sdk.tabsdata_server import (
|
|
25
|
+
PERMISSION_TYPES_WITH_ENTITY,
|
|
26
|
+
VALID_PERMISSION_TYPES,
|
|
27
|
+
Role,
|
|
28
|
+
TabsdataServer,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
ALL_ENTITIES_REPRESENTATION = "<ALL>"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@cli_command
|
|
35
|
+
@click.group()
|
|
36
|
+
def role():
|
|
37
|
+
"""Role management commands"""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@role.command()
|
|
41
|
+
@click.option(
|
|
42
|
+
"--name",
|
|
43
|
+
"-n",
|
|
44
|
+
help="Name of the role to which the permissions will be added.",
|
|
45
|
+
)
|
|
46
|
+
@click.option(
|
|
47
|
+
"--perm",
|
|
48
|
+
help=(
|
|
49
|
+
"Permission to add. Will "
|
|
50
|
+
"be prompted for it if not provided. Valid values are "
|
|
51
|
+
f"{', '.join(str(p) for p in VALID_PERMISSION_TYPES)}"
|
|
52
|
+
),
|
|
53
|
+
)
|
|
54
|
+
@click.option(
|
|
55
|
+
"--proj",
|
|
56
|
+
"project",
|
|
57
|
+
help=(
|
|
58
|
+
"Project to which the permission will apply. If '"
|
|
59
|
+
f"{ALL_ENTITIES_REPRESENTATION}' is provided, it will "
|
|
60
|
+
"apply to all projects. This option is only allowed for "
|
|
61
|
+
"permissions that require an entity, which are "
|
|
62
|
+
f"{', '.join(str(p) for p in PERMISSION_TYPES_WITH_ENTITY)}."
|
|
63
|
+
),
|
|
64
|
+
)
|
|
65
|
+
@click.pass_context
|
|
66
|
+
def add_perm(ctx: click.Context, name: str, perm: str, project: str):
|
|
67
|
+
"""Add a permission to a role"""
|
|
68
|
+
verify_login_or_prompt(ctx)
|
|
69
|
+
name = (
|
|
70
|
+
name
|
|
71
|
+
or get_currently_pinned_object(ctx, "role")
|
|
72
|
+
or logical_prompt(ctx, "Name of the role to add the permission to")
|
|
73
|
+
)
|
|
74
|
+
perm = perm or logical_prompt(
|
|
75
|
+
ctx,
|
|
76
|
+
"Permission to add. Valid values are "
|
|
77
|
+
f"'{', '.join(str(p) for p in VALID_PERMISSION_TYPES)}'",
|
|
78
|
+
)
|
|
79
|
+
flattened_list = [item for tup in PERMISSION_TYPES_WITH_ENTITY for item in tup]
|
|
80
|
+
requires_entity = perm in flattened_list
|
|
81
|
+
if project:
|
|
82
|
+
if not requires_entity:
|
|
83
|
+
raise click.ClickException(
|
|
84
|
+
f"Permission '{perm}' does not require an entity. The permissions "
|
|
85
|
+
"that require an entity are: "
|
|
86
|
+
f"{', '.join(str(p) for p in PERMISSION_TYPES_WITH_ENTITY)}. "
|
|
87
|
+
"Please remove the --proj option."
|
|
88
|
+
)
|
|
89
|
+
if project == ALL_ENTITIES_REPRESENTATION:
|
|
90
|
+
project = None
|
|
91
|
+
else:
|
|
92
|
+
if requires_entity:
|
|
93
|
+
project = logical_prompt(
|
|
94
|
+
ctx,
|
|
95
|
+
"Project to which the permission will apply. If "
|
|
96
|
+
f"'{ALL_ENTITIES_REPRESENTATION}' is provided, it will apply "
|
|
97
|
+
"to all projects.",
|
|
98
|
+
default_value=ALL_ENTITIES_REPRESENTATION,
|
|
99
|
+
)
|
|
100
|
+
if project == ALL_ENTITIES_REPRESENTATION:
|
|
101
|
+
project = None
|
|
102
|
+
try:
|
|
103
|
+
click.echo(f"Adding permission of type '{perm}' to role '{name}'")
|
|
104
|
+
click.echo("-" * 10)
|
|
105
|
+
server: TabsdataServer = ctx.obj["tabsdataserver"]
|
|
106
|
+
role = server.get_role(name)
|
|
107
|
+
permission = role.create_permission(perm, project)
|
|
108
|
+
|
|
109
|
+
click.echo("Permission added successfully")
|
|
110
|
+
click.echo(f"Permission ID: {permission.id}")
|
|
111
|
+
except Exception as e:
|
|
112
|
+
hint_common_solutions(ctx, e)
|
|
113
|
+
raise click.ClickException(f"Failed to add permission: {e}")
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@role.command()
|
|
117
|
+
@click.option(
|
|
118
|
+
"--name",
|
|
119
|
+
"-n",
|
|
120
|
+
help="Name of the role to which the user will be added.",
|
|
121
|
+
)
|
|
122
|
+
@click.option(
|
|
123
|
+
"--user",
|
|
124
|
+
"-u",
|
|
125
|
+
help="User that will be added to the role.",
|
|
126
|
+
)
|
|
127
|
+
@click.pass_context
|
|
128
|
+
def add_user(ctx: click.Context, name: str, user: str):
|
|
129
|
+
"""Add a user to a role"""
|
|
130
|
+
verify_login_or_prompt(ctx)
|
|
131
|
+
name = (
|
|
132
|
+
name
|
|
133
|
+
or get_currently_pinned_object(ctx, "role")
|
|
134
|
+
or logical_prompt(ctx, "Name of the role to the user to")
|
|
135
|
+
)
|
|
136
|
+
user = user or logical_prompt(ctx, "User that will be added to the role")
|
|
137
|
+
try:
|
|
138
|
+
click.echo(f"Adding user '{user}' to role '{name}'")
|
|
139
|
+
click.echo("-" * 10)
|
|
140
|
+
server: TabsdataServer = ctx.obj["tabsdataserver"]
|
|
141
|
+
role = server.get_role(name)
|
|
142
|
+
role.add_user(user)
|
|
143
|
+
|
|
144
|
+
click.echo("User added successfully")
|
|
145
|
+
except Exception as e:
|
|
146
|
+
hint_common_solutions(ctx, e)
|
|
147
|
+
raise click.ClickException(f"Failed to add user to role: {e}")
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@role.command()
|
|
151
|
+
@click.option("--name", "-n", help="Name of the role to create.")
|
|
152
|
+
@click.option("--description", help="Description of the role.")
|
|
153
|
+
@click.pass_context
|
|
154
|
+
def create(
|
|
155
|
+
ctx: click.Context,
|
|
156
|
+
name: str,
|
|
157
|
+
description: str,
|
|
158
|
+
):
|
|
159
|
+
"""Create a new role"""
|
|
160
|
+
verify_login_or_prompt(ctx)
|
|
161
|
+
name = (
|
|
162
|
+
name
|
|
163
|
+
or get_currently_pinned_object(ctx, "role")
|
|
164
|
+
or logical_prompt(ctx, "Name of the role to create")
|
|
165
|
+
)
|
|
166
|
+
description = description or ""
|
|
167
|
+
click.echo("Creating a new role")
|
|
168
|
+
click.echo("-" * 10)
|
|
169
|
+
try:
|
|
170
|
+
server: TabsdataServer = ctx.obj["tabsdataserver"]
|
|
171
|
+
server.create_role(name, description)
|
|
172
|
+
click.echo("Role created successfully")
|
|
173
|
+
except Exception as e:
|
|
174
|
+
hint_common_solutions(ctx, e)
|
|
175
|
+
raise click.ClickException(f"Failed to create role: {e}")
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
@role.command()
|
|
179
|
+
@click.option("--name", "-n", help="Name of the role to delete.")
|
|
180
|
+
@click.option(
|
|
181
|
+
"--confirm",
|
|
182
|
+
help="Write 'delete' to confirm deletion. Will be prompted for it if not provided.",
|
|
183
|
+
)
|
|
184
|
+
@click.pass_context
|
|
185
|
+
def delete(ctx: click.Context, name: str, confirm: str):
|
|
186
|
+
"""Delete a role by name"""
|
|
187
|
+
verify_login_or_prompt(ctx)
|
|
188
|
+
name = (
|
|
189
|
+
name
|
|
190
|
+
or get_currently_pinned_object(ctx, "role")
|
|
191
|
+
or logical_prompt(ctx, "Name of the role to delete")
|
|
192
|
+
)
|
|
193
|
+
click.echo(f"Deleting role: {name}")
|
|
194
|
+
click.echo("-" * 10)
|
|
195
|
+
confirm = confirm or logical_prompt(ctx, "Please type 'delete' to confirm deletion")
|
|
196
|
+
if confirm != "delete":
|
|
197
|
+
raise click.ClickException(
|
|
198
|
+
"Deletion not confirmed. The confirmation word is 'delete'."
|
|
199
|
+
)
|
|
200
|
+
try:
|
|
201
|
+
server: TabsdataServer = ctx.obj["tabsdataserver"]
|
|
202
|
+
server.delete_role(name)
|
|
203
|
+
click.echo("Role deleted successfully")
|
|
204
|
+
except Exception as e:
|
|
205
|
+
hint_common_solutions(ctx, e)
|
|
206
|
+
raise click.ClickException(f"Failed to delete role: {e}")
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
@role.command()
|
|
210
|
+
@click.option(
|
|
211
|
+
"--name",
|
|
212
|
+
"-n",
|
|
213
|
+
help="Name of the role from which the permissions will be deleted.",
|
|
214
|
+
)
|
|
215
|
+
@click.option(
|
|
216
|
+
"--id",
|
|
217
|
+
help="ID of the permission to delete.",
|
|
218
|
+
cls=MutuallyExclusiveOption,
|
|
219
|
+
mutually_exclusive=["perm", "project"],
|
|
220
|
+
)
|
|
221
|
+
@click.option(
|
|
222
|
+
"--perm",
|
|
223
|
+
help=(
|
|
224
|
+
"Permission to delete. Valid values are "
|
|
225
|
+
f"{', '.join(str(p) for p in VALID_PERMISSION_TYPES)}"
|
|
226
|
+
),
|
|
227
|
+
cls=MutuallyExclusiveOption,
|
|
228
|
+
mutually_exclusive=["id"],
|
|
229
|
+
)
|
|
230
|
+
@click.option(
|
|
231
|
+
"--proj",
|
|
232
|
+
"project",
|
|
233
|
+
help=(
|
|
234
|
+
"Project to which the permission applies. "
|
|
235
|
+
"This option is only allowed for permissions that require an entity, which are "
|
|
236
|
+
f"{', '.join(str(p) for p in PERMISSION_TYPES_WITH_ENTITY)}."
|
|
237
|
+
),
|
|
238
|
+
cls=MutuallyExclusiveOption,
|
|
239
|
+
mutually_exclusive=["id"],
|
|
240
|
+
)
|
|
241
|
+
@click.pass_context
|
|
242
|
+
def delete_perm(ctx: click.Context, name: str, id: str, perm: str, project: str):
|
|
243
|
+
"""Delete a permission from a role"""
|
|
244
|
+
verify_login_or_prompt(ctx)
|
|
245
|
+
name = (
|
|
246
|
+
name
|
|
247
|
+
or get_currently_pinned_object(ctx, "role")
|
|
248
|
+
or logical_prompt(
|
|
249
|
+
ctx, "Name of the role from which the permission will be deleted"
|
|
250
|
+
)
|
|
251
|
+
)
|
|
252
|
+
if not perm:
|
|
253
|
+
id = id or logical_prompt(ctx, "ID of the permission to delete")
|
|
254
|
+
else:
|
|
255
|
+
project = _obtain_project_for_perm(perm, project, ctx)
|
|
256
|
+
try:
|
|
257
|
+
if id:
|
|
258
|
+
click.echo(f"Deleting permission from role '{name}' with ID '{id}'")
|
|
259
|
+
else:
|
|
260
|
+
click.echo(f"Deleting permission '{perm}' from role '{name}'")
|
|
261
|
+
click.echo("-" * 10)
|
|
262
|
+
server: TabsdataServer = ctx.obj["tabsdataserver"]
|
|
263
|
+
role = server.get_role(name)
|
|
264
|
+
if id:
|
|
265
|
+
_delete_permission_by_id(role, id, name)
|
|
266
|
+
else:
|
|
267
|
+
_delete_permission_by_type_and_entity(perm, project, role, name)
|
|
268
|
+
|
|
269
|
+
click.echo("Permission deleted successfully")
|
|
270
|
+
except Exception as e:
|
|
271
|
+
hint_common_solutions(ctx, e)
|
|
272
|
+
raise click.ClickException(f"Failed to delete permission: {e}")
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def _delete_permission_by_id(role: Role, id: str, name: str):
|
|
276
|
+
permissions = role.list_permissions(filter=f"id:eq:{id}")
|
|
277
|
+
try:
|
|
278
|
+
permission = permissions[0]
|
|
279
|
+
except IndexError:
|
|
280
|
+
raise click.ClickException(
|
|
281
|
+
f"No permission found for role '{name}' with ID '{id}'. The"
|
|
282
|
+
" existing permissions are:"
|
|
283
|
+
f" {', '.join(p.id for p in role.permissions)}"
|
|
284
|
+
)
|
|
285
|
+
role.delete_permission(permission)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def _obtain_project_for_perm(perm: str, project: str, ctx: click.Context):
|
|
289
|
+
flattened_list = [item for tup in PERMISSION_TYPES_WITH_ENTITY for item in tup]
|
|
290
|
+
requires_entity = perm in flattened_list
|
|
291
|
+
if project:
|
|
292
|
+
if not requires_entity:
|
|
293
|
+
raise click.ClickException(
|
|
294
|
+
f"Permission '{perm}' does not require an entity. The permissions "
|
|
295
|
+
"that require an entity are: "
|
|
296
|
+
f"{', '.join(str(p) for p in PERMISSION_TYPES_WITH_ENTITY)}. "
|
|
297
|
+
"Please remove the --proj option."
|
|
298
|
+
)
|
|
299
|
+
if project == ALL_ENTITIES_REPRESENTATION:
|
|
300
|
+
project = None
|
|
301
|
+
else:
|
|
302
|
+
if requires_entity:
|
|
303
|
+
project = logical_prompt(
|
|
304
|
+
ctx,
|
|
305
|
+
"Project to which the permission that will be deleted "
|
|
306
|
+
"currently applies. Provide "
|
|
307
|
+
f"'{ALL_ENTITIES_REPRESENTATION}' if it applies "
|
|
308
|
+
"to all projects.",
|
|
309
|
+
default_value=ALL_ENTITIES_REPRESENTATION,
|
|
310
|
+
)
|
|
311
|
+
if project == ALL_ENTITIES_REPRESENTATION:
|
|
312
|
+
project = None
|
|
313
|
+
return project
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def _delete_permission_by_type_and_entity(
|
|
317
|
+
perm: str, project: str, role: Role, name: str
|
|
318
|
+
):
|
|
319
|
+
for n, value in VALID_PERMISSION_TYPES:
|
|
320
|
+
if perm.lower() == n or perm.lower() == value:
|
|
321
|
+
permission_type = value
|
|
322
|
+
break
|
|
323
|
+
else:
|
|
324
|
+
raise click.ClickException(
|
|
325
|
+
f"'{perm}' is an invalid permission type. "
|
|
326
|
+
"The valid values are: "
|
|
327
|
+
f"{', '.join(str(p) for p in VALID_PERMISSION_TYPES)}."
|
|
328
|
+
)
|
|
329
|
+
permissions = role.list_permissions(
|
|
330
|
+
filter=f"permission_type:eq:{permission_type}",
|
|
331
|
+
)
|
|
332
|
+
for p in permissions:
|
|
333
|
+
if p.entity == project:
|
|
334
|
+
role.delete_permission(p)
|
|
335
|
+
break
|
|
336
|
+
else:
|
|
337
|
+
flattened_list = [item for tup in PERMISSION_TYPES_WITH_ENTITY for item in tup]
|
|
338
|
+
list_of_permissions = []
|
|
339
|
+
for p in role.permissions:
|
|
340
|
+
entity = p.entity
|
|
341
|
+
if not entity:
|
|
342
|
+
entity = (
|
|
343
|
+
ALL_ENTITIES_REPRESENTATION if p.type in flattened_list else "-"
|
|
344
|
+
)
|
|
345
|
+
list_of_permissions.append((p.type, entity))
|
|
346
|
+
raise click.ClickException(
|
|
347
|
+
f"No permission found for role '{name}' with type '{perm}' and "
|
|
348
|
+
"applying to the provided entity. The existing "
|
|
349
|
+
"permissions are: "
|
|
350
|
+
f"{', '.join(str(p) for p in list_of_permissions)}"
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
@role.command()
|
|
355
|
+
@click.option(
|
|
356
|
+
"--name",
|
|
357
|
+
"-n",
|
|
358
|
+
help="Name of the role from which the user will be deleted.",
|
|
359
|
+
)
|
|
360
|
+
@click.option(
|
|
361
|
+
"--user",
|
|
362
|
+
"-u",
|
|
363
|
+
help="User to delete from the role.",
|
|
364
|
+
)
|
|
365
|
+
@click.pass_context
|
|
366
|
+
def delete_user(ctx: click.Context, name: str, user: str):
|
|
367
|
+
"""Delete a user from a role"""
|
|
368
|
+
verify_login_or_prompt(ctx)
|
|
369
|
+
name = (
|
|
370
|
+
name
|
|
371
|
+
or get_currently_pinned_object(ctx, "role")
|
|
372
|
+
or logical_prompt(ctx, "Name of the role from which the user will be deleted")
|
|
373
|
+
)
|
|
374
|
+
user = user or logical_prompt(ctx, "User to delete from the role")
|
|
375
|
+
try:
|
|
376
|
+
click.echo(f"Deleting user '{user}' from role '{name}'")
|
|
377
|
+
click.echo("-" * 10)
|
|
378
|
+
server: TabsdataServer = ctx.obj["tabsdataserver"]
|
|
379
|
+
role = server.get_role(name)
|
|
380
|
+
users = role.list_users(filter=f"user:eq:{user}")
|
|
381
|
+
try:
|
|
382
|
+
user = users[0]
|
|
383
|
+
except IndexError:
|
|
384
|
+
raise click.ClickException(
|
|
385
|
+
f"No users found for role '{name}' with name '{user}'. The existing "
|
|
386
|
+
f"users are: {', '.join(u.name for u in role.users)}"
|
|
387
|
+
)
|
|
388
|
+
role.delete_user(user)
|
|
389
|
+
|
|
390
|
+
click.echo("User deleted from role successfully")
|
|
391
|
+
except Exception as e:
|
|
392
|
+
hint_common_solutions(ctx, e)
|
|
393
|
+
raise click.ClickException(f"Failed to delete user from role: {e}")
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
@role.command()
|
|
397
|
+
@click.option("--name", "-n", help="Name of the role to display.")
|
|
398
|
+
@click.pass_context
|
|
399
|
+
def info(ctx: click.Context, name: str):
|
|
400
|
+
"""Display a role by name"""
|
|
401
|
+
verify_login_or_prompt(ctx)
|
|
402
|
+
name = (
|
|
403
|
+
name
|
|
404
|
+
or get_currently_pinned_object(ctx, "role")
|
|
405
|
+
or logical_prompt(ctx, "Name of the role to display")
|
|
406
|
+
)
|
|
407
|
+
try:
|
|
408
|
+
server: TabsdataServer = ctx.obj["tabsdataserver"]
|
|
409
|
+
role = server.get_role(name)
|
|
410
|
+
|
|
411
|
+
table = Table(title="Role")
|
|
412
|
+
table.add_column("Name", style="cyan", no_wrap=True)
|
|
413
|
+
table.add_column("ID", no_wrap=True)
|
|
414
|
+
table.add_column("Description")
|
|
415
|
+
table.add_column("Created on")
|
|
416
|
+
table.add_column("Created by")
|
|
417
|
+
|
|
418
|
+
table.add_row(
|
|
419
|
+
role.name,
|
|
420
|
+
role.id,
|
|
421
|
+
role.description,
|
|
422
|
+
role.created_on_str,
|
|
423
|
+
role.created_by,
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
click.echo()
|
|
427
|
+
console = make_console()
|
|
428
|
+
console.print(table)
|
|
429
|
+
click.echo()
|
|
430
|
+
except Exception as e:
|
|
431
|
+
hint_common_solutions(ctx, e)
|
|
432
|
+
raise click.ClickException(f"Failed to display role: {e}")
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
@role.command()
|
|
436
|
+
@max_result_option
|
|
437
|
+
@click.pass_context
|
|
438
|
+
def list(ctx: click.Context):
|
|
439
|
+
"""List all roles"""
|
|
440
|
+
verify_login_or_prompt(ctx)
|
|
441
|
+
try:
|
|
442
|
+
server: TabsdataServer = ctx.obj["tabsdataserver"]
|
|
443
|
+
list_of_roles, truncated = take(ctx, server.list_roles_generator())
|
|
444
|
+
|
|
445
|
+
table = Table(title="Roles")
|
|
446
|
+
table.add_column("Name", style="cyan", no_wrap=True)
|
|
447
|
+
table.add_column("ID", no_wrap=True)
|
|
448
|
+
table.add_column("Description")
|
|
449
|
+
table.add_column("Created on")
|
|
450
|
+
table.add_column("Created by")
|
|
451
|
+
|
|
452
|
+
for role in list_of_roles:
|
|
453
|
+
table.add_row(
|
|
454
|
+
role.name,
|
|
455
|
+
role.id,
|
|
456
|
+
role.description,
|
|
457
|
+
role.created_on_str,
|
|
458
|
+
role.created_by,
|
|
459
|
+
)
|
|
460
|
+
|
|
461
|
+
click.echo()
|
|
462
|
+
console = make_console()
|
|
463
|
+
console.print(table)
|
|
464
|
+
click.echo(f"Number of roles: {len(list_of_roles)}")
|
|
465
|
+
echo_more_results(ctx, truncated)
|
|
466
|
+
click.echo()
|
|
467
|
+
except Exception as e:
|
|
468
|
+
hint_common_solutions(ctx, e)
|
|
469
|
+
raise click.ClickException(f"Failed to list roles: {e}")
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
@role.command()
|
|
473
|
+
@click.option("--name", "-n", help="Name of the role to which the permissions belong.")
|
|
474
|
+
@max_result_option
|
|
475
|
+
@click.pass_context
|
|
476
|
+
def list_perm(ctx: click.Context, name: str):
|
|
477
|
+
"""List all permissions of a role"""
|
|
478
|
+
verify_login_or_prompt(ctx)
|
|
479
|
+
name = (
|
|
480
|
+
name
|
|
481
|
+
or get_currently_pinned_object(ctx, "role")
|
|
482
|
+
or logical_prompt(ctx, "Name of the role to which the permissions belong")
|
|
483
|
+
)
|
|
484
|
+
try:
|
|
485
|
+
server: TabsdataServer = ctx.obj["tabsdataserver"]
|
|
486
|
+
role = server.get_role(name)
|
|
487
|
+
list_of_permissions, truncated = take(ctx, role.list_permissions_generator())
|
|
488
|
+
|
|
489
|
+
table = Table(title="Permissions")
|
|
490
|
+
table.add_column("ID", style="cyan", no_wrap=True)
|
|
491
|
+
table.add_column("Permission type")
|
|
492
|
+
table.add_column("Entity name")
|
|
493
|
+
table.add_column("Granted on")
|
|
494
|
+
table.add_column("Granted by")
|
|
495
|
+
|
|
496
|
+
for permission in list_of_permissions:
|
|
497
|
+
permission_type = permission.type
|
|
498
|
+
flattened_list = [
|
|
499
|
+
item for tup in PERMISSION_TYPES_WITH_ENTITY for item in tup
|
|
500
|
+
]
|
|
501
|
+
if permission_type not in flattened_list:
|
|
502
|
+
entity = "-"
|
|
503
|
+
else:
|
|
504
|
+
entity = (
|
|
505
|
+
permission.entity
|
|
506
|
+
if permission.entity
|
|
507
|
+
else ALL_ENTITIES_REPRESENTATION
|
|
508
|
+
)
|
|
509
|
+
table.add_row(
|
|
510
|
+
permission.id,
|
|
511
|
+
permission_type,
|
|
512
|
+
entity,
|
|
513
|
+
permission.granted_on_str,
|
|
514
|
+
permission.granted_by,
|
|
515
|
+
)
|
|
516
|
+
|
|
517
|
+
click.echo()
|
|
518
|
+
console = make_console()
|
|
519
|
+
console.print(table)
|
|
520
|
+
click.echo(f"Number of permissions: {len(list_of_permissions)}")
|
|
521
|
+
echo_more_results(ctx, truncated)
|
|
522
|
+
click.echo()
|
|
523
|
+
except Exception as e:
|
|
524
|
+
hint_common_solutions(ctx, e)
|
|
525
|
+
raise click.ClickException(f"Failed to list permissions: {e}")
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
@role.command()
|
|
529
|
+
@click.option("--name", "-n", help="Name of the role to which the users belong.")
|
|
530
|
+
@max_result_option
|
|
531
|
+
@click.pass_context
|
|
532
|
+
def list_user(ctx: click.Context, name: str):
|
|
533
|
+
"""List all users of a role"""
|
|
534
|
+
verify_login_or_prompt(ctx)
|
|
535
|
+
name = (
|
|
536
|
+
name
|
|
537
|
+
or get_currently_pinned_object(ctx, "role")
|
|
538
|
+
or logical_prompt(ctx, "Name of the role to which the users belong")
|
|
539
|
+
)
|
|
540
|
+
try:
|
|
541
|
+
server: TabsdataServer = ctx.obj["tabsdataserver"]
|
|
542
|
+
role = server.get_role(name)
|
|
543
|
+
list_of_users, truncated = take(ctx, role.list_users_generator())
|
|
544
|
+
|
|
545
|
+
table = Table(title="Users")
|
|
546
|
+
table.add_column("Name", style="cyan", no_wrap=True)
|
|
547
|
+
table.add_column("Full name")
|
|
548
|
+
table.add_column("Email")
|
|
549
|
+
table.add_column("Enabled")
|
|
550
|
+
|
|
551
|
+
for user in list_of_users:
|
|
552
|
+
table.add_row(user.name, user.full_name, user.email, str(user.enabled))
|
|
553
|
+
|
|
554
|
+
click.echo()
|
|
555
|
+
console = make_console()
|
|
556
|
+
console.print(table)
|
|
557
|
+
click.echo(f"Number of users: {len(list_of_users)}")
|
|
558
|
+
echo_more_results(ctx, truncated)
|
|
559
|
+
click.echo()
|
|
560
|
+
except Exception as e:
|
|
561
|
+
hint_common_solutions(ctx, e)
|
|
562
|
+
raise click.ClickException(f"Failed to list users: {e}")
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
@role.command()
|
|
566
|
+
@click.option("--name", "-n", help="Name of the role to pin.")
|
|
567
|
+
@click.pass_context
|
|
568
|
+
def pin(ctx: click.Context, name: str):
|
|
569
|
+
"""Pin a role by name"""
|
|
570
|
+
name = name or logical_prompt(ctx, "Name of the role to be pinned")
|
|
571
|
+
click.echo(f"Pinning role: {name}")
|
|
572
|
+
click.echo("-" * 10)
|
|
573
|
+
try:
|
|
574
|
+
previously_pinned = get_pin(ctx, "role")
|
|
575
|
+
if previously_pinned:
|
|
576
|
+
click.echo(f"Unpinning previously pinned role: {previously_pinned}")
|
|
577
|
+
set_pin(ctx, "role", name)
|
|
578
|
+
store_cli_options(ctx)
|
|
579
|
+
click.echo("Role pinned successfully")
|
|
580
|
+
except Exception as e:
|
|
581
|
+
hint_common_solutions(ctx, e)
|
|
582
|
+
raise click.ClickException(f"Failed to pin role: {e}")
|
|
583
|
+
|
|
584
|
+
|
|
585
|
+
@role.command()
|
|
586
|
+
@click.pass_context
|
|
587
|
+
def unpin(ctx: click.Context):
|
|
588
|
+
"""Unpin the currently pinned role"""
|
|
589
|
+
click.echo("Unpinning role")
|
|
590
|
+
click.echo("-" * 10)
|
|
591
|
+
try:
|
|
592
|
+
previously_pinned = get_pin(ctx, "role")
|
|
593
|
+
if not previously_pinned:
|
|
594
|
+
click.echo("No previously pinned role to unpin.")
|
|
595
|
+
else:
|
|
596
|
+
set_pin(ctx, "role", None)
|
|
597
|
+
store_cli_options(ctx)
|
|
598
|
+
click.echo("Role unpinned successfully")
|
|
599
|
+
except Exception as e:
|
|
600
|
+
hint_common_solutions(ctx, e)
|
|
601
|
+
raise click.ClickException(f"Failed to unpin role: {e}")
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
@role.command()
|
|
605
|
+
@click.option("--name", "-n", help="Name of the role to update.")
|
|
606
|
+
@click.option("--new-name", help="New name for the role.")
|
|
607
|
+
@click.option("--description", help="New description for the role.")
|
|
608
|
+
@click.pass_context
|
|
609
|
+
def update(
|
|
610
|
+
ctx: click.Context,
|
|
611
|
+
name: str,
|
|
612
|
+
new_name: str,
|
|
613
|
+
description: str,
|
|
614
|
+
):
|
|
615
|
+
"""Update a role by name"""
|
|
616
|
+
verify_login_or_prompt(ctx)
|
|
617
|
+
name = (
|
|
618
|
+
name
|
|
619
|
+
or get_currently_pinned_object(ctx, "role")
|
|
620
|
+
or logical_prompt(ctx, "Name of the role to update")
|
|
621
|
+
)
|
|
622
|
+
click.echo(f"Updating role: {name}")
|
|
623
|
+
click.echo("-" * 10)
|
|
624
|
+
try:
|
|
625
|
+
server: TabsdataServer = ctx.obj["tabsdataserver"]
|
|
626
|
+
server.update_role(name, new_name=new_name, new_description=description)
|
|
627
|
+
click.echo("Role updated successfully")
|
|
628
|
+
except Exception as e:
|
|
629
|
+
hint_common_solutions(ctx, e)
|
|
630
|
+
raise click.ClickException(f"Failed to update role: {e}")
|