Shri Jayaram commited on
Commit
d94e904
·
2 Parent(s): d60aba7 5c780f1

Merge pull request #24 from yuvabe-ai-labs/feat/profile

Browse files
src/auth/router.py CHANGED
@@ -11,7 +11,8 @@ from src.auth.service import (
11
  login_user,
12
  )
13
  from src.auth.utils import get_current_user
14
- from src.core.models import Users
 
15
  from src.core.config import settings
16
  from fastapi.responses import RedirectResponse
17
  from .schemas import SignUpRequest, LoginRequest, BaseResponse, SendVerificationRequest
@@ -63,6 +64,21 @@ async def login(
63
  payload: LoginRequest, session: AsyncSession = Depends(get_async_session)
64
  ):
65
  response = await login_user(session, payload.email, payload.password)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  return {"code": 200, "data": response}
67
 
68
 
@@ -104,6 +120,13 @@ async def get_home(
104
  if not user:
105
  raise HTTPException(status_code=404, detail="User not found")
106
 
 
 
 
 
 
 
 
107
  # Example payload — replace with your real app data
108
  return {
109
  "code": 200,
@@ -115,7 +138,8 @@ async def get_home(
115
  "email": user.email_id,
116
  "is_verified": user.is_verified,
117
  "dob": user.dob.isoformat() if user.dob else None,
118
- "profile_picture": user.profile_picture
 
119
  },
120
  "home_data": {
121
  "announcements": ["Welcome!", "New protocol released"],
 
11
  login_user,
12
  )
13
  from src.auth.utils import get_current_user
14
+ from src.core.models import Users, Roles, UserTeamsRole
15
+ from sqlmodel import select
16
  from src.core.config import settings
17
  from fastapi.responses import RedirectResponse
18
  from .schemas import SignUpRequest, LoginRequest, BaseResponse, SendVerificationRequest
 
64
  payload: LoginRequest, session: AsyncSession = Depends(get_async_session)
65
  ):
66
  response = await login_user(session, payload.email, payload.password)
67
+
68
+ user_id = response["user"]["id"]
69
+
70
+ # 🔥 Fetch User Role
71
+ result = await session.exec(
72
+ select(Roles)
73
+ .join(UserTeamsRole, UserTeamsRole.role_id == Roles.id)
74
+ .where(UserTeamsRole.user_id == uuid.UUID(user_id))
75
+ )
76
+
77
+ role_obj = result.first()
78
+ role_name = role_obj.name if role_obj else "Member"
79
+
80
+ response["user"]["role"] = (role_name or "member").lower()
81
+
82
  return {"code": 200, "data": response}
83
 
84
 
 
120
  if not user:
121
  raise HTTPException(status_code=404, detail="User not found")
122
 
123
+ role_join = await session.exec(
124
+ select(Roles.name)
125
+ .join(UserTeamsRole, UserTeamsRole.role_id == Roles.id)
126
+ .where(UserTeamsRole.user_id == uuid.UUID(user_id))
127
+ )
128
+ user_role = role_join.first() or "Member"
129
+
130
  # Example payload — replace with your real app data
131
  return {
132
  "code": 200,
 
138
  "email": user.email_id,
139
  "is_verified": user.is_verified,
140
  "dob": user.dob.isoformat() if user.dob else None,
141
+ "profile_picture": user.profile_picture,
142
+ "role": user_role.lower(),
143
  },
144
  "home_data": {
145
  "announcements": ["Welcome!", "New protocol released"],
src/notifications/router.py CHANGED
@@ -1,3 +1,4 @@
 
1
  from src.notifications.schemas import RegisterDeviceRequest
2
  from src.notifications.service import register_device
3
  from fastapi import APIRouter, Depends
@@ -16,3 +17,5 @@ async def register_device_route(
16
  ):
17
  device = await register_device(user, body, session)
18
  return {"message": "Device registered", "device": str(device.id)}
 
 
 
1
+ from requests.api import delete
2
  from src.notifications.schemas import RegisterDeviceRequest
3
  from src.notifications.service import register_device
4
  from fastapi import APIRouter, Depends
 
17
  ):
18
  device = await register_device(user, body, session)
19
  return {"message": "Device registered", "device": str(device.id)}
20
+
21
+
src/profile/router.py CHANGED
@@ -1,3 +1,4 @@
 
1
  from src.core.database import get_async_session
2
  from src.auth.utils import get_current_user
3
  from src.profile.models import Leave, LeaveType, LeaveStatus
@@ -210,33 +211,42 @@ async def list_notifications(
210
  return {"code": 200, "data": notifications}
211
 
212
 
213
- @router.get("/leave/{leave_id}")
214
  async def get_leave_details(
215
  leave_id: str,
216
  session: AsyncSession = Depends(get_async_session),
217
  user_id: str = Depends(get_current_user),
218
  ):
219
- leave = await session.get(Leave, leave_id)
 
 
 
 
 
220
 
221
- if not leave:
 
 
222
  raise HTTPException(status_code=404, detail="Leave not found")
223
 
224
- # Convert to JSON response
 
225
  return {
226
  "code": 200,
227
  "data": {
228
  "id": str(leave.id),
229
  "user_id": str(leave.user_id),
 
230
  "mentor_id": str(leave.mentor_id),
231
  "lead_id": str(leave.lead_id),
232
  "leave_type": leave.leave_type,
233
- "from_date": str(leave.from_date),
234
- "to_date": str(leave.to_date),
235
  "days": leave.days,
236
  "reason": leave.reason,
237
  "status": leave.status,
238
  "reject_reason": leave.reject_reason,
239
- "updated_at": leave.updated_at.isoformat(),
240
  },
241
  }
242
 
@@ -246,32 +256,122 @@ async def mentor_pending_leaves(
246
  session: AsyncSession = Depends(get_async_session),
247
  mentor_id: str = Depends(get_current_user),
248
  ):
249
- stmt = select(Leave).where(
250
- Leave.mentor_id == mentor_id,
251
- Leave.status == LeaveStatus.PENDING,
 
 
 
 
 
 
252
  )
253
 
254
  rows = (await session.exec(stmt)).all()
255
 
256
- return {
257
- "code": 200,
258
- "data": [
 
259
  LeaveResponse(
260
- id=str(r.id),
261
- leave_type=r.leave_type,
262
- from_date=r.from_date,
263
- to_date=r.to_date,
264
- days=r.days,
265
- reason=r.reason,
266
- status=r.status,
267
- mentor_id=str(r.mentor_id),
268
- lead_id=str(r.lead_id),
 
 
 
 
 
 
 
 
 
 
269
  )
270
- for r in rows
271
- ],
 
 
 
272
  }
273
 
274
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
275
  @router.get("/contacts", response_model=BaseResponse)
276
  async def get_leave_contacts(
277
  current_user=Depends(get_current_user),
 
1
+ from src.profile.schemas import LeaveDetailResponse
2
  from src.core.database import get_async_session
3
  from src.auth.utils import get_current_user
4
  from src.profile.models import Leave, LeaveType, LeaveStatus
 
211
  return {"code": 200, "data": notifications}
212
 
213
 
214
+ @router.get("/leave/{leave_id}", response_model=LeaveDetailResponse)
215
  async def get_leave_details(
216
  leave_id: str,
217
  session: AsyncSession = Depends(get_async_session),
218
  user_id: str = Depends(get_current_user),
219
  ):
220
+ # Join Leave + Users table to get user_name
221
+ stmt = (
222
+ select(Leave, Users.user_name)
223
+ .join(Users, Users.id == Leave.user_id)
224
+ .where(Leave.id == uuid.UUID(leave_id))
225
+ )
226
 
227
+ row = (await session.exec(stmt)).first()
228
+
229
+ if not row:
230
  raise HTTPException(status_code=404, detail="Leave not found")
231
 
232
+ leave, user_name = row
233
+
234
  return {
235
  "code": 200,
236
  "data": {
237
  "id": str(leave.id),
238
  "user_id": str(leave.user_id),
239
+ "user_name": user_name,
240
  "mentor_id": str(leave.mentor_id),
241
  "lead_id": str(leave.lead_id),
242
  "leave_type": leave.leave_type,
243
+ "from_date": leave.from_date.isoformat(),
244
+ "to_date": leave.to_date.isoformat(),
245
  "days": leave.days,
246
  "reason": leave.reason,
247
  "status": leave.status,
248
  "reject_reason": leave.reject_reason,
249
+ "updated_at": leave.updated_at.isoformat() if leave.updated_at else None,
250
  },
251
  }
252
 
 
256
  session: AsyncSession = Depends(get_async_session),
257
  mentor_id: str = Depends(get_current_user),
258
  ):
259
+ print("🔥 mentor pending called for:", mentor_id)
260
+
261
+ stmt = (
262
+ select(Leave, Users.user_name)
263
+ .join(Users, Users.id == Leave.user_id)
264
+ .where(
265
+ Leave.mentor_id == uuid.UUID(mentor_id),
266
+ Leave.status == LeaveStatus.PENDING,
267
+ )
268
  )
269
 
270
  rows = (await session.exec(stmt)).all()
271
 
272
+ result = []
273
+
274
+ for leave, user_name in rows:
275
+ result.append(
276
  LeaveResponse(
277
+ id=str(leave.id),
278
+ leave_type=leave.leave_type,
279
+ from_date=leave.from_date.isoformat(),
280
+ to_date=leave.to_date.isoformat(),
281
+ days=leave.days,
282
+ reason=leave.reason,
283
+ status=(
284
+ leave.status.value
285
+ if hasattr(leave.status, "value")
286
+ else leave.status
287
+ ),
288
+ mentor_id=str(leave.mentor_id),
289
+ lead_id=str(leave.lead_id),
290
+ user_name=user_name,
291
+ updated_at=(
292
+ leave.updated_at.isoformat()
293
+ if hasattr(leave, "updated_at") and leave.updated_at
294
+ else None
295
+ ),
296
  )
297
+ )
298
+
299
+ return {
300
+ "code": 200,
301
+ "data": result,
302
  }
303
 
304
 
305
+ @router.get("/my-leaves")
306
+ async def my_leave_history(
307
+ session: AsyncSession = Depends(get_async_session),
308
+ user_id: str = Depends(get_current_user),
309
+ ):
310
+ stmt = (
311
+ select(Leave, Users.user_name, Users.email_id)
312
+ .join(Users, Users.id == Leave.mentor_id, isouter=True)
313
+ .where(Leave.user_id == uuid.UUID(user_id))
314
+ .order_by(desc(Leave.updated_at))
315
+ )
316
+
317
+ rows = (await session.exec(stmt)).all()
318
+
319
+ result = []
320
+ for leave, mentor_name, mentor_email in rows:
321
+ result.append(
322
+ {
323
+ "id": str(leave.id),
324
+ "leave_type": leave.leave_type,
325
+ "from_date": leave.from_date.isoformat(),
326
+ "to_date": leave.to_date.isoformat(),
327
+ "days": leave.days,
328
+ "reason": leave.reason,
329
+ "status": leave.status,
330
+ "mentor_name": mentor_name,
331
+ "updated_at": (
332
+ leave.updated_at.isoformat() if leave.updated_at else None
333
+ ),
334
+ }
335
+ )
336
+
337
+ return {"code": 200, "data": result}
338
+
339
+
340
+ @router.get("/mentor/team-leaves")
341
+ async def team_leave_history(
342
+ session: AsyncSession = Depends(get_async_session),
343
+ mentor_id: str = Depends(get_current_user),
344
+ ):
345
+ stmt = (
346
+ select(Leave, Users.user_name)
347
+ .join(Users, Users.id == Leave.user_id)
348
+ .where(Leave.mentor_id == uuid.UUID(mentor_id))
349
+ .order_by(desc(Leave.updated_at))
350
+ )
351
+
352
+ rows = (await session.exec(stmt)).all()
353
+
354
+ result = []
355
+ for leave, username in rows:
356
+ result.append(
357
+ {
358
+ "id": str(leave.id),
359
+ "user_name": username,
360
+ "leave_type": leave.leave_type,
361
+ "from_date": leave.from_date.isoformat(),
362
+ "to_date": leave.to_date.isoformat(),
363
+ "days": leave.days,
364
+ "reason": leave.reason,
365
+ "status": leave.status,
366
+ "updated_at": (
367
+ leave.updated_at.isoformat() if leave.updated_at else None
368
+ ),
369
+ }
370
+ )
371
+
372
+ return {"code": 200, "data": result}
373
+
374
+
375
  @router.get("/contacts", response_model=BaseResponse)
376
  async def get_leave_contacts(
377
  current_user=Depends(get_current_user),
src/profile/schemas.py CHANGED
@@ -31,6 +31,27 @@ class ApproveRejectRequest(BaseModel):
31
  comment: Optional[str] = None # optional for approve, required for reject
32
 
33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  class LeaveResponse(BaseModel):
35
  id: str
36
  leave_type: LeaveType
@@ -41,6 +62,8 @@ class LeaveResponse(BaseModel):
41
  status: LeaveStatus
42
  mentor_id: str
43
  lead_id: str
 
 
44
 
45
 
46
  class DeviceTokenIn(BaseModel):
 
31
  comment: Optional[str] = None # optional for approve, required for reject
32
 
33
 
34
+ class LeaveDetail(BaseModel):
35
+ id: str
36
+ user_id: str
37
+ user_name: str # 👈 NEW FIELD
38
+ mentor_id: Optional[str]
39
+ lead_id: Optional[str]
40
+ leave_type: str
41
+ from_date: str
42
+ to_date: str
43
+ days: int
44
+ reason: str
45
+ status: str
46
+ reject_reason: Optional[str]
47
+ updated_at: Optional[str]
48
+
49
+
50
+ class LeaveDetailResponse(BaseModel):
51
+ code: int
52
+ data: LeaveDetail
53
+
54
+
55
  class LeaveResponse(BaseModel):
56
  id: str
57
  leave_type: LeaveType
 
62
  status: LeaveStatus
63
  mentor_id: str
64
  lead_id: str
65
+ user_name: Optional[str] = None
66
+ updated_at: Optional[str] = None
67
 
68
 
69
  class DeviceTokenIn(BaseModel):