From b61bb779502b654e934e8055d34654f149bfca39 Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Thu, 28 Dec 2023 23:02:49 -0800 Subject: [PATCH 1/5] feat: delete user backend support --- backend/apps/web/models/users.py | 16 +++++++++++++++ backend/apps/web/routers/users.py | 33 +++++++++++++++++++++++++++++++ backend/constants.py | 2 ++ 3 files changed, 51 insertions(+) diff --git a/backend/apps/web/models/users.py b/backend/apps/web/models/users.py index 782b7f47..2768f20b 100644 --- a/backend/apps/web/models/users.py +++ b/backend/apps/web/models/users.py @@ -8,6 +8,8 @@ from utils.utils import decode_token from utils.misc import get_gravatar_url from apps.web.internal.db import DB +from apps.web.models.chats import Chat + #################### # User DB Schema @@ -110,5 +112,19 @@ class UsersTable: except: return None + def delete_user_by_id(self, id: str) -> bool: + try: + # Delete User Chats + query = Chat.delete().where(Chat.user_id == id) + query.execute() # Remove the rows, return number of rows removed. + + # Delete User + query = User.delete().where(User.id == id) + query.execute() # Remove the rows, return number of rows removed. + + return True + except: + return False + Users = UsersTable(DB) diff --git a/backend/apps/web/routers/users.py b/backend/apps/web/routers/users.py index 08437bd3..0206b7d7 100644 --- a/backend/apps/web/routers/users.py +++ b/backend/apps/web/routers/users.py @@ -73,3 +73,36 @@ async def update_user_role(form_data: UserRoleUpdateForm, cred=Depends(bearer_sc status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.INVALID_TOKEN, ) + + +############################ +# DeleteUser +############################ + + +@router.delete("/{user_id}", response_model=bool) +async def delete_user_by_id(user_id: str, cred=Depends(bearer_scheme)): + token = cred.credentials + user = Users.get_user_by_token(token) + + if user: + if user.role == "admin": + result = Users.delete_user_by_id(user_id) + + if result: + return True + else: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=ERROR_MESSAGES.DELETE_USER_ERROR, + ) + else: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=ERROR_MESSAGES.ACCESS_PROHIBITED, + ) + else: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=ERROR_MESSAGES.INVALID_TOKEN, + ) diff --git a/backend/constants.py b/backend/constants.py index 06d67eec..a068995d 100644 --- a/backend/constants.py +++ b/backend/constants.py @@ -12,6 +12,7 @@ class ERROR_MESSAGES(str, Enum): DEFAULT = lambda err="": f"Something went wrong :/\n{err if err else ''}" ENV_VAR_NOT_FOUND = "Required environment variable not found. Terminating now." CREATE_USER_ERROR = "Oops! Something went wrong while creating your account. Please try again later. If the issue persists, contact support for assistance." + DELETE_USER_ERROR = "Oops! Something went wrong. We encountered an issue while trying to delete the user. Please give it another shot." EMAIL_TAKEN = "Uh-oh! This email is already registered. Sign in with your existing account or choose another email to start anew." USERNAME_TAKEN = ( "Uh-oh! This username is already registered. Please choose another username." @@ -27,4 +28,5 @@ class ERROR_MESSAGES(str, Enum): ) NOT_FOUND = "We could not find what you're looking for :/" USER_NOT_FOUND = "We could not find what you're looking for :/" + MALICIOUS = "Unusual activities detected, please try again in a few minutes." From ad1cb5fc256b9ff1f3a2f008484a765fd8c139d4 Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Thu, 28 Dec 2023 23:07:46 -0800 Subject: [PATCH 2/5] fix: disable admin self user delete --- backend/apps/web/routers/users.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/backend/apps/web/routers/users.py b/backend/apps/web/routers/users.py index 0206b7d7..2b116828 100644 --- a/backend/apps/web/routers/users.py +++ b/backend/apps/web/routers/users.py @@ -87,14 +87,20 @@ async def delete_user_by_id(user_id: str, cred=Depends(bearer_scheme)): if user: if user.role == "admin": - result = Users.delete_user_by_id(user_id) + if user.id != user_id: + result = Users.delete_user_by_id(user_id) - if result: - return True + if result: + return True + else: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=ERROR_MESSAGES.DELETE_USER_ERROR, + ) else: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, - detail=ERROR_MESSAGES.DELETE_USER_ERROR, + detail=ERROR_MESSAGES.ACTION_PROHIBITED, ) else: raise HTTPException( From 7fade0bb2f308741a5207ba69ba09fc368a48547 Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Thu, 28 Dec 2023 23:12:58 -0800 Subject: [PATCH 3/5] feat: delete user button added to admin page --- src/lib/apis/users/index.ts | 32 ++++++++++++++++++-- src/routes/(app)/admin/+page.svelte | 45 ++++++++++++++++++++++++----- 2 files changed, 68 insertions(+), 9 deletions(-) diff --git a/src/lib/apis/users/index.ts b/src/lib/apis/users/index.ts index b1f9e5d9..3fca8b99 100644 --- a/src/lib/apis/users/index.ts +++ b/src/lib/apis/users/index.ts @@ -45,8 +45,9 @@ export const getUsers = async (token: string) => { if (!res.ok) throw await res.json(); return res.json(); }) - .catch((error) => { - console.log(error); + .catch((err) => { + console.log(err); + error = err.detail; return null; }); @@ -56,3 +57,30 @@ export const getUsers = async (token: string) => { return res ? res : []; }; + +export const deleteUserById = async (token: string, userId: string) => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/users/${userId}`, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}` + } + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + console.log(err); + error = err.detail; + return null; + }); + + if (error) { + throw error; + } + + return res; +}; diff --git a/src/routes/(app)/admin/+page.svelte b/src/routes/(app)/admin/+page.svelte index 13078b3c..5f5beeae 100644 --- a/src/routes/(app)/admin/+page.svelte +++ b/src/routes/(app)/admin/+page.svelte @@ -6,7 +6,7 @@ import toast from 'svelte-french-toast'; - import { updateUserRole, getUsers } from '$lib/apis/users'; + import { updateUserRole, getUsers, deleteUserById } from '$lib/apis/users'; let loaded = false; let users = []; @@ -22,6 +22,16 @@ } }; + const deleteUserHandler = async (id) => { + const res = await deleteUserById(localStorage.token, id).catch((error) => { + toast.error(error); + return null; + }); + if (res) { + users = await getUsers(localStorage.token); + } + }; + onMount(async () => { if ($user?.role !== 'admin') { await goto('/'); @@ -55,7 +65,7 @@ Name Email Role - + Action @@ -63,15 +73,16 @@
user -
{user.name}
+
{user.name}
{user.email} @@ -89,9 +100,29 @@ }}>{user.role} - + + + {/each} From 48cc2c5053f4a770a39eaf202aadf9a605696965 Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Thu, 28 Dec 2023 23:17:58 -0800 Subject: [PATCH 4/5] chore: delete user backend refac --- backend/apps/web/models/chats.py | 9 +++++++++ backend/apps/web/models/users.py | 14 ++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/backend/apps/web/models/chats.py b/backend/apps/web/models/chats.py index 8f075e40..ebc17d9a 100644 --- a/backend/apps/web/models/chats.py +++ b/backend/apps/web/models/chats.py @@ -153,5 +153,14 @@ class ChatTable: except: return False + def delete_chats_by_user_id(self, user_id: str) -> bool: + try: + query = Chat.delete().where(Chat.user_id == user_id) + query.execute() # Remove the rows, return number of rows removed. + + return True + except: + return False + Chats = ChatTable(DB) diff --git a/backend/apps/web/models/users.py b/backend/apps/web/models/users.py index 2768f20b..4b790ab2 100644 --- a/backend/apps/web/models/users.py +++ b/backend/apps/web/models/users.py @@ -115,14 +115,16 @@ class UsersTable: def delete_user_by_id(self, id: str) -> bool: try: # Delete User Chats - query = Chat.delete().where(Chat.user_id == id) - query.execute() # Remove the rows, return number of rows removed. + result = Chat.delete_chats_by_user_id(id) - # Delete User - query = User.delete().where(User.id == id) - query.execute() # Remove the rows, return number of rows removed. + if result: + # Delete User + query = User.delete().where(User.id == id) + query.execute() # Remove the rows, return number of rows removed. - return True + return True + else: + return False except: return False From 5b4bf45ad275faa9003275877e71af0575ee2117 Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Thu, 28 Dec 2023 23:24:51 -0800 Subject: [PATCH 5/5] fix: delete auth with user --- backend/apps/web/models/auths.py | 16 ++++++++++++++++ backend/apps/web/models/users.py | 4 ++-- backend/apps/web/routers/users.py | 6 ++++-- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/backend/apps/web/models/auths.py b/backend/apps/web/models/auths.py index c066dbef..1bd4b4cb 100644 --- a/backend/apps/web/models/auths.py +++ b/backend/apps/web/models/auths.py @@ -109,5 +109,21 @@ class AuthsTable: except: return None + def delete_auth_by_id(self, id: str) -> Optional[UserModel]: + try: + # Delete User + result = Users.delete_user_by_id(id) + + if result: + # Delete Auth + query = Auth.delete().where(Auth.id == id) + query.execute() # Remove the rows, return number of rows removed. + + return True + else: + return False + except: + return False + Auths = AuthsTable(DB) diff --git a/backend/apps/web/models/users.py b/backend/apps/web/models/users.py index 4b790ab2..b7df92eb 100644 --- a/backend/apps/web/models/users.py +++ b/backend/apps/web/models/users.py @@ -8,7 +8,7 @@ from utils.utils import decode_token from utils.misc import get_gravatar_url from apps.web.internal.db import DB -from apps.web.models.chats import Chat +from apps.web.models.chats import Chats #################### @@ -115,7 +115,7 @@ class UsersTable: def delete_user_by_id(self, id: str) -> bool: try: # Delete User Chats - result = Chat.delete_chats_by_user_id(id) + result = Chats.delete_chats_by_user_id(id) if result: # Delete User diff --git a/backend/apps/web/routers/users.py b/backend/apps/web/routers/users.py index 2b116828..fd0d2d6f 100644 --- a/backend/apps/web/routers/users.py +++ b/backend/apps/web/routers/users.py @@ -9,6 +9,8 @@ import time import uuid from apps.web.models.users import UserModel, UserRoleUpdateForm, Users +from apps.web.models.auths import Auths + from utils.utils import ( get_password_hash, @@ -76,7 +78,7 @@ async def update_user_role(form_data: UserRoleUpdateForm, cred=Depends(bearer_sc ############################ -# DeleteUser +# DeleteUserById ############################ @@ -88,7 +90,7 @@ async def delete_user_by_id(user_id: str, cred=Depends(bearer_scheme)): if user: if user.role == "admin": if user.id != user_id: - result = Users.delete_user_by_id(user_id) + result = Auths.delete_auth_by_id(user_id) if result: return True