fix: rename origin, add new mutation

This commit is contained in:
dettlaff 2024-12-04 02:54:24 +04:00
parent b662d0f243
commit ecb3f36f96
9 changed files with 85 additions and 40 deletions

View file

@ -0,0 +1 @@
PLEASE_UPDATE_APP_TEXT = "Your SelfPrivacy app is out of date, please update. Some important functions are not working at the moment."

View file

@ -121,3 +121,10 @@ def get_user_by_username(username: str) -> Optional[UserDataUser]:
pass pass
return user return user
def generate_password_reset_link(username: str) -> str:
if ACTIVE_USERS_PROVIDER == JsonUserRepository:
return "Error: API using old user manager provider!"
return ACTIVE_USERS_PROVIDER.generate_password_reset_link(username=username)

View file

@ -23,12 +23,13 @@ class UserType(Enum):
@strawberry.type @strawberry.type
class User: class User:
username: str username: str
user_type: UserType
ssh_keys: Optional[list[str]] = strawberry.field(default_factory=list)
user_type: Optional[UserType] = None
displayname: Optional[str] = None displayname: Optional[str] = None
ssh_keys: list[str] = strawberry.field(default_factory=list)
email: Optional[str] = None email: Optional[str] = None
directmemberof: Optional[list[str]] = strawberry.field(default_factory=list) directmemberof: Optional[list[str]] = None
memberof: Optional[list[str]] = strawberry.field(default_factory=list) memberof: Optional[list[str]] = None
# userHomeFolderspace: UserHomeFolderUsage # userHomeFolderspace: UserHomeFolderUsage
@ -37,6 +38,7 @@ class UserMutationReturn(MutationReturnInterface):
"""Return type for user mutation""" """Return type for user mutation"""
user: Optional[User] = None user: Optional[User] = None
password_reset_link: Optional[str] = None
def get_user_by_username(username: str) -> Optional[User]: def get_user_by_username(username: str) -> Optional[User]:
@ -45,13 +47,13 @@ def get_user_by_username(username: str) -> Optional[User]:
return None return None
return User( return User(
user_type=UserType(user.origin.value),
username=user.username, username=user.username,
ssh_keys=user.ssh_keys, ssh_keys=user.ssh_keys or [],
displayname=(user.displayname if user.displayname else user.username), user_type=user.user_type or None,
email=user.email, displayname=user.displayname or None,
directmemberof=user.directmemberof, email=user.email or None,
memberof=user.memberof, directmemberof=user.directmemberof or None,
memberof=user.memberof or None,
) )
@ -60,13 +62,13 @@ def get_users() -> list[User]:
users = actions_get_users(exclude_root=True) users = actions_get_users(exclude_root=True)
return [ return [
User( User(
user_type=UserType(user.origin.value),
username=user.username, username=user.username,
ssh_keys=user.ssh_keys, ssh_keys=user.ssh_keys or [],
displayname=(user.displayname if user.displayname else user.username), user_type=user.user_type or None,
email=user.email, displayname=user.displayname or None,
directmemberof=user.directmemberof, email=user.email or None,
memberof=user.memberof, directmemberof=user.directmemberof or None,
memberof=user.memberof or None,
) )
for user in users for user in users
] ]

View file

