Spaces:
Running
Running
Commit
·
4cde766
1
Parent(s):
448a5b1
fyp
Browse files- app/ai/agent/brain.py +6 -1
- app/config.py +2 -2
- app/core/security.py +6 -6
- app/routes/auth.py +5 -45
- app/services/auth_service.py +4 -4
app/ai/agent/brain.py
CHANGED
|
@@ -86,7 +86,12 @@ AVAILABLE_TOOLS = """
|
|
| 86 |
- This saves their last search criteria so they get a DM when a matching property is listed
|
| 87 |
- Only use AFTER a search with 0 results where user was prompted about notifications
|
| 88 |
|
| 89 |
-
8.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
- Use this for general chat, greeting, or asking clarifying questions
|
| 91 |
- If no other tool fits, use this
|
| 92 |
"""
|
|
|
|
| 86 |
- This saves their last search criteria so they get a DM when a matching property is listed
|
| 87 |
- Only use AFTER a search with 0 results where user was prompted about notifications
|
| 88 |
|
| 89 |
+
8. delete_listing(listing_id: str)
|
| 90 |
+
- Use this IMMEDIATELY when user says "delete listing X" or confirms deletion
|
| 91 |
+
- The UI handles the "Are you sure?" confirmation dialog, so if you receive this command, EXECUTE it.
|
| 92 |
+
- Do not ask for confirmation again.
|
| 93 |
+
|
| 94 |
+
9. respond(message: str)
|
| 95 |
- Use this for general chat, greeting, or asking clarifying questions
|
| 96 |
- If no other tool fits, use this
|
| 97 |
"""
|
app/config.py
CHANGED
|
@@ -50,8 +50,8 @@ class Settings(BaseSettings):
|
|
| 50 |
JWT_SECRET: str = os.getenv("JWT_SECRET", "") # MUST be set in production
|
| 51 |
JWT_REFRESH_SECRET: str = os.getenv("JWT_REFRESH_SECRET", "") # Separate secret for refresh tokens
|
| 52 |
JWT_ALGORITHM: str = "HS256"
|
| 53 |
-
JWT_ACCESS_EXPIRY_MINUTES: int =
|
| 54 |
-
JWT_REFRESH_EXPIRY_DAYS: int =
|
| 55 |
JWT_RESET_EXPIRY_MINUTES: int = 10
|
| 56 |
JWT_ISSUER: str = "lojiz-api"
|
| 57 |
JWT_AUDIENCE: str = "lojiz-app"
|
|
|
|
| 50 |
JWT_SECRET: str = os.getenv("JWT_SECRET", "") # MUST be set in production
|
| 51 |
JWT_REFRESH_SECRET: str = os.getenv("JWT_REFRESH_SECRET", "") # Separate secret for refresh tokens
|
| 52 |
JWT_ALGORITHM: str = "HS256"
|
| 53 |
+
JWT_ACCESS_EXPIRY_MINUTES: int = 60 * 24 * 60 # Long-lived access token (60 days)
|
| 54 |
+
JWT_REFRESH_EXPIRY_DAYS: int = 60 # (Unused/Legacy)
|
| 55 |
JWT_RESET_EXPIRY_MINUTES: int = 10
|
| 56 |
JWT_ISSUER: str = "lojiz-api"
|
| 57 |
JWT_AUDIENCE: str = "lojiz-app"
|
app/core/security.py
CHANGED
|
@@ -232,19 +232,19 @@ def create_token_pair(
|
|
| 232 |
role: str,
|
| 233 |
) -> Dict[str, str]:
|
| 234 |
"""
|
| 235 |
-
Create
|
| 236 |
-
Returns dict with
|
| 237 |
"""
|
| 238 |
access_token = create_access_token(user_id, email, phone, role)
|
| 239 |
-
refresh_token = create_refresh_token(user_id, email, phone, role)
|
| 240 |
|
| 241 |
-
logger.info(f"
|
| 242 |
|
| 243 |
return {
|
| 244 |
"access_token": access_token,
|
| 245 |
-
"refresh_token": refresh_token,
|
| 246 |
"token_type": "bearer",
|
| 247 |
-
"expires_in": settings.JWT_ACCESS_EXPIRY_MINUTES * 60, # In seconds
|
| 248 |
}
|
| 249 |
|
| 250 |
# ============================================================
|
|
|
|
| 232 |
role: str,
|
| 233 |
) -> Dict[str, str]:
|
| 234 |
"""
|
| 235 |
+
Create long-lived access token for login.
|
| 236 |
+
Returns dict with access_token.
|
| 237 |
"""
|
| 238 |
access_token = create_access_token(user_id, email, phone, role)
|
| 239 |
+
# refresh_token = create_refresh_token(user_id, email, phone, role) # DEPRECATED
|
| 240 |
|
| 241 |
+
logger.info(f"Long-lived token created for user: {user_id}")
|
| 242 |
|
| 243 |
return {
|
| 244 |
"access_token": access_token,
|
| 245 |
+
# "refresh_token": refresh_token, # DEPRECATED
|
| 246 |
"token_type": "bearer",
|
| 247 |
+
"expires_in": settings.JWT_ACCESS_EXPIRY_MINUTES * 60, # In seconds (60 days)
|
| 248 |
}
|
| 249 |
|
| 250 |
# ============================================================
|
app/routes/auth.py
CHANGED
|
@@ -181,49 +181,9 @@ async def logout(current_user: dict = Depends(get_current_user)):
|
|
| 181 |
# REFRESH TOKEN ENDPOINT
|
| 182 |
# ============================================================
|
| 183 |
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
refresh_token: str
|
| 188 |
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
"""
|
| 192 |
-
Refresh Access Token
|
| 193 |
-
|
| 194 |
-
Use this endpoint to get a new access token when the current one expires.
|
| 195 |
-
Send your refresh_token in the request body.
|
| 196 |
-
|
| 197 |
-
Returns new access_token and refresh_token pair.
|
| 198 |
-
|
| 199 |
-
**Frontend Implementation:**
|
| 200 |
-
1. When API returns 401 (token expired)
|
| 201 |
-
2. Call this endpoint with your stored refresh_token
|
| 202 |
-
3. Store the new tokens and retry the original request
|
| 203 |
-
"""
|
| 204 |
-
from app.core.security import verify_refresh_token, create_token_pair
|
| 205 |
-
|
| 206 |
-
payload = verify_refresh_token(dto.refresh_token)
|
| 207 |
-
|
| 208 |
-
if not payload:
|
| 209 |
-
raise HTTPException(
|
| 210 |
-
status_code=status.HTTP_401_UNAUTHORIZED,
|
| 211 |
-
detail="Invalid or expired refresh token. Please login again.",
|
| 212 |
-
headers={"WWW-Authenticate": "Bearer"},
|
| 213 |
-
)
|
| 214 |
-
|
| 215 |
-
# Generate new token pair
|
| 216 |
-
tokens = create_token_pair(
|
| 217 |
-
user_id=payload.get("user_id"),
|
| 218 |
-
email=payload.get("email"),
|
| 219 |
-
phone=payload.get("phone"),
|
| 220 |
-
role=payload.get("role"),
|
| 221 |
-
)
|
| 222 |
-
|
| 223 |
-
logger.info(f"Tokens refreshed for user: {payload.get('user_id')}")
|
| 224 |
-
|
| 225 |
-
return {
|
| 226 |
-
"success": True,
|
| 227 |
-
"message": "Tokens refreshed successfully.",
|
| 228 |
-
"data": tokens,
|
| 229 |
-
}
|
|
|
|
| 181 |
# REFRESH TOKEN ENDPOINT
|
| 182 |
# ============================================================
|
| 183 |
|
| 184 |
+
# ============================================================
|
| 185 |
+
# REFRESH TOKEN ENDPOINT
|
| 186 |
+
# ============================================================
|
|
|
|
| 187 |
|
| 188 |
+
# DEPRECATED: Refresh token mechanism replaced by 60-day long-lived access tokens
|
| 189 |
+
# Endpoint removed to simplify auth flow.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/services/auth_service.py
CHANGED
|
@@ -197,7 +197,7 @@ class AuthService:
|
|
| 197 |
# Delete OTP
|
| 198 |
await otp_service.delete_otp(identifier, "signup")
|
| 199 |
|
| 200 |
-
# Generate token pair (access
|
| 201 |
tokens = create_token_pair(
|
| 202 |
user_id=str(user["_id"]),
|
| 203 |
email=user.get("email"),
|
|
@@ -212,7 +212,7 @@ class AuthService:
|
|
| 212 |
"message": "Welcome! Your account is now verified.",
|
| 213 |
"data": {
|
| 214 |
"user": User.format_response(user),
|
| 215 |
-
**tokens, # access_token,
|
| 216 |
},
|
| 217 |
}
|
| 218 |
|
|
@@ -277,7 +277,7 @@ class AuthService:
|
|
| 277 |
{"$set": {"lastLogin": now, "updatedAt": now}}
|
| 278 |
)
|
| 279 |
|
| 280 |
-
# Generate token pair (access
|
| 281 |
tokens = create_token_pair(
|
| 282 |
user_id=str(user["_id"]),
|
| 283 |
email=user.get("email"),
|
|
@@ -292,7 +292,7 @@ class AuthService:
|
|
| 292 |
"message": "Login successful!",
|
| 293 |
"data": {
|
| 294 |
"user": User.format_response(user),
|
| 295 |
-
**tokens, # access_token,
|
| 296 |
},
|
| 297 |
}
|
| 298 |
|
|
|
|
| 197 |
# Delete OTP
|
| 198 |
await otp_service.delete_otp(identifier, "signup")
|
| 199 |
|
| 200 |
+
# Generate token pair (access only)
|
| 201 |
tokens = create_token_pair(
|
| 202 |
user_id=str(user["_id"]),
|
| 203 |
email=user.get("email"),
|
|
|
|
| 212 |
"message": "Welcome! Your account is now verified.",
|
| 213 |
"data": {
|
| 214 |
"user": User.format_response(user),
|
| 215 |
+
**tokens, # access_token, token_type, expires_in
|
| 216 |
},
|
| 217 |
}
|
| 218 |
|
|
|
|
| 277 |
{"$set": {"lastLogin": now, "updatedAt": now}}
|
| 278 |
)
|
| 279 |
|
| 280 |
+
# Generate token pair (access only)
|
| 281 |
tokens = create_token_pair(
|
| 282 |
user_id=str(user["_id"]),
|
| 283 |
email=user.get("email"),
|
|
|
|
| 292 |
"message": "Login successful!",
|
| 293 |
"data": {
|
| 294 |
"user": User.format_response(user),
|
| 295 |
+
**tokens, # access_token, token_type, expires_in
|
| 296 |
},
|
| 297 |
}
|
| 298 |
|