Hussien Haider commited on
Commit
77e48ab
·
1 Parent(s): f792754
Files changed (1) hide show
  1. app/api/profile.py +63 -0
app/api/profile.py CHANGED
@@ -21,6 +21,10 @@ class AvatarUpdateResponse(BaseModel):
21
  avatar_url: str
22
 
23
 
 
 
 
 
24
  @router.get("", response_model=AvatarResponse)
25
  async def get_profile(
26
  user: dict = Depends(get_current_user),
@@ -48,6 +52,29 @@ async def get_profile(
48
  )
49
 
50
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  @router.post("/avatar", response_model=AvatarUpdateResponse)
52
  async def upload_avatar(
53
  file: UploadFile = File(...),
@@ -125,3 +152,39 @@ async def upload_avatar(
125
  pass # Non-critical; the file is already uploaded
126
 
127
  return AvatarUpdateResponse(avatar_url=public_url)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  avatar_url: str
22
 
23
 
24
+ class AvatarUrlPayload(BaseModel):
25
+ url: str
26
+
27
+
28
  @router.get("", response_model=AvatarResponse)
29
  async def get_profile(
30
  user: dict = Depends(get_current_user),
 
52
  )
53
 
54
 
55
+ @router.post("/avatar-url", response_model=AvatarUpdateResponse)
56
+ async def set_avatar_url(
57
+ payload: AvatarUrlPayload,
58
+ user: dict = Depends(get_current_user),
59
+ request: Request = None,
60
+ ):
61
+ """Save an external avatar URL (e.g. from Google OAuth) to the user's profile."""
62
+ user_id = user["user_id"]
63
+ user_token = extract_token_from_request(request) or SUPABASE_ANON_KEY
64
+ update_url = f"{SUPABASE_URL}/rest/v1/users?id=eq.{user_id}"
65
+ async with httpx.AsyncClient(timeout=15) as client:
66
+ await client.patch(
67
+ update_url,
68
+ json={"avatar_url": payload.url},
69
+ headers={
70
+ "apikey": SUPABASE_ANON_KEY,
71
+ "Authorization": f"Bearer {user_token}",
72
+ "Content-Type": "application/json",
73
+ },
74
+ )
75
+ return AvatarUpdateResponse(avatar_url=payload.url)
76
+
77
+
78
  @router.post("/avatar", response_model=AvatarUpdateResponse)
79
  async def upload_avatar(
80
  file: UploadFile = File(...),
 
152
  pass # Non-critical; the file is already uploaded
153
 
154
  return AvatarUpdateResponse(avatar_url=public_url)
155
+
156
+
157
+ @router.get("/public/{user_id}")
158
+ async def get_public_profile(user_id: str):
159
+ """Fetch a public user profile (no auth required)."""
160
+ headers = {
161
+ "apikey": SUPABASE_ANON_KEY,
162
+ "Authorization": f"Bearer {SUPABASE_ANON_KEY}",
163
+ "Content-Type": "application/json",
164
+ }
165
+ async with httpx.AsyncClient(timeout=15) as client:
166
+ url = f"{SUPABASE_URL}/rest/v1/leaderboard?id=eq.{user_id}&select=id,name,xp,completed_trainings,avatar_url&limit=1"
167
+ resp = await client.get(url, headers=headers)
168
+ user_data = {}
169
+ if resp.status_code == 200 and resp.json():
170
+ user_data = resp.json()[0]
171
+ else:
172
+ url2 = f"{SUPABASE_URL}/rest/v1/users?id=eq.{user_id}&select=id,name,avatar_url&limit=1"
173
+ resp2 = await client.get(url2, headers=headers)
174
+ if resp2.status_code == 200 and resp2.json():
175
+ u = resp2.json()[0]
176
+ user_data = {**u, "xp": 0, "completed_trainings": 0}
177
+ cert_url = f"{SUPABASE_URL}/rest/v1/certificates?user_id=eq.{user_id}&select=id,category,issue_date,verify_code,title&order=issue_date.desc"
178
+ cert_resp = await client.get(cert_url, headers=headers)
179
+ certificates = cert_resp.json() if cert_resp.status_code == 200 else []
180
+ return {
181
+ "user": {
182
+ "id": user_data.get("id", user_id),
183
+ "name": user_data.get("name") or "مستخدم",
184
+ "xp": int(user_data.get("xp") or 0),
185
+ "completed_trainings": int(user_data.get("completed_trainings") or 0),
186
+ "avatar_url": user_data.get("avatar_url") or "",
187
+ },
188
+ "certificates": certificates,
189
+ "total_certificates": len(certificates),
190
+ }