@ -23,6 +23,7 @@ from selfprivacy_api.actions.users import (
create_user as create_user_action, create_user as create_user_action,
delete_user as delete_user_action, delete_user as delete_user_action,
update_user as update_user_action, update_user as update_user_action,
generate_password_reset_link as generate_password_reset_link_action,
) )
from selfprivacy_api.repositories.users.exceptions import ( from selfprivacy_api.repositories.users.exceptions import (
PasswordIsEmpty, PasswordIsEmpty,
@ -33,7 +34,9 @@ from selfprivacy_api.repositories.users.exceptions import (
UsernameNotAlphanumeric, UsernameNotAlphanumeric,
UsernameTooLong, UsernameTooLong,
UserNotFound, UserNotFound,
SelfPrivacyAppIsOutdate,
) )
from selfprivacy_api import PLEASE_UPDATE_APP_TEXT
@strawberry.input @strawberry.input
@ -44,8 +47,8 @@ class UserMutationInput:
password: Optional[str] = None password: Optional[str] = None
displayname: Optional[str] = None displayname: Optional[str] = None
email: Optional[str] = None email: Optional[str] = None
directmemberof: Optional[list[str]] = strawberry.field(default_factory=list) directmemberof: Optional[list[str]] = None
memberof: Optional[list[str]] = strawberry.field(default_factory=list) memberof: Optional[list[str]] = None
@strawberry.input @strawberry.input
@ -111,7 +114,7 @@ class UsersMutations:
return UserMutationReturn( return UserMutationReturn(
success=True, success=True,
message="User created", message=PLEASE_UPDATE_APP_TEXT if user.password else "User created",
code=201, code=201,
user=get_user_by_username(user.username), user=get_user_by_username(user.username),
) )
@ -163,6 +166,12 @@ class UsersMutations:
message=str(e), message=str(e),
code=404, code=404,
) )
except SelfPrivacyAppIsOutdate:
return UserMutationReturn(
success=False,
message="Error: Failed to change password.", PLEASE_UPDATE_APP_TEXT,
code=400,
)
return UserMutationReturn( return UserMutationReturn(
success=True, success=True,
@ -195,7 +204,7 @@ class UsersMutations:
message="User not found", message="User not found",
code=404, code=404,
) )
except Exception as e: except Exception as e: # TODO why?
return UserMutationReturn( return UserMutationReturn(
success=False, success=False,
message=str(e), message=str(e),
@ -227,7 +236,7 @@ class UsersMutations:
message="User not found", message="User not found",
code=404, code=404,
) )
except Exception as e: except Exception as e: # TODO why?
return UserMutationReturn( return UserMutationReturn(
success=False, success=False,
message=str(e), message=str(e),
@ -240,3 +249,21 @@ class UsersMutations:
code=200, code=200,
user=get_user_by_username(ssh_input.username), user=get_user_by_username(ssh_input.username),
) )
@strawberry.mutation(permission_classes=[IsAuthenticated])
def generate_password_reset_link(username: str) -> UserMutationReturn:
try:
password_reset_link = generate_password_reset_link_action(username=username)
except UserNotFound:
return UserMutationReturn(
success=False,
message="User not found",
code=404,
)
return UserMutationReturn(
success=True,
message="Link successfully created",
code=200,
password_reset_link=password_reset_link,
)

View file

