destinyebuka commited on
Commit
4cde766
·
1 Parent(s): 448a5b1
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. respond(message: str)
 
 
 
 
 
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 = 15 # Short-lived access token (15 min)
54
- JWT_REFRESH_EXPIRY_DAYS: int = 30 # Long-lived refresh token (30 days)
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 both access and refresh tokens for login.
236
- Returns dict with both tokens.
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"Token pair created for user: {user_id}")
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
- from pydantic import BaseModel
185
-
186
- class RefreshTokenDto(BaseModel):
187
- refresh_token: str
188
 
189
- @router.post("/refresh", status_code=status.HTTP_200_OK)
190
- async def refresh_tokens(dto: RefreshTokenDto):
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 + refresh)
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, refresh_token, token_type, expires_in
216
  },
217
  }
218
 
@@ -277,7 +277,7 @@ class AuthService:
277
  {"$set": {"lastLogin": now, "updatedAt": now}}
278
  )
279
 
280
- # Generate token pair (access + refresh)
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, refresh_token, token_type, expires_in
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