Coverage for api/account/controller.py: 92.59%
54 statements
« prev ^ index » next coverage.py v7.9.2, created at 2026-01-25 13:05 +0000
« prev ^ index » next coverage.py v7.9.2, created at 2026-01-25 13:05 +0000
1from core.redis import get_redis
2from core.dependencies import get_db
3from core.security import verify_token
4from sqlalchemy.ext.asyncio import AsyncSession
5from fastapi import APIRouter, Depends, HTTPException, Response
6from .schema import UserProfile, UserUpdate, PasswordChange
7from utils.response import APIResponse, parse_responses, common_responses
8from .services import get_user_by_id, update_user_profile, change_password
9from utils.custom_exception import AuthenticationException, NotFoundException
10from extensions.smtp import get_mailer, SMTPMailer
12router = APIRouter(tags=["Account"])
14@router.get(
15 "/profile",
16 response_model=APIResponse[UserProfile],
17 summary="Get current user profile",
18 responses=parse_responses({
19 200: ("User profile retrieved successfully", UserProfile)
20 }, common_responses)
21)
22async def get_user_profile_api(
23 token: dict = Depends(verify_token),
24 db: AsyncSession = Depends(get_db)
25):
26 """
27 Get the current authenticated user's profile information.
28 """
29 try:
30 user_id = token.get("sub")
31 user = await get_user_by_id(db, user_id)
33 if not user:
34 raise NotFoundException("User not found")
36 user_data = UserProfile(
37 id=user.id,
38 first_name=user.first_name,
39 last_name=user.last_name,
40 email=user.email,
41 phone=user.phone,
42 status=user.status,
43 created_at=user.created_at
44 )
46 return APIResponse(code=200, message="User profile retrieved successfully", data=user_data)
47 except NotFoundException:
48 raise HTTPException(status_code=404, detail="User not found")
49 except Exception:
50 raise HTTPException(status_code=500)
52@router.put(
53 "/profile",
54 response_model=APIResponse[UserProfile],
55 response_model_exclude_unset=True,
56 summary="Update current user profile",
57 responses=parse_responses({
58 200: ("User profile updated successfully", UserProfile),
59 202: ("Email verification required", UserProfile)
60 }, common_responses)
61)
62async def update_user_profile_api(
63 user_update: UserUpdate,
64 response: Response,
65 token: dict = Depends(verify_token),
66 db: AsyncSession = Depends(get_db),
67 redis_client = Depends(get_redis),
68 mailer: SMTPMailer = Depends(get_mailer)
69):
70 """
71 Update the current authenticated user's profile information (excluding password).
72 """
73 try:
74 user_id = token.get("sub")
75 result = await update_user_profile(
76 db, user_id, user_update, mailer, redis_client
77 )
79 if not result:
80 raise NotFoundException("User not found")
82 user, email_change_requested = result
84 user_data = UserProfile(
85 id=user.id,
86 first_name=user.first_name,
87 last_name=user.last_name,
88 email=user.email,
89 phone=user.phone,
90 status=user.status,
91 created_at=user.created_at
92 )
94 if email_change_requested:
95 response.status_code = 202
96 return APIResponse(code=202, message="Email verification required", data=user_data)
98 return APIResponse(code=200, message="User profile updated successfully", data=user_data)
99 except NotFoundException:
100 raise HTTPException(status_code=404, detail="User not found")
101 except ValueError:
102 raise HTTPException(status_code=409, detail="Email already exists")
103 except Exception:
104 raise HTTPException(status_code=500)
106@router.put(
107 "/password",
108 response_model=APIResponse[None],
109 response_model_exclude_unset=True,
110 summary="Change current user password",
111 responses=parse_responses({
112 200: ("Password changed successfully", None),
113 401: ("Invalid or expired token / Current password is incorrect", None)
114 }, common_responses)
115)
116async def change_user_password_api(
117 password_change: PasswordChange,
118 token: dict = Depends(verify_token),
119 db: AsyncSession = Depends(get_db),
120 redis_client = Depends(get_redis)
121):
122 """
123 Change the current authenticated user's password.
124 """
125 try:
126 user_id = token.get("sub")
127 success = await change_password(db, user_id, password_change, redis_client)
129 if success:
130 return APIResponse(code=200, message="Password changed successfully")
132 except AuthenticationException:
133 raise HTTPException(status_code=401, detail="Current password is incorrect")
134 except Exception as e:
135 raise HTTPException(status_code=500, detail=str(e))