Ali2206 commited on
Commit
b84b4a7
·
verified ·
1 Parent(s): 14f392b

Update api/routes/auth.py

Browse files
Files changed (1) hide show
  1. api/routes/auth.py +131 -88
api/routes/auth.py CHANGED
@@ -1,113 +1,156 @@
1
- from fastapi import APIRouter, Depends, HTTPException, status, Request
2
  from fastapi.security import OAuth2PasswordRequestForm
3
- from db.mongo import get_user_db
4
- from core.security import (
5
- create_access_token,
6
- verify_token,
7
- get_password_hash,
8
- verify_password
9
- )
10
- from models.schemas import (
11
- TokenResponse,
12
- UserCreate,
13
- UserInDB,
14
- UserResponse
15
- )
16
- from datetime import timedelta
17
  import logging
18
- from core.config import settings
19
 
20
- router = APIRouter()
 
 
 
 
21
  logger = logging.getLogger(__name__)
22
 
23
- @router.post("/login", response_model=TokenResponse)
24
- async def login(
25
- request: Request,
26
- form_data: OAuth2PasswordRequestForm = Depends()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  ):
28
- logger.info(f"Login attempt from {request.client.host}")
 
 
 
 
 
 
29
 
30
- user_db = await get_user_db()
31
- user = await user_db.find_one({"email": form_data.username.lower()})
 
 
 
 
 
 
32
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  if not user or not verify_password(form_data.password, user["password"]):
34
- logger.warning(f"Failed login attempt for {form_data.username}")
35
  raise HTTPException(
36
  status_code=status.HTTP_401_UNAUTHORIZED,
37
- detail="Incorrect email or password",
38
  headers={"WWW-Authenticate": "Bearer"},
39
  )
40
-
41
- access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
42
- access_token = create_access_token(
43
- data={"sub": user["email"], "role": user.get("role", "user")},
44
- expires_delta=access_token_expires
45
- )
46
 
47
- logger.info(f"Successful login for {user['email']}")
 
48
  return {
49
  "access_token": access_token,
50
  "token_type": "bearer",
51
- "expires_in": access_token_expires.total_seconds()
52
  }
53
 
54
- @router.post("/signup", response_model=UserResponse)
55
- async def signup(user_in: UserCreate):
56
- logger.info(f"Signup attempt for {user_in.email}")
57
-
58
- user_db = await get_user_db()
59
- if await user_db.find_one({"email": user_in.email.lower()}):
60
- logger.warning(f"Email already registered: {user_in.email}")
61
- raise HTTPException(
62
- status_code=status.HTTP_400_BAD_REQUEST,
63
- detail="Email already registered"
64
- )
65
-
66
- hashed_password = get_password_hash(user_in.password)
67
- db_user = UserInDB(
68
- **user_in.dict(),
69
- password=hashed_password,
70
- role="user",
71
- created_at=datetime.utcnow(),
72
- updated_at=datetime.utcnow()
73
- )
74
-
75
  try:
76
- result = await user_db.insert_one(db_user.dict())
77
- logger.info(f"User created: {user_in.email}")
78
- return UserResponse(
79
- id=str(result.inserted_id),
80
- email=db_user.email,
81
- full_name=db_user.full_name,
82
- role=db_user.role
83
- )
 
 
 
 
 
 
 
 
 
 
 
84
  except Exception as e:
85
- logger.error(f"User creation failed: {str(e)}")
86
  raise HTTPException(
87
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
88
- detail="User creation failed"
89
  )
90
 
91
- @router.get("/me", response_model=UserResponse)
92
- async def read_users_me(
93
- request: Request,
94
- current_user: UserInDB = Depends(verify_token)
95
- ):
96
- logger.info(f"User profile request for {current_user.sub}")
97
-
98
- user_db = await get_user_db()
99
- user = await user_db.find_one({"email": current_user.sub})
100
-
101
- if not user:
102
- logger.error(f"User not found: {current_user.sub}")
103
- raise HTTPException(
104
- status_code=status.HTTP_404_NOT_FOUND,
105
- detail="User not found"
106
- )
107
-
108
- return UserResponse(
109
- id=str(user["_id"]),
110
- email=user["email"],
111
- full_name=user.get("full_name", ""),
112
- role=user.get("role", "user")
113
- )
 
1
+ from fastapi import APIRouter, HTTPException, Depends, status, Request
2
  from fastapi.security import OAuth2PasswordRequestForm
3
+ from db.mongo import users_collection
4
+ from core.security import hash_password, verify_password, create_access_token, get_current_user
5
+ from models.schemas import SignupForm, TokenResponse, DoctorCreate
6
+ from datetime import datetime
 
 
 
 
 
 
 
 
 
 
7
  import logging
 
8
 
9
+ # Configure logging
10
+ logging.basicConfig(
11
+ level=logging.INFO,
12
+ format='%(asctime)s - %(levelname)s - %(name)s - %(message)s'
13
+ )
14
  logger = logging.getLogger(__name__)
15
 
