diff --git a/backend/apps/web/models/auths.py b/backend/apps/web/models/auths.py index 00c66a2c..367db3ff 100644 --- a/backend/apps/web/models/auths.py +++ b/backend/apps/web/models/auths.py @@ -63,6 +63,15 @@ class SigninForm(BaseModel): password: str +class ProfileImageUrlForm(BaseModel): + profile_image_url: str + + +class UpdateProfileForm(BaseModel): + profile_image_url: str + name: str + + class UpdatePasswordForm(BaseModel): password: str new_password: str diff --git a/backend/apps/web/models/users.py b/backend/apps/web/models/users.py index f86697f4..c6d8b38d 100644 --- a/backend/apps/web/models/users.py +++ b/backend/apps/web/models/users.py @@ -65,7 +65,7 @@ class UsersTable: "name": name, "email": email, "role": role, - "profile_image_url": get_gravatar_url(email), + "profile_image_url": "/user.png", "timestamp": int(time.time()), } ) @@ -108,6 +108,20 @@ class UsersTable: except: return None + def update_user_profile_image_url_by_id( + self, id: str, profile_image_url: str + ) -> Optional[UserModel]: + try: + query = User.update(profile_image_url=profile_image_url).where( + User.id == id + ) + query.execute() + + user = User.get(User.id == id) + return UserModel(**model_to_dict(user)) + except: + return None + def update_user_by_id(self, id: str, updated: dict) -> Optional[UserModel]: try: query = User.update(**updated).where(User.id == id) diff --git a/backend/apps/web/routers/auths.py b/backend/apps/web/routers/auths.py index a0772223..f45c67ac 100644 --- a/backend/apps/web/routers/auths.py +++ b/backend/apps/web/routers/auths.py @@ -11,6 +11,7 @@ import uuid from apps.web.models.auths import ( SigninForm, SignupForm, + UpdateProfileForm, UpdatePasswordForm, UserResponse, SigninResponse, @@ -40,14 +41,37 @@ async def get_session_user(user=Depends(get_current_user)): } +############################ +# Update Profile +############################ + + +@router.post("/update/profile", response_model=UserResponse) +async def update_profile( + form_data: UpdateProfileForm, session_user=Depends(get_current_user) +): + if session_user: + user = Users.update_user_by_id( + session_user.id, + {"profile_image_url": form_data.profile_image_url, "name": form_data.name}, + ) + if user: + return user + else: + raise HTTPException(400, detail=ERROR_MESSAGES.DEFAULT()) + else: + raise HTTPException(400, detail=ERROR_MESSAGES.INVALID_CRED) + + ############################ # Update Password ############################ @router.post("/update/password", response_model=bool) -async def update_password(form_data: UpdatePasswordForm, - session_user=Depends(get_current_user)): +async def update_password( + form_data: UpdatePasswordForm, session_user=Depends(get_current_user) +): if session_user: user = Auths.authenticate_user(session_user.email, form_data.password) @@ -93,18 +117,19 @@ async def signin(form_data: SigninForm): async def signup(request: Request, form_data: SignupForm): if not request.app.state.ENABLE_SIGNUP: raise HTTPException(400, detail=ERROR_MESSAGES.ACCESS_PROHIBITED) - + if not validate_email_format(form_data.email.lower()): raise HTTPException(400, detail=ERROR_MESSAGES.INVALID_EMAIL_FORMAT) - + if Users.get_user_by_email(form_data.email.lower()): raise HTTPException(400, detail=ERROR_MESSAGES.EMAIL_TAKEN) - + try: role = "admin" if Users.get_num_users() == 0 else "pending" hashed = get_password_hash(form_data.password) - user = Auths.insert_new_auth(form_data.email.lower(), - hashed, form_data.name, role) + user = Auths.insert_new_auth( + form_data.email.lower(), hashed, form_data.name, role + ) if user: token = create_token(data={"email": user.email}) @@ -120,11 +145,10 @@ async def signup(request: Request, form_data: SignupForm): "profile_image_url": user.profile_image_url, } else: - raise HTTPException( - 500, detail=ERROR_MESSAGES.CREATE_USER_ERROR) + raise HTTPException(500, detail=ERROR_MESSAGES.CREATE_USER_ERROR) except Exception as err: - raise HTTPException(500, - detail=ERROR_MESSAGES.DEFAULT(err)) + raise HTTPException(500, detail=ERROR_MESSAGES.DEFAULT(err)) + ############################ # ToggleSignUp diff --git a/backend/apps/web/routers/utils.py b/backend/apps/web/routers/utils.py index 9adf2801..86e1a9e5 100644 --- a/backend/apps/web/routers/utils.py +++ b/backend/apps/web/routers/utils.py @@ -9,7 +9,7 @@ import os import aiohttp import json -from utils.misc import calculate_sha256 +from utils.misc import calculate_sha256, get_gravatar_url from config import OLLAMA_API_BASE_URL, DATA_DIR, UPLOAD_DIR from constants import ERROR_MESSAGES @@ -165,3 +165,10 @@ def upload(file: UploadFile = File(...)): yield f"data: {json.dumps(res)}\n\n" return StreamingResponse(file_process_stream(), media_type="text/event-stream") + + +@router.get("/gravatar") +async def get_gravatar( + email: str, +): + return get_gravatar_url(email) diff --git a/src/lib/apis/auths/index.ts b/src/lib/apis/auths/index.ts index 8734a588..5f16f83f 100644 --- a/src/lib/apis/auths/index.ts +++ b/src/lib/apis/auths/index.ts @@ -89,6 +89,37 @@ export const userSignUp = async (name: string, email: string, password: string) return res; }; +export const updateUserProfile = async (token: string, name: string, profileImageUrl: string) => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/auths/update/profile`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + ...(token && { authorization: `Bearer ${token}` }) + }, + body: JSON.stringify({ + name: name, + profile_image_url: profileImageUrl + }) + }) + .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; +}; + export const updateUserPassword = async (token: string, password: string, newPassword: string) => { let error = null; diff --git a/src/lib/apis/utils/index.ts b/src/lib/apis/utils/index.ts new file mode 100644 index 00000000..ed4d4e02 --- /dev/null +++ b/src/lib/apis/utils/index.ts @@ -0,0 +1,23 @@ +import { WEBUI_API_BASE_URL } from '$lib/constants'; + +export const getGravatarUrl = async (email: string) => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/utils/gravatar?email=${email}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + console.log(err); + error = err; + return null; + }); + + return res; +}; diff --git a/src/lib/components/chat/Settings/Account.svelte b/src/lib/components/chat/Settings/Account.svelte new file mode 100644 index 00000000..e4ae634c --- /dev/null +++ b/src/lib/components/chat/Settings/Account.svelte @@ -0,0 +1,179 @@ + + +