diff --git a/client/app/factory/edit/page.tsx b/client/app/factory/edit/page.tsx index 5b7c2422..acfe9ff4 100644 --- a/client/app/factory/edit/page.tsx +++ b/client/app/factory/edit/page.tsx @@ -26,7 +26,7 @@ import { useBotCreate, useBotEdit, } from '@/app/hooks/useBot'; -import { useAgreement } from '@/app/hooks/useAgreement'; +import { useAgreement, useAgreementStatus } from '@/app/hooks/useAgreement'; import FullPageSkeleton from '@/components/FullPageSkeleton'; import { isEmpty } from 'lodash'; import { Chat } from '@petercatai/assistant'; @@ -64,6 +64,11 @@ export default function Edit() { const { language } = useGlobal(); const { botProfile, setBotProfile } = useBot(); const { user, status } = useUser(); + const { + data: agreementStatus, + isLoading: getAgreementStatusLoading, + error: getAgreementStatusError, + } = useAgreementStatus(); const router = useRouter(); const searchParams = useSearchParams(); const id = searchParams.get('id'); @@ -103,15 +108,21 @@ export default function Edit() { } if (!user || user.id.startsWith('client|')) { router.push(`${apiDomain}/api/auth/login`); - } else { - if (!user?.agreement_accepted) { - setAgreementModalIsOpen(true); - } else { - setAgreementModalIsOpen(false); - } } }, [user, status]); + useEffect(() => { + if (getAgreementStatusLoading) { + return; + } + if (getAgreementStatusError) { + setAgreementModalIsOpen(true); + } else { + const agreementAccepted = agreementStatus?.data?.agreement_accepted; + setAgreementModalIsOpen(!agreementAccepted); + } + }, [agreementStatus, getAgreementStatusError, getAgreementStatusLoading]); + const { updateBot: onUpdateBot, isLoading: updateBotLoading, diff --git a/client/app/hooks/useAgreement.ts b/client/app/hooks/useAgreement.ts index 9a56cf2f..d5e91f70 100644 --- a/client/app/hooks/useAgreement.ts +++ b/client/app/hooks/useAgreement.ts @@ -1,5 +1,8 @@ -import { useMutation } from '@tanstack/react-query'; -import { acceptAgreement } from '@/app/services/UserController'; +import { useMutation, useQuery } from '@tanstack/react-query'; +import { + acceptAgreement, + getAgreementStatus, +} from '@/app/services/UserController'; export function useAgreement() { const mutation = useMutation({ mutationFn: acceptAgreement, @@ -13,3 +16,11 @@ export function useAgreement() { isSuccess: mutation.isSuccess, }; } + +export const useAgreementStatus = () => { + return useQuery({ + queryKey: [`agreement`], + queryFn: async () => getAgreementStatus(), + retry: false, + }); +}; diff --git a/client/app/services/UserController.ts b/client/app/services/UserController.ts index 345808d0..a5946f63 100644 --- a/client/app/services/UserController.ts +++ b/client/app/services/UserController.ts @@ -20,6 +20,13 @@ export async function acceptAgreement() { return response.data; } +export async function getAgreementStatus() { + const response = await axios.get(`${apiDomain}/api/auth/agreement/status`, { + withCredentials: true, + }); + return response.data; +} + export async function getAvailableLLMs() { const response = await axios.get(`${apiDomain}/api/user/llms`, { withCredentials: true, diff --git a/server/auth/router.py b/server/auth/router.py index bb6d4f8d..bb8a2ca4 100644 --- a/server/auth/router.py +++ b/server/auth/router.py @@ -1,10 +1,11 @@ +from core.dao.profilesDAO import ProfilesDAO from fastapi import APIRouter, Request, HTTPException, status, Depends from fastapi.responses import RedirectResponse, JSONResponse import secrets from petercat_utils import get_client, get_env_variable from starlette.config import Config from authlib.integrations.starlette_client import OAuth -from typing import Annotated +from typing import Annotated, Optional from auth.get_user_info import generateAnonymousUser, getUserInfoByToken, get_user_id @@ -98,33 +99,33 @@ async def userinfo(request: Request): return { "data": data, "status": 200} return { "data": user, "status": 200} +@router.get("/agreement/status") +async def get_agreement_status(user_id: Optional[str] = Depends(get_user_id)): + if not user_id: + raise HTTPException(status_code=401, detail="User not found") + try: + profiles_dao = ProfilesDAO() + response = profiles_dao.get_agreement_status(user_id=user_id) + if not response: + raise HTTPException(status_code=404, detail="User does not exist, accept failed.") + return {"success": True, "data": response} + except Exception as e: + raise HTTPException(status_code=500, detail=f"An error occurred: {str(e)}") + @router.post("/accept/agreement", status_code=200) async def bot_generator( request: Request, user_id: Annotated[str | None, Depends(get_user_id)] = None, ): if not user_id: - return JSONResponse( - content={ - "success": False, - "errorMessage": "User not found", - }, - status_code=401, - ) + raise HTTPException(status_code=401, detail="User not found") try: - supabase = get_client() - response = supabase.table("profiles").update({"agreement_accepted": True}).match({"id": user_id}).execute() - - if not response.data: - return JSONResponse( - content={ - "success": False, - "errorMessage": "User does not exist, accept failed.", - } - ) - request.session['user'] = response.data[0] - return JSONResponse(content={"success": True}) + profiles_dao = ProfilesDAO() + response = profiles_dao.accept_agreement(user_id=user_id) + if response: + request.session['user'] = response + return JSONResponse(content={"success": True}) + else: + raise HTTPException(status_code=400, detail="User update failed") except Exception as e: - return JSONResponse( - content={"success": False, "errorMessage": str(e)}, status_code=500 - ) + raise HTTPException(status_code=500, detail=f"An error occurred: {str(e)}") diff --git a/server/core/dao/profilesDAO.py b/server/core/dao/profilesDAO.py new file mode 100644 index 00000000..0983dd5d --- /dev/null +++ b/server/core/dao/profilesDAO.py @@ -0,0 +1,33 @@ +from core.dao.BaseDAO import BaseDAO +from supabase.client import Client + +from core.models.profiles import Profiles +from petercat_utils.db.client.supabase import get_client + +class ProfilesDAO(BaseDAO): + client: Client + + def __init__(self): + super().__init__() + self.client = get_client() + + def get_agreement_status(self, user_id: str): + + resp = self.client.table("profiles")\ + .select("agreement_accepted") \ + .eq("id", user_id) \ + .execute() + agreement_accepted = resp.data[0] + return agreement_accepted + + def accept_agreement(self, user_id: str): + try: + response = self.client.table("profiles").update({"agreement_accepted": True}).match({"id": user_id}).execute() + + if not response.data: + return False, {"message": "User does not exist, accept failed."} + return response.data[0] + except Exception as e: + print("Error: ", e) + return False, {"message": "Profile Update failed"} + \ No newline at end of file diff --git a/server/core/models/profiles.py b/server/core/models/profiles.py new file mode 100644 index 00000000..2b6d686b --- /dev/null +++ b/server/core/models/profiles.py @@ -0,0 +1,13 @@ +from pydantic import BaseModel +from datetime import datetime +from typing import Optional + +class Profiles(BaseModel): + id: str + created_at: datetime = datetime.now() + nickname: Optional[str] = "" + name: Optional[str] = "" + picture: Optional[str] = "" + sid: Optional[str] = "" + sub: Optional[str] = "" + agreement_accepted: Optional[bool] = False diff --git a/server/github_app/router.py b/server/github_app/router.py index c2e0211d..411bb676 100644 --- a/server/github_app/router.py +++ b/server/github_app/router.py @@ -28,7 +28,6 @@ get_installation_repositories, get_jwt, get_private_key, - get_user_orgs, ) from petercat_utils import get_env_variable