16
+ router = APIRouter()
17
+
18
+ @router.post("/signup", status_code=status.HTTP_201_CREATED)
19
+ async def signup(data: SignupForm):
20
+ logger.info(f"Signup attempt for email: {data.email}")
21
+ email = data.email.lower().strip()
22
+ existing = await users_collection.find_one({"email": email})
23
+ if existing:
24
+ logger.warning(f"Signup failed: Email already exists: {email}")
25
+ raise HTTPException(
26
+ status_code=status.HTTP_409_CONFLICT,
27
+ detail="Email already exists"
28
+ )
29
+
30
+ hashed_pw = hash_password(data.password)
31
+ user_doc = {
32
+ "email": email,
33
+ "full_name": data.full_name.strip(),
34
+ "password": hashed_pw,
35
+ "role": "patient",
36
+ "created_at": datetime.utcnow().isoformat(),
37
+ "updated_at": datetime.utcnow().isoformat()
38
+ }
39
+
40
+ try:
41
+ result = await users_collection.insert_one(user_doc)
42
+ logger.info(f"User created successfully: {email}")
43
+ return {
44
+ "status": "success",
45
+ "id": str(result.inserted_id),
46
+ "email": email
47
+ }
48
+ except Exception as e:
49
+ logger.error(f"Failed to create user {email}: {str(e)}")
50
+ raise HTTPException(
51
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
52
+ detail=f"Failed to create user: {str(e)}"
53
+ )
54
+
55
+ @router.post("/admin/doctors", status_code=status.HTTP_201_CREATED)
56
+ async def create_doctor(
57
+ data: DoctorCreate,
58
+ current_user: dict = Depends(get_current_user)
59
  ):
60
+ logger.info(f"Doctor creation attempt by {current_user.get('email')}")
61
+ if current_user.get('role') != 'admin':
62
+ logger.warning(f"Unauthorized doctor creation attempt by {current_user.get('email')}")
63
+ raise HTTPException(
64
+ status_code=status.HTTP_403_FORBIDDEN,
65
+ detail="Only admins can create doctor accounts"
66
+ )
67
 
68
+ email = data.email.lower().strip()
69
+ existing = await users_collection.find_one({"email": email})
70
+ if existing:
71
+ logger.warning(f"Doctor creation failed: Email already exists: {email}")
72
+ raise HTTPException(
73
+ status_code=status.HTTP_409_CONFLICT,
74
+ detail="Email already exists"
75
+ )
76
 
77
+ hashed_pw = hash_password(data.password)
78
+ doctor_doc = {
79
+ "email": email,
80
+ "full_name": data.full_name.strip(),
81
+ "password": hashed_pw,
82
+ "role": "doctor",
83
+ "specialty": data.specialty,
84
+ "license_number": data.license_number,
85
+ "created_at": datetime.utcnow().isoformat(),
86
+ "updated_at": datetime.utcnow().isoformat()
87
+ }
88
+
89
+ try:
90
+ result = await users_collection.insert_one(doctor_doc)
91
+ logger.info(f"Doctor created successfully: {email}")
92
+ return {
93
+ "status": "success",
94
+ "id": str(result.inserted_id),
95
+ "email": email
96
+ }
97
+ except Exception as e:
98
+ logger.error(f"Failed to create doctor {email}: {str(e)}")
99
+ raise HTTPException(
100
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
101
+ detail=f"Failed to create doctor: {str(e)}"
102
+ )
103
+
104
+ @router.post("/login", response_model=TokenResponse)
105
+ async def login(form_data: OAuth2PasswordRequestForm = Depends()):
106
+ logger.info(f"Login attempt for email: {form_data.username}")
107
+ user = await users_collection.find_one({"email": form_data.username.lower()})
108
  if not user or not verify_password(form_data.password, user["password"]):
109
+ logger.warning(f"Login failed for {form_data.username}: Invalid credentials")
110
  raise HTTPException(
111
  status_code=status.HTTP_401_UNAUTHORIZED,
112
+ detail="Invalid credentials",
113
  headers={"WWW-Authenticate": "Bearer"},
114
  )
 
 
 
 
 
 
115
 
116
+ access_token = create_access_token(data={"sub": user["email"]})
117
+ logger.info(f"Successful login for {form_data.username}")
118
  return {
119
  "access_token": access_token,
120
  "token_type": "bearer",
121
+ "role": user.get("role", "patient")
122
  }
123
 
124
+ @router.get("/me")
125
+ async def get_me(request: Request, current_user: dict = Depends(get_current_user)):
126
+ logger.info(f"Fetching user profile for {current_user['email']}")
127
+ print(f"Headers: {request.headers}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  try:
129
+ user = await users_collection.find_one({"email": current_user["email"]})
130
+ if not user:
131
+ logger.warning(f"User not found: {current_user['email']}")
132
+ raise HTTPException(
133
+ status_code=status.HTTP_404_NOT_FOUND,
134
+ detail="User not found"
135
+ )
136
+
137
+ response = {
138
+ "id": str(user["_id"]),
139
+ "email": user["email"],
140
+ "full_name": user.get("full_name", ""),
141
+ "role": user.get("role", "patient"),
142
+ "specialty": user.get("specialty"),
143
+ "created_at": user.get("created_at"),
144
+ "updated_at": user.get("updated_at")
145
+ }
146
+ logger.info(f"User profile retrieved for {current_user['email']}")
147
+ return response
148
  except Exception as e:
149
+ logger.error(f"Database error for user {current_user['email']}: {str(e)}")
150
  raise HTTPException(
151
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
152
+ detail=f"Database error: {str(e)}"
153
  )
154
 
155
+ # Export the router as 'auth' for api.__init__.py
156
+ auth = router