1
- from fastapi import APIRouter , Depends , HTTPException , Form , UploadFile , File
1
+ from fastapi import APIRouter , Depends , Form , UploadFile , File
2
2
from fastapi .responses import RedirectResponse , Response
3
3
from pydantic import BaseModel , EmailStr
4
- from sqlmodel import Session , select
4
+ from sqlmodel import Session
5
5
from typing import Optional
6
- from utils .models import User
7
- from utils .auth import get_session , get_authenticated_user , verify_password
6
+ from utils .models import User , DataIntegrityError
7
+ from utils .auth import get_session , get_authenticated_user , verify_password , PasswordValidationError
8
8
9
9
router = APIRouter (prefix = "/user" , tags = ["user" ])
10
10
@@ -16,7 +16,6 @@ class UpdateProfile(BaseModel):
16
16
"""Request model for updating user profile information"""
17
17
name : str
18
18
email : EmailStr
19
- avatar_url : Optional [str ] = None
20
19
avatar_file : Optional [bytes ] = None
21
20
avatar_content_type : Optional [str ] = None
22
21
@@ -25,21 +24,18 @@ async def as_form(
25
24
cls ,
26
25
name : str = Form (...),
27
26
email : EmailStr = Form (...),
28
- avatar_url : Optional [str ] = Form (None ),
29
27
avatar_file : Optional [UploadFile ] = File (None ),
30
28
):
31
29
avatar_data = None
32
30
avatar_content_type = None
33
31
34
32
if avatar_file :
35
- # Read the file content
36
33
avatar_data = await avatar_file .read ()
37
34
avatar_content_type = avatar_file .content_type
38
35
39
36
return cls (
40
37
name = name ,
41
38
email = email ,
42
- avatar_url = avatar_url if not avatar_file else None ,
43
39
avatar_file = avatar_data ,
44
40
avatar_content_type = avatar_content_type
45
41
)
@@ -62,74 +58,64 @@ async def as_form(
62
58
@router .post ("/update_profile" , response_class = RedirectResponse )
63
59
async def update_profile (
64
60
user_profile : UpdateProfile = Depends (UpdateProfile .as_form ),
65
- current_user : User = Depends (get_authenticated_user ),
61
+ user : User = Depends (get_authenticated_user ),
66
62
session : Session = Depends (get_session )
67
63
):
68
64
# Update user details
69
- current_user .name = user_profile .name
70
- current_user .email = user_profile .email
65
+ user .name = user_profile .name
66
+ user .email = user_profile .email
71
67
72
68
# Handle avatar update
73
69
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
70
+ user .avatar_data = user_profile .avatar_file
71
+ user .avatar_content_type = user_profile .avatar_content_type
81
72
82
73
session .commit ()
83
- session .refresh (current_user )
74
+ session .refresh (user )
84
75
return RedirectResponse (url = "/profile" , status_code = 303 )
85
76
86
77
87
78
@router .post ("/delete_account" , response_class = RedirectResponse )
88
79
async def delete_account (
89
80
user_delete_account : UserDeleteAccount = Depends (
90
81
UserDeleteAccount .as_form ),
91
- current_user : User = Depends (get_authenticated_user ),
82
+ user : User = Depends (get_authenticated_user ),
92
83
session : Session = Depends (get_session )
93
84
):
94
- if not current_user .password :
95
- raise HTTPException (
96
- status_code = 500 ,
97
- detail = "User password not found in database; please contact a system administrator"
85
+ if not user .password :
86
+ raise DataIntegrityError (
87
+ resource = "User password"
98
88
)
99
89
100
90
if not verify_password (
101
91
user_delete_account .confirm_delete_password ,
102
- current_user .password .hashed_password
92
+ user .password .hashed_password
103
93
):
104
- raise HTTPException (
105
- status_code = 400 ,
106
- detail = "Password is incorrect"
94
+ raise PasswordValidationError (
95
+ field = "confirm_delete_password" ,
96
+ message = "Password is incorrect"
107
97
)
108
98
109
99
# Delete the user
110
- session .delete (current_user )
100
+ session .delete (user )
111
101
session .commit ()
112
102
113
103
# Log out the user
114
104
return RedirectResponse (url = "/auth/logout" , status_code = 303 )
115
105
116
106
117
- @router .get ("/avatar/{user_id} " )
107
+ @router .get ("/avatar" )
118
108
async def get_avatar (
119
- user_id : int ,
109
+ user : User = Depends ( get_authenticated_user ) ,
120
110
session : Session = Depends (get_session )
121
111
):
122
112
"""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
113
+ if not user .avatar_data :
114
+ raise DataIntegrityError (
115
+ resource = "User avatar"
131
116
)
132
- elif user .avatar_url :
133
- return RedirectResponse (url = user .avatar_url )
134
- else :
135
- raise HTTPException (status_code = 404 , detail = "Avatar not found" )
117
+
118
+ return Response (
119
+ content = user .avatar_data ,
120
+ media_type = user .avatar_content_type
121
+ )
0 commit comments