diff --git a/backend/modules/user/controller/user_controller.py b/backend/modules/user/controller/user_controller.py index 716b5983d..c734b6ef0 100644 --- a/backend/modules/user/controller/user_controller.py +++ b/backend/modules/user/controller/user_controller.py @@ -79,6 +79,26 @@ def get_user_identity_route( """ return user_repository.get_user_identity(current_user.id) +@user_router.delete( + "/user_data", + dependencies=[Depends(AuthBearer())], + tags=["User"], +) +async def delete_user_data_route( + current_user: UserIdentity = Depends(get_current_user), +): + """ + Delete a user. + + - `user_id`: The ID of the user to delete. + + This endpoint deletes a user from the system. + """ + + user_repository.delete_user_data(current_user.id) + + return {"message": "User deleted successfully"} + @user_router.get( "/user/credits", dependencies=[Depends(AuthBearer())], diff --git a/backend/modules/user/repository/users.py b/backend/modules/user/repository/users.py index cdd181909..a65d3188e 100644 --- a/backend/modules/user/repository/users.py +++ b/backend/modules/user/repository/users.py @@ -76,6 +76,30 @@ class Users(UsersInterface): ).execute() return response.data[0]["email"] + def delete_user_data(self, user_id): + response = ( + self.db.from_("brains_users") + .select("brain_id") + .filter("rights", "eq", "Owner") + .filter("user_id", "eq", str(user_id)) + .execute() + ) + brain_ids = [row["brain_id"] for row in response.data] + + for brain_id in brain_ids: + self.db.table("brains").delete().filter("brain_id", "eq", brain_id).execute() + + for brain_id in brain_ids: + self.db.table("brains_vectors").delete().filter("brain_id", "eq", brain_id).execute() + + for brain_id in brain_ids: + self.db.table("chat_history").delete().filter("brain_id", "eq", brain_id).execute() + + self.db.table("user_settings").delete().filter("user_id", "eq", str(user_id)).execute() + self.db.table("user_identity").delete().filter("user_id", "eq", str(user_id)).execute() + self.db.table("users").delete().filter("id", "eq", str(user_id)).execute() + + def get_user_credits(self, user_id): user_usage_instance = user_usage.UserUsage(id=user_id) diff --git a/backend/modules/user/repository/users_interface.py b/backend/modules/user/repository/users_interface.py index a188b455b..5c0e2b47c 100644 --- a/backend/modules/user/repository/users_interface.py +++ b/backend/modules/user/repository/users_interface.py @@ -46,6 +46,15 @@ class UsersInterface(ABC): pass @abstractmethod + def delete_user_data(self, user_id: str): + """ + Delete a user. + + - `user_id`: The ID of the user to delete. + + This endpoint deletes a user from the system. + """ + @abstractmethod def get_user_credits(self, user_id: UUID) -> int: """ Get user remaining credits diff --git a/frontend/app/user/page.module.scss b/frontend/app/user/page.module.scss index b9b7f737c..84203a00f 100644 --- a/frontend/app/user/page.module.scss +++ b/frontend/app/user/page.module.scss @@ -7,3 +7,14 @@ flex-direction: column; gap: Spacings.$spacing05; } + +.modal_wrapper { + display: flex; + flex-direction: column; + gap: Spacings.$spacing05; + + .buttons { + display: flex; + justify-content: space-between; + } +} diff --git a/frontend/app/user/page.tsx b/frontend/app/user/page.tsx index 356b1dc64..ee2a802d0 100644 --- a/frontend/app/user/page.tsx +++ b/frontend/app/user/page.tsx @@ -1,7 +1,9 @@ "use client"; +import { useState } from "react"; import { useTranslation } from "react-i18next"; +import { useUserApi } from "@/lib/api/user/useUserApi"; import PageHeader from "@/lib/components/PageHeader/PageHeader"; import { Modal } from "@/lib/components/ui/Modal/Modal"; import QuivrButton from "@/lib/components/ui/QuivrButton/QuivrButton"; @@ -18,7 +20,10 @@ import { useLogoutModal } from "../../lib/hooks/useLogoutModal"; const UserPage = (): JSX.Element => { const { session } = useSupabase(); const { userData } = useUserData(); + const { deleteUserData } = useUserApi(); const { t } = useTranslation(["translation", "logout"]); + const [deleteAccountModalOpened, setDeleteAccountModalOpened] = + useState(false); const { handleLogout, isLoggingOut, @@ -26,14 +31,24 @@ const UserPage = (): JSX.Element => { setIsLogoutModalOpened, } = useLogoutModal(); - const button: ButtonType = { - label: "Logout", - color: "dangerous", - onClick: () => { - setIsLogoutModalOpened(true); + const buttons: ButtonType[] = [ + { + label: "Logout", + color: "dangerous", + onClick: () => { + setIsLogoutModalOpened(true); + }, + iconName: "logout", }, - iconName: "logout", - }; + { + label: "Delete Account", + color: "dangerous", + onClick: () => { + setDeleteAccountModalOpened(true); + }, + iconName: "delete", + }, + ]; if (!session || !userData) { redirectToLogin(); @@ -42,7 +57,7 @@ const UserPage = (): JSX.Element => { return ( <>