1
- from fastapi import APIRouter , Depends , HTTPException , Form
2
- from fastapi .responses import RedirectResponse
1
+ from fastapi import APIRouter , Depends , HTTPException , Form , UploadFile , File
2
+ from fastapi .responses import RedirectResponse , Response
3
3
from pydantic import BaseModel , EmailStr
4
- from sqlmodel import Session
4
+ from sqlmodel import Session , select
5
+ from typing import Optional
5
6
from utils .models import User
6
7
from utils .auth import get_session , get_authenticated_user , verify_password
7
8
@@ -15,16 +16,33 @@ class UpdateProfile(BaseModel):
15
16
"""Request model for updating user profile information"""
16
17
name : str
17
18
email : EmailStr
18
- avatar_url : str
19
+ avatar_url : Optional [str ] = None
20
+ avatar_file : Optional [bytes ] = None
21
+ avatar_content_type : Optional [str ] = None
19
22
20
23
@classmethod
21
24
async def as_form (
22
25
cls ,
23
26
name : str = Form (...),
24
27
email : EmailStr = Form (...),
25
- avatar_url : str = Form (...),
28
+ avatar_url : Optional [str ] = Form (None ),
29
+ avatar_file : Optional [UploadFile ] = File (None ),
26
30
):
27
- return cls (name = name , email = email , avatar_url = avatar_url )
31
+ avatar_data = None
32
+ avatar_content_type = None
33
+
34
+ if avatar_file :
35
+ # Read the file content
36
+ avatar_data = await avatar_file .read ()
37
+ avatar_content_type = avatar_file .content_type
38
+
39
+ return cls (
40
+ name = name ,
41
+ email = email ,
42
+ avatar_url = avatar_url if not avatar_file else None ,
43
+ avatar_file = avatar_data ,
44
+ avatar_content_type = avatar_content_type
45
+ )
28
46
29
47
30
48
class UserDeleteAccount (BaseModel ):
@@ -50,7 +68,17 @@ async def update_profile(
50
68
# Update user details
51
69
current_user .name = user_profile .name
52
70
current_user .email = user_profile .email
53
- current_user .avatar_url = user_profile .avatar_url
71
+
72
+ # Handle avatar update
73
+ if user_profile .avatar_file :
74
+ current_user .avatar_url = None
75
+ current_user .avatar_data = user_profile .avatar_file
76
+ current_user .avatar_content_type = user_profile .avatar_content_type
77
+ else :
78
+ current_user .avatar_url = user_profile .avatar_url
79
+ current_user .avatar_data = None
80
+ current_user .avatar_content_type = None
81
+
54
82
session .commit ()
55
83
session .refresh (current_user )
56
84
return RedirectResponse (url = "/profile" , status_code = 303 )
@@ -84,3 +112,24 @@ async def delete_account(
84
112
85
113
# Log out the user
86
114
return RedirectResponse (url = "/auth/logout" , status_code = 303 )
115
+
116
+
117
+ @router .get ("/avatar/{user_id}" )
118
+ async def get_avatar (
119
+ user_id : int ,
120
+ session : Session = Depends (get_session )
121
+ ):
122
+ """Serve avatar image from database"""
123
+ user = session .exec (select (User ).where (User .id == user_id )).first ()
124
+ if not user :
125
+ raise HTTPException (status_code = 404 , detail = "User not found" )
126
+
127
+ if user .avatar_data :
128
+ return Response (
129
+ content = user .avatar_data ,
130
+ media_type = user .avatar_content_type
131
+ )
132
+ elif user .avatar_url :
133
+ return RedirectResponse (url = user .avatar_url )
134
+ else :
135
+ raise HTTPException (status_code = 404 , detail = "Avatar not found" )
0 commit comments