@ -15,12 +15,12 @@ class UserDataUser(BaseModel):
"""The user model from the userdata file""" """The user model from the userdata file"""
username: str username: str
origin: UserDataUserOrigin
ssh_keys: Optional[list[str]]
user_type: Optional[UserDataUserOrigin]
displayname: Optional[ displayname: Optional[
str str
] # in logic graphql will return "username" if "displayname" None ] # in logic graphql will return "username" if "displayname" None
email: Optional[str] email: Optional[str]
ssh_keys: Optional[list[str]]
directmemberof: Optional[list[str]] directmemberof: Optional[list[str]]
memberof: Optional[list[str]] memberof: Optional[list[str]]

View file

@ -28,3 +28,7 @@ class PasswordIsEmpty(Exception):
class InvalidConfiguration(Exception): class InvalidConfiguration(Exception):
"""The userdata is broken""" """The userdata is broken"""
class SelfPrivacyAppIsOutdate(Exception):
"""SelfPrivacy app is out of date, please update. Some important functions are not working at the moment."""

View file

@ -6,12 +6,15 @@ import re
import logging import logging
import json import json
from selfprivacy_api.repositories.users.exceptions import SelfPrivacyAppIsOutdate
from selfprivacy_api.utils import get_domain, temporary_env_var from selfprivacy_api.utils import get_domain, temporary_env_var
from selfprivacy_api.utils.redis_pool import RedisPool from selfprivacy_api.utils.redis_pool import RedisPool
from selfprivacy_api.models.user import UserDataUser, UserDataUserOrigin from selfprivacy_api.models.user import UserDataUser, UserDataUserOrigin
from selfprivacy_api.repositories.users.abstract_user_repository import ( from selfprivacy_api.repositories.users.abstract_user_repository import (
AbstractUserRepository, AbstractUserRepository,
) )
from selfprivacy_api import PLEASE_UPDATE_APP_TEXT
KANIDM_URL = "https://127.0.0.1:3013" KANIDM_URL = "https://127.0.0.1:3013"
@ -143,7 +146,7 @@ class KanidmUserRepository(AbstractUserRepository):
""" """
if password: if password:
pass # TODO make notif logger.error(PLEASE_UPDATE_APP_TEXT)
data = { data = {
"attrs": { "attrs": {
@ -175,27 +178,28 @@ class KanidmUserRepository(AbstractUserRepository):
The root user will never return. The root user will never return.
""" """
users_data = KanidmUserRepository._send_query(endpoint="person", method="GET") users_data = KanidmUserRepository._send_query(endpoint="person", method="GET")
users = [] users = []
for user in users_data: for user in users_data:
attrs = user.get("attrs", {}) user_attrs = user.get("attrs", {})
origin = KanidmUserRepository._check_user_origin_by_memberof( user_type = KanidmUserRepository._check_user_origin_by_memberof(
memberof=attrs.get("memberof", []) memberof=user_attrs.get("memberof", [])
) )
if exclude_primary and origin == UserDataUserOrigin.PRIMARY: if exclude_primary and user_type == UserDataUserOrigin.PRIMARY:
continue continue
user_type = UserDataUser( filled_user = UserDataUser(
username=attrs.get("name", [None])[0], username=user_attrs.get("name", [None])[0],
displayname=attrs.get("displayname", [None])[0], displayname=user_attrs.get("displayname", [None])[0],
email=attrs.get("mail", [None])[0], email=user_attrs.get("mail", [None])[0],
ssh_keys=[], # actions layer will full in this field ssh_keys=[], # actions layer will full in this field
origin=origin, user_type=user_type,
directmemberof=attrs.get("directmemberof", []), directmemberof=user_attrs.get("directmemberof", []),
memberof=attrs.get("memberof", []), memberof=user_attrs.get("memberof", []),
) )
users.append(user_type) users.append(filled_user)
return users return users
@staticmethod @staticmethod
@ -220,7 +224,7 @@ class KanidmUserRepository(AbstractUserRepository):
use generate_password_reset_link() instead. use generate_password_reset_link() instead.
""" """
if password: if password:
pass # TODO make notif raise SelfPrivacyAppIsOutdate
data = { data = {
"attrs": { "attrs": {
@ -259,7 +263,7 @@ class KanidmUserRepository(AbstractUserRepository):
displayname=attrs.get("displayname", [None])[0], displayname=attrs.get("displayname", [None])[0],
email=attrs.get("mail", [None])[0], email=attrs.get("mail", [None])[0],
ssh_keys=[], # actions layer will full in this field ssh_keys=[], # actions layer will full in this field
origin=KanidmUserRepository._check_user_origin_by_memberof( user_type=KanidmUserRepository._check_user_origin_by_memberof(
memberof=attrs.get("memberof", []) memberof=attrs.get("memberof", [])
), ),
directmemberof=attrs.get("directmemberof", []), directmemberof=attrs.get("directmemberof", []),

View file

@ -89,7 +89,7 @@ def no_admin_key(generic_userdata, authorized_client):
def admin_name() -> Optional[str]: def admin_name() -> Optional[str]:
users = get_users() users = get_users()
for user in users: for user in users:
if user.origin == UserDataUserOrigin.PRIMARY: if user.user_type == UserDataUserOrigin.PRIMARY:
return user.username return user.username
return None return None

View file

@ -73,7 +73,7 @@ def password_auth_spectrum(request):
def admin_name() -> Optional[str]: def admin_name() -> Optional[str]:
users = get_users() users = get_users()
for user in users: for user in users:
if user.origin == UserDataUserOrigin.PRIMARY: if user.user_type == UserDataUserOrigin.PRIMARY:
return user.username return user.username
return None return None