2022-08-01 10:40:40 +00:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
"""Users management module"""
|
|
|
|
# pylint: disable=too-few-public-methods
|
2024-11-15 00:19:24 +00:00
|
|
|
from typing import Optional
|
2022-08-01 10:40:40 +00:00
|
|
|
import strawberry
|
2024-10-26 18:22:31 +00:00
|
|
|
|
2022-08-01 10:40:40 +00:00
|
|
|
from selfprivacy_api.graphql import IsAuthenticated
|
|
|
|
from selfprivacy_api.graphql.common_types.user import (
|
|
|
|
UserMutationReturn,
|
|
|
|
get_user_by_username,
|
|
|
|
)
|
2023-06-21 03:46:56 +00:00
|
|
|
from selfprivacy_api.actions.ssh import (
|
|
|
|
InvalidPublicKey,
|
|
|
|
KeyAlreadyExists,
|
|
|
|
KeyNotFound,
|
2024-11-15 00:19:24 +00:00
|
|
|
create_ssh_key as create_ssh_key_action,
|
|
|
|
remove_ssh_key as remove_ssh_key_action,
|
2023-06-21 03:46:56 +00:00
|
|
|
)
|
2022-08-01 10:40:40 +00:00
|
|
|
from selfprivacy_api.graphql.mutations.mutation_interface import (
|
|
|
|
GenericMutationReturn,
|
|
|
|
)
|
2024-11-15 00:19:24 +00:00
|
|
|
from selfprivacy_api.actions.users import (
|
|
|
|
create_user as create_user_action,
|
|
|
|
delete_user as delete_user_action,
|
|
|
|
update_user as update_user_action,
|
2024-12-03 22:54:24 +00:00
|
|
|
generate_password_reset_link as generate_password_reset_link_action,
|
2024-11-15 00:19:24 +00:00
|
|
|
)
|
2024-10-26 18:22:31 +00:00
|
|
|
from selfprivacy_api.repositories.users.exceptions import (
|
|
|
|
PasswordIsEmpty,
|
|
|
|
UsernameForbidden,
|
|
|
|
InvalidConfiguration,
|
|
|
|
UserAlreadyExists,
|
|
|
|
UserIsProtected,
|
|
|
|
UsernameNotAlphanumeric,
|
|
|
|
UsernameTooLong,
|
|
|
|
UserNotFound,
|
2024-12-03 22:54:24 +00:00
|
|
|
SelfPrivacyAppIsOutdate,
|
2024-10-26 18:22:31 +00:00
|
|
|
)
|
2024-12-03 22:54:24 +00:00
|
|
|
from selfprivacy_api import PLEASE_UPDATE_APP_TEXT
|
2022-08-01 10:40:40 +00:00
|
|
|
|
|
|
|
|
2024-12-05 23:05:28 +00:00
|
|
|
FAILED_TO_SETUP_PASSWORD_TEXT = "Failed to set a password for a user. The problem occurred due to an old version of the SelfPrivacy app."
|
|
|
|
|
|
|
|
|
|
|
|
def return_failed_mutation_return(
|
|
|
|
error: str,
|
|
|
|
code: int = 400,
|
|
|
|
username: str = None,
|
|
|
|
) -> UserMutationReturn:
|
|
|
|
return UserMutationReturn(
|
|
|
|
success=False,
|
|
|
|
message=str(error),
|
|
|
|
code=code,
|
|
|
|
user=get_user_by_username(username) if username else None,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2022-08-01 10:40:40 +00:00
|
|
|
@strawberry.input
|
|
|
|
class UserMutationInput:
|
|
|
|
"""Input type for user mutation"""
|
|
|
|
|
|
|
|
username: str
|
2024-11-15 00:19:24 +00:00
|
|
|
password: Optional[str] = None
|
|
|
|
displayname: Optional[str] = None
|
|
|
|
email: Optional[str] = None
|
2024-12-03 22:54:24 +00:00
|
|
|
directmemberof: Optional[list[str]] = None
|
|
|
|
memberof: Optional[list[str]] = None
|
2022-08-01 10:40:40 +00:00
|
|
|
|
|
|
|
|
2023-06-21 03:46:56 +00:00
|
|
|
@strawberry.input
|
|
|
|
class SshMutationInput:
|
|
|
|
"""Input type for ssh mutation"""
|
|
|
|
|
|
|
|
username: str
|
|
|
|
ssh_key: str
|
|
|
|
|
|
|
|
|
2022-08-01 10:40:40 +00:00
|
|
|
@strawberry.type
|
2023-06-21 03:46:56 +00:00
|
|
|
class UsersMutations:
|
2022-08-01 10:40:40 +00:00
|
|
|
"""Mutations change user settings"""
|
|
|
|
|
|
|
|
@strawberry.mutation(permission_classes=[IsAuthenticated])
|
|
|
|
def create_user(self, user: UserMutationInput) -> UserMutationReturn:
|
2022-08-25 17:03:56 +00:00
|
|
|
try:
|
2024-11-15 00:19:24 +00:00
|
|
|
create_user_action(
|
|
|
|
username=user.username,
|
|
|
|
password=user.password,
|
|
|
|
displayname=user.displayname,
|
|
|
|
email=user.email,
|
|
|
|
directmemberof=user.directmemberof,
|
|
|
|
memberof=user.memberof,
|
|
|
|
)
|
2024-12-05 23:05:28 +00:00
|
|
|
except (
|
|
|
|
PasswordIsEmpty,
|
|
|
|
UsernameNotAlphanumeric,
|
|
|
|
UsernameTooLong,
|
|
|
|
InvalidConfiguration,
|
|
|
|
) as error:
|
|
|
|
return return_failed_mutation_return(
|
|
|
|
error=error,
|
|
|
|
message=error.get_description(),
|
|
|
|
)
|
|
|
|
except UsernameForbidden as error:
|
|
|
|
return return_failed_mutation_return(
|
|
|
|
message=error.get_error_message(),
|
2022-08-25 17:03:56 +00:00
|
|
|
code=409,
|
2024-12-05 23:05:28 +00:00
|
|
|
username=user.username,
|
2022-08-25 17:03:56 +00:00
|
|
|
)
|
2024-12-05 23:05:28 +00:00
|
|
|
except UserAlreadyExists as error:
|
|
|
|
return return_failed_mutation_return(
|
|
|
|
message=error.get_error_message(),
|
2022-08-25 17:03:56 +00:00
|
|
|
code=409,
|
2024-12-05 23:05:28 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
if user.password:
|
|
|
|
return return_failed_mutation_return(
|
|
|
|
message=f"{FAILED_TO_SETUP_PASSWORD_TEXT} {PLEASE_UPDATE_APP_TEXT}",
|
|
|
|
code=201,
|
|
|
|
username=user.username,
|
2022-08-25 17:03:56 +00:00
|
|
|
)
|
2022-08-01 10:40:40 +00:00
|
|
|
|
|
|
|
return UserMutationReturn(
|
2022-08-25 17:03:56 +00:00
|
|
|
success=True,
|
2024-12-05 23:05:28 +00:00
|
|
|
message="User created",
|
2022-08-25 17:03:56 +00:00
|
|
|
code=201,
|
2022-08-01 10:40:40 +00:00
|
|
|
user=get_user_by_username(user.username),
|
|
|
|
)
|
|
|
|
|
|
|
|
@strawberry.mutation(permission_classes=[IsAuthenticated])
|
|
|
|
def delete_user(self, username: str) -> GenericMutationReturn:
|
2022-08-25 17:03:56 +00:00
|
|
|
try:
|
2024-11-15 00:19:24 +00:00
|
|
|
delete_user_action(username)
|
2024-12-05 23:05:28 +00:00
|
|
|
except UserNotFound as error:
|
|
|
|
return return_failed_mutation_return(
|
|
|
|
message=error.get_error_message(),
|
2022-08-25 17:03:56 +00:00
|
|
|
code=404,
|
|
|
|
)
|
2024-12-05 23:05:28 +00:00
|
|
|
except UserIsProtected as error:
|
|
|
|
return return_failed_mutation_return(error=error)
|
2022-08-01 10:40:40 +00:00
|
|
|
|
|
|
|
return GenericMutationReturn(
|
2022-08-25 17:03:56 +00:00
|
|
|
success=True,
|
|
|
|
message="User deleted",
|
|
|
|
code=200,
|
2022-08-01 10:40:40 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
@strawberry.mutation(permission_classes=[IsAuthenticated])
|
|
|
|
def update_user(self, user: UserMutationInput) -> UserMutationReturn:
|
|
|
|
"""Update user mutation"""
|
2022-08-25 17:03:56 +00:00
|
|
|
try:
|
2024-11-15 00:19:24 +00:00
|
|
|
update_user_action(
|
|
|
|
username=user.username,
|
|
|
|
password=user.password,
|
|
|
|
displayname=user.displayname,
|
|
|
|
email=user.email,
|
|
|
|
directmemberof=user.directmemberof,
|
|
|
|
memberof=user.memberof,
|
|
|
|
)
|
2024-12-05 23:05:28 +00:00
|
|
|
except (PasswordIsEmpty, SelfPrivacyAppIsOutdate) as error:
|
|
|
|
return return_failed_mutation_return(
|
|
|
|
message=error.get_error_message(),
|
2022-08-25 17:03:56 +00:00
|
|
|
)
|
2024-12-05 23:05:28 +00:00
|
|
|
except UserNotFound as error:
|
|
|
|
return return_failed_mutation_return(
|
|
|
|
message=error.get_error_message(),
|
2022-08-25 17:03:56 +00:00
|
|
|
code=404,
|
|
|
|
)
|
2022-08-01 10:40:40 +00:00
|
|
|
|
|
|
|
return UserMutationReturn(
|
2022-08-25 17:03:56 +00:00
|
|
|
success=True,
|
|
|
|
message="User updated",
|
|
|
|
code=200,
|
2022-08-01 10:40:40 +00:00
|
|
|
user=get_user_by_username(user.username),
|
|
|
|
)
|
2023-06-21 03:46:56 +00:00
|
|
|
|
|
|
|
@strawberry.mutation(permission_classes=[IsAuthenticated])
|
|
|
|
def add_ssh_key(self, ssh_input: SshMutationInput) -> UserMutationReturn:
|
|
|
|
"""Add a new ssh key"""
|
|
|
|
|
|
|
|
try:
|
2024-11-15 00:19:24 +00:00
|
|
|
create_ssh_key_action(ssh_input.username, ssh_input.ssh_key)
|
2024-12-05 23:05:28 +00:00
|
|
|
except KeyAlreadyExists as error:
|
|
|
|
return return_failed_mutation_return(
|
|
|
|
message=error.get_error_message(),
|
2023-06-21 03:46:56 +00:00
|
|
|
code=409,
|
|
|
|
)
|
2024-12-05 23:05:28 +00:00
|
|
|
except InvalidPublicKey as error:
|
|
|
|
return return_failed_mutation_return(
|
|
|
|
message=error.get_error_message(),
|
2023-06-21 03:46:56 +00:00
|
|
|
)
|
2024-12-05 23:05:28 +00:00
|
|
|
except UserNotFound as error:
|
|
|
|
return return_failed_mutation_return(
|
|
|
|
message=error.get_error_message(),
|
2023-06-21 03:46:56 +00:00
|
|
|
code=404,
|
|
|
|
)
|
2024-12-05 23:05:28 +00:00
|
|
|
except Exception as error: # TODO why?
|
|
|
|
return return_failed_mutation_return(
|
|
|
|
message=str(error),
|
2023-06-21 03:46:56 +00:00
|
|
|
code=500,
|
|
|
|
)
|
|
|
|
|
|
|
|
return UserMutationReturn(
|
|
|
|
success=True,
|
|
|
|
message="New SSH key successfully written",
|
|
|
|
code=201,
|
|
|
|
user=get_user_by_username(ssh_input.username),
|
|
|
|
)
|
|
|
|
|
|
|
|
@strawberry.mutation(permission_classes=[IsAuthenticated])
|
|
|
|
def remove_ssh_key(self, ssh_input: SshMutationInput) -> UserMutationReturn:
|
|
|
|
"""Remove ssh key from user"""
|
|
|
|
|
|
|
|
try:
|
2024-11-15 00:19:24 +00:00
|
|
|
remove_ssh_key_action(ssh_input.username, ssh_input.ssh_key)
|
2024-12-05 23:05:28 +00:00
|
|
|
except (KeyNotFound, UserMutationReturn) as error:
|
|
|
|
return return_failed_mutation_return(
|
|
|
|
message=error.get_error_message(),
|
2023-06-21 03:46:56 +00:00
|
|
|
code=404,
|
|
|
|
)
|
2024-12-05 23:05:28 +00:00
|
|
|
except Exception as error: # TODO why?
|
2023-06-21 03:46:56 +00:00
|
|
|
return UserMutationReturn(
|
|
|
|
success=False,
|
2024-12-05 23:05:28 +00:00
|
|
|
message=str(error),
|
2023-06-21 03:46:56 +00:00
|
|
|
code=500,
|
|
|
|
)
|
|
|
|
|
|
|
|
return UserMutationReturn(
|
|
|
|
success=True,
|
|
|
|
message="SSH key successfully removed",
|
|
|
|
code=200,
|
|
|
|
user=get_user_by_username(ssh_input.username),
|
|
|
|
)
|
2024-12-03 22:54:24 +00:00
|
|
|
|
|
|
|
@strawberry.mutation(permission_classes=[IsAuthenticated])
|
|
|
|
def generate_password_reset_link(username: str) -> UserMutationReturn:
|
|
|
|
try:
|
|
|
|
password_reset_link = generate_password_reset_link_action(username=username)
|
2024-12-05 23:05:28 +00:00
|
|
|
except UserNotFound as error:
|
|
|
|
return return_failed_mutation_return(
|
|
|
|
message=error.get_error_message(),
|
2024-12-03 22:54:24 +00:00
|
|
|
code=404,
|
|
|
|
)
|
|
|
|
|
|
|
|
return UserMutationReturn(
|
|
|
|
success=True,
|
|
|
|
message="Link successfully created",
|
|
|
|
code=200,
|
|
|
|
password_reset_link=password_reset_link,
|
|
|
|
)
|