forked from Github-Mirrors/canaille
Merge branch 'get-all' into 'main'
feat: implement '--all' option of 'get' command See merge request yaal/canaille!211
This commit is contained in:
commit
32cb5119fd
3 changed files with 112 additions and 33 deletions
|
@ -5,6 +5,7 @@ Added
|
||||||
^^^^^
|
^^^^^
|
||||||
- ``--version`` option to the CLI. :pr:`209`
|
- ``--version`` option to the CLI. :pr:`209`
|
||||||
- :attr:`~canaille.backends.sql.configuration.SQLSettings.PASSWORD_SCHEMES` :issue:`175`
|
- :attr:`~canaille.backends.sql.configuration.SQLSettings.PASSWORD_SCHEMES` :issue:`175`
|
||||||
|
- `canaille get --all` command option to perform full database dumps
|
||||||
|
|
||||||
Changed
|
Changed
|
||||||
^^^^^^^
|
^^^^^^^
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import datetime
|
import datetime
|
||||||
import inspect
|
|
||||||
import json
|
import json
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
|
@ -70,15 +69,10 @@ def is_multiple(attribute_type):
|
||||||
def register(cli):
|
def register(cli):
|
||||||
"""Generate commands using factories that each have one subcommand per
|
"""Generate commands using factories that each have one subcommand per
|
||||||
available model."""
|
available model."""
|
||||||
factories = [get_factory, set_factory, create_factory, delete_factory]
|
cli.add_command(get_command)
|
||||||
|
cli.add_command(set_command)
|
||||||
for factory in factories:
|
cli.add_command(create_command)
|
||||||
command_help = inspect.getdoc(factory)
|
cli.add_command(delete_command)
|
||||||
name = factory.__name__.replace("_factory", "")
|
|
||||||
|
|
||||||
@cli.command(cls=ModelCommand, factory=factory, name=name, help=command_help)
|
|
||||||
def factory_command(): ...
|
|
||||||
|
|
||||||
cli.add_command(reset_otp)
|
cli.add_command(reset_otp)
|
||||||
|
|
||||||
|
|
||||||
|
@ -115,15 +109,6 @@ def serialize(instance):
|
||||||
|
|
||||||
|
|
||||||
def get_factory(model):
|
def get_factory(model):
|
||||||
"""Read information about models.
|
|
||||||
|
|
||||||
Options can be used to filter models::
|
|
||||||
|
|
||||||
canaille get user --given-name John --last-name Doe
|
|
||||||
|
|
||||||
Displays the matching models in JSON format in the standard output.
|
|
||||||
"""
|
|
||||||
|
|
||||||
command_help = f"""Search for {model.__name__.lower()}s and display the
|
command_help = f"""Search for {model.__name__.lower()}s and display the
|
||||||
matching models as JSON."""
|
matching models as JSON."""
|
||||||
|
|
||||||
|
@ -145,16 +130,43 @@ def get_factory(model):
|
||||||
return command
|
return command
|
||||||
|
|
||||||
|
|
||||||
def set_factory(model):
|
@click.command(
|
||||||
"""Update models.
|
cls=ModelCommand, factory=get_factory, name="get", invoke_without_command=True
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--all",
|
||||||
|
is_flag=True,
|
||||||
|
show_default=True,
|
||||||
|
default=False,
|
||||||
|
help="Dump all the model instances",
|
||||||
|
)
|
||||||
|
@click.pass_context
|
||||||
|
def get_command(ctx, all: bool):
|
||||||
|
"""Read information about models.
|
||||||
|
|
||||||
The command takes an model ID and edit one or several attributes::
|
Options can be used to filter models::
|
||||||
|
|
||||||
canaille set user 229d112e-1bb5-452f-b2ac-f7680ffe7fb8 --given-name Jack
|
canaille get user --given-name John --last-name Doe
|
||||||
|
|
||||||
Displays the edited model in JSON format in the standard output.
|
Displays the matching models in JSON format in the standard output.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if not all and not ctx.invoked_subcommand:
|
||||||
|
click.echo(ctx.get_help())
|
||||||
|
ctx.exit(0)
|
||||||
|
|
||||||
|
if all:
|
||||||
|
objects = {}
|
||||||
|
for model_name, model in MODELS.items():
|
||||||
|
objects[model_name] = [
|
||||||
|
serialize(instance) for instance in Backend.instance.query(model)
|
||||||
|
]
|
||||||
|
|
||||||
|
output = json.dumps(objects)
|
||||||
|
click.echo(output)
|
||||||
|
|
||||||
|
|
||||||
|
def set_factory(model):
|
||||||
command_help = f"""Update a {model.__name__.lower()} and display the
|
command_help = f"""Update a {model.__name__.lower()} and display the
|
||||||
edited model in JSON format in the standard output.
|
edited model in JSON format in the standard output.
|
||||||
|
|
||||||
|
@ -204,16 +216,19 @@ def set_factory(model):
|
||||||
return command
|
return command
|
||||||
|
|
||||||
|
|
||||||
def create_factory(model):
|
@click.command(cls=ModelCommand, factory=set_factory, name="set")
|
||||||
"""Create models.
|
def set_command():
|
||||||
|
"""Update models.
|
||||||
|
|
||||||
The model attributes can be passed as command options::
|
The command takes an model ID and edit one or several attributes::
|
||||||
|
|
||||||
canaille create user --given-name John --last-name Doe
|
canaille set user 229d112e-1bb5-452f-b2ac-f7680ffe7fb8 --given-name Jack
|
||||||
|
|
||||||
Displays the created model in JSON format in the standard output.
|
Displays the edited model in JSON format in the standard output.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def create_factory(model):
|
||||||
command_help = f"""Create a new {model.__name__.lower()} and display the
|
command_help = f"""Create a new {model.__name__.lower()} and display the
|
||||||
created model in JSON format in the standard output.
|
created model in JSON format in the standard output.
|
||||||
"""
|
"""
|
||||||
|
@ -254,14 +269,19 @@ def create_factory(model):
|
||||||
return command
|
return command
|
||||||
|
|
||||||
|
|
||||||
def delete_factory(model):
|
@click.command(cls=ModelCommand, factory=create_factory, name="create")
|
||||||
"""Delete models.
|
def create_command():
|
||||||
|
"""Create models.
|
||||||
|
|
||||||
The command takes a model ID and deletes it::
|
The model attributes can be passed as command options::
|
||||||
|
|
||||||
canaille delete user --id 229d112e-1bb5-452f-b2ac-f7680ffe7fb8
|
canaille create user --given-name John --last-name Doe
|
||||||
|
|
||||||
|
Displays the created model in JSON format in the standard output.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def delete_factory(model):
|
||||||
command_help = f"""Delete a {model.__name__.lower()}.
|
command_help = f"""Delete a {model.__name__.lower()}.
|
||||||
|
|
||||||
IDENTIFIER should be a {model.__name__.lower()} id or
|
IDENTIFIER should be a {model.__name__.lower()} id or
|
||||||
|
@ -287,6 +307,16 @@ def delete_factory(model):
|
||||||
return command
|
return command
|
||||||
|
|
||||||
|
|
||||||
|
@click.command(cls=ModelCommand, factory=delete_factory, name="delete")
|
||||||
|
def delete_command():
|
||||||
|
"""Delete models.
|
||||||
|
|
||||||
|
The command takes a model ID and deletes it::
|
||||||
|
|
||||||
|
canaille delete user --id 229d112e-1bb5-452f-b2ac-f7680ffe7fb8
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@with_appcontext
|
@with_appcontext
|
||||||
@with_backendcontext
|
@with_backendcontext
|
||||||
|
|
|
@ -104,3 +104,51 @@ def test_get_datetime_filter(testclient, backend, user):
|
||||||
"user_name": "user",
|
"user_name": "user",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_all(testclient, backend, user, foo_group):
|
||||||
|
"""Test the full database dump command."""
|
||||||
|
|
||||||
|
runner = testclient.app.test_cli_runner()
|
||||||
|
res = runner.invoke(cli, ["get", "--all"])
|
||||||
|
assert res.exit_code == 0, res.stdout
|
||||||
|
assert json.loads(res.stdout) == {
|
||||||
|
"authorizationcode": [],
|
||||||
|
"client": [],
|
||||||
|
"consent": [],
|
||||||
|
"group": [
|
||||||
|
{
|
||||||
|
"created": mock.ANY,
|
||||||
|
"display_name": "foo",
|
||||||
|
"id": foo_group.id,
|
||||||
|
"last_modified": mock.ANY,
|
||||||
|
"members": [
|
||||||
|
user.id,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"token": [],
|
||||||
|
"user": [
|
||||||
|
{
|
||||||
|
"created": mock.ANY,
|
||||||
|
"display_name": "Johnny",
|
||||||
|
"emails": [
|
||||||
|
"john@doe.test",
|
||||||
|
],
|
||||||
|
"family_name": "Doe",
|
||||||
|
"formatted_address": "1235, somewhere",
|
||||||
|
"formatted_name": "John (johnny) Doe",
|
||||||
|
"given_name": "John",
|
||||||
|
"groups": [foo_group.id],
|
||||||
|
"id": user.id,
|
||||||
|
"last_modified": mock.ANY,
|
||||||
|
"password": "***",
|
||||||
|
"phone_numbers": [
|
||||||
|
"555-000-000",
|
||||||
|
],
|
||||||
|
"preferred_language": "en",
|
||||||
|
"profile_url": "https://john.test",
|
||||||
|
"user_name": "user",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue