Server CLI: user management
This commit is contained in:
parent
900fabae79
commit
654d206033
13 changed files with 700 additions and 1 deletions
0
api/tests/cli/__init__.py
Normal file
0
api/tests/cli/__init__.py
Normal file
118
api/tests/cli/test_main.py
Normal file
118
api/tests/cli/test_main.py
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
import pytest
|
||||
|
||||
from click.testing import CliRunner
|
||||
|
||||
from funkwhale_api.cli import main
|
||||
from funkwhale_api.cli import users
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"cmd, args, handlers",
|
||||
[
|
||||
(
|
||||
("users", "create"),
|
||||
(
|
||||
"--username",
|
||||
"testuser",
|
||||
"--password",
|
||||
"testpassword",
|
||||
"--email",
|
||||
"test@hello.com",
|
||||
"--upload-quota",
|
||||
"35",
|
||||
"--permission",
|
||||
"library",
|
||||
"--permission",
|
||||
"moderation",
|
||||
"--staff",
|
||||
"--superuser",
|
||||
),
|
||||
[
|
||||
(
|
||||
users,
|
||||
"handler_create_user",
|
||||
{
|
||||
"username": "testuser",
|
||||
"password": "testpassword",
|
||||
"email": "test@hello.com",
|
||||
"upload_quota": 35,
|
||||
"permissions": ("library", "moderation"),
|
||||
"is_staff": True,
|
||||
"is_superuser": True,
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
(
|
||||
("users", "rm"),
|
||||
("testuser1", "testuser2", "--no-input"),
|
||||
[
|
||||
(
|
||||
users,
|
||||
"handler_delete_user",
|
||||
{"usernames": ("testuser1", "testuser2"), "soft": True},
|
||||
)
|
||||
],
|
||||
),
|
||||
(
|
||||
("users", "rm"),
|
||||
("testuser1", "testuser2", "--no-input", "--hard",),
|
||||
[
|
||||
(
|
||||
users,
|
||||
"handler_delete_user",
|
||||
{"usernames": ("testuser1", "testuser2"), "soft": False},
|
||||
)
|
||||
],
|
||||
),
|
||||
(
|
||||
("users", "set"),
|
||||
(
|
||||
"testuser1",
|
||||
"testuser2",
|
||||
"--no-input",
|
||||
"--inactive",
|
||||
"--upload-quota",
|
||||
"35",
|
||||
"--no-staff",
|
||||
"--superuser",
|
||||
"--permission-library",
|
||||
"--no-permission-moderation",
|
||||
"--no-permission-settings",
|
||||
"--password",
|
||||
"newpassword",
|
||||
),
|
||||
[
|
||||
(
|
||||
users,
|
||||
"handler_update_user",
|
||||
{
|
||||
"usernames": ("testuser1", "testuser2"),
|
||||
"kwargs": {
|
||||
"is_active": False,
|
||||
"upload_quota": 35,
|
||||
"is_staff": False,
|
||||
"is_superuser": True,
|
||||
"permission_library": True,
|
||||
"permission_moderation": False,
|
||||
"permission_settings": False,
|
||||
"password": "newpassword",
|
||||
},
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_cli(cmd, args, handlers, mocker):
|
||||
patched_handlers = {}
|
||||
for module, path, _ in handlers:
|
||||
patched_handlers[(module, path)] = mocker.spy(module, path)
|
||||
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main.base.cli, cmd + args)
|
||||
|
||||
assert result.exit_code == 0, result.output
|
||||
|
||||
for module, path, expected_call in handlers:
|
||||
patched_handlers[(module, path)].assert_called_once_with(**expected_call)
|
||||
147
api/tests/cli/test_users.py
Normal file
147
api/tests/cli/test_users.py
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
import pytest
|
||||
|
||||
from funkwhale_api.cli import users
|
||||
|
||||
|
||||
def test_user_create_handler(factories, mocker, now):
|
||||
kwargs = {
|
||||
"username": "helloworld",
|
||||
"password": "securepassword",
|
||||
"is_superuser": False,
|
||||
"is_staff": True,
|
||||
"email": "hello@world.email",
|
||||
"upload_quota": 35,
|
||||
"permissions": ["moderation"],
|
||||
}
|
||||
set_password = mocker.spy(users.models.User, "set_password")
|
||||
create_actor = mocker.spy(users.models, "create_actor")
|
||||
user = users.handler_create_user(**kwargs)
|
||||
|
||||
assert user.username == kwargs["username"]
|
||||
assert user.is_superuser == kwargs["is_superuser"]
|
||||
assert user.is_staff == kwargs["is_staff"]
|
||||
assert user.date_joined >= now
|
||||
assert user.upload_quota == kwargs["upload_quota"]
|
||||
set_password.assert_called_once_with(user, kwargs["password"])
|
||||
create_actor.assert_called_once_with(user)
|
||||
|
||||
expected_permissions = {
|
||||
p: p in kwargs["permissions"] for p in users.models.PERMISSIONS
|
||||
}
|
||||
|
||||
assert user.all_permissions == expected_permissions
|
||||
|
||||
|
||||
def test_user_delete_handler_soft(factories, mocker, now):
|
||||
user1 = factories["federation.Actor"](local=True).user
|
||||
actor1 = user1.actor
|
||||
user2 = factories["federation.Actor"](local=True).user
|
||||
actor2 = user2.actor
|
||||
user3 = factories["federation.Actor"](local=True).user
|
||||
delete_account = mocker.spy(users.tasks, "delete_account")
|
||||
users.handler_delete_user([user1.username, user2.username, "unknown"])
|
||||
|
||||
assert delete_account.call_count == 2
|
||||
delete_account.assert_any_call(user_id=user1.pk)
|
||||
with pytest.raises(user1.DoesNotExist):
|
||||
user1.refresh_from_db()
|
||||
|
||||
delete_account.assert_any_call(user_id=user2.pk)
|
||||
with pytest.raises(user2.DoesNotExist):
|
||||
user2.refresh_from_db()
|
||||
|
||||
# soft delete, actor shouldn't be deleted
|
||||
actor1.refresh_from_db()
|
||||
actor2.refresh_from_db()
|
||||
|
||||
# not deleted
|
||||
user3.refresh_from_db()
|
||||
|
||||
|
||||
def test_user_delete_handler_hard(factories, mocker, now):
|
||||
user1 = factories["federation.Actor"](local=True).user
|
||||
actor1 = user1.actor
|
||||
user2 = factories["federation.Actor"](local=True).user
|
||||
actor2 = user2.actor
|
||||
user3 = factories["federation.Actor"](local=True).user
|
||||
delete_account = mocker.spy(users.tasks, "delete_account")
|
||||
users.handler_delete_user([user1.username, user2.username, "unknown"], soft=False)
|
||||
|
||||
assert delete_account.call_count == 2
|
||||
delete_account.assert_any_call(user_id=user1.pk)
|
||||
with pytest.raises(user1.DoesNotExist):
|
||||
user1.refresh_from_db()
|
||||
|
||||
delete_account.assert_any_call(user_id=user2.pk)
|
||||
with pytest.raises(user2.DoesNotExist):
|
||||
user2.refresh_from_db()
|
||||
|
||||
# hard delete, actors are deleted as well
|
||||
with pytest.raises(actor1.DoesNotExist):
|
||||
actor1.refresh_from_db()
|
||||
|
||||
with pytest.raises(actor2.DoesNotExist):
|
||||
actor2.refresh_from_db()
|
||||
|
||||
# not deleted
|
||||
user3.refresh_from_db()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params, expected",
|
||||
[
|
||||
({"is_active": False}, {"is_active": False}),
|
||||
(
|
||||
{"is_staff": True, "is_superuser": True},
|
||||
{"is_staff": True, "is_superuser": True},
|
||||
),
|
||||
({"upload_quota": 35}, {"upload_quota": 35}),
|
||||
(
|
||||
{
|
||||
"permission_library": True,
|
||||
"permission_moderation": True,
|
||||
"permission_settings": True,
|
||||
},
|
||||
{
|
||||
"all_permissions": {
|
||||
"library": True,
|
||||
"moderation": True,
|
||||
"settings": True,
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_user_update_handler(params, expected, factories):
|
||||
user1 = factories["federation.Actor"](local=True).user
|
||||
user2 = factories["federation.Actor"](local=True).user
|
||||
user3 = factories["federation.Actor"](local=True).user
|
||||
|
||||
def get_field_values(user):
|
||||
return {f: getattr(user, f) for f, v in expected.items()}
|
||||
|
||||
unchanged = get_field_values(user3)
|
||||
|
||||
users.handler_update_user([user1.username, user2.username, "unknown"], params)
|
||||
|
||||
user1.refresh_from_db()
|
||||
user2.refresh_from_db()
|
||||
user3.refresh_from_db()
|
||||
|
||||
assert get_field_values(user1) == expected
|
||||
assert get_field_values(user2) == expected
|
||||
assert get_field_values(user3) == unchanged
|
||||
|
||||
|
||||
def test_user_update_handler_password(factories, mocker):
|
||||
user = factories["federation.Actor"](local=True).user
|
||||
current_password = user.password
|
||||
|
||||
set_password = mocker.spy(users.models.User, "set_password")
|
||||
|
||||
users.handler_update_user([user.username], {"password": "hello"})
|
||||
|
||||
user.refresh_from_db()
|
||||
|
||||
set_password.assert_called_once_with(user, "hello")
|
||||
assert user.password != current_password
|
||||
Loading…
Add table
Add a link
Reference in a new issue