kamau1 commited on
Commit
52d9d84
Β·
1 Parent(s): 5d0b34b

fix: add missing Response param to all rate-limited OTP endpoints to resolve slowapi decorator errors

Browse files
docs/hflogs/runtimeerror.txt CHANGED
@@ -1,33 +1,70 @@
1
- ===== Application Startup at 2025-11-16 12:09:02 =====
2
 
3
- INFO: Started server process [7]
4
  INFO: Waiting for application startup.
5
- INFO: 2025-11-16T12:09:12 - app.main: ============================================================
6
- INFO: 2025-11-16T12:09:12 - app.main: πŸš€ SwiftOps API v1.0.0 | PRODUCTION
7
- INFO: 2025-11-16T12:09:12 - app.main: ============================================================
8
- INFO: 2025-11-16T12:09:12 - app.main: πŸ“¦ Database:
9
- INFO: 2025-11-16T12:09:16 - app.main: βœ“ Connected | 42 tables | 10 users
10
- INFO: 2025-11-16T12:09:16 - app.main: πŸ’Ύ Cache & Sessions:
11
- INFO: 2025-11-16T12:09:17 - app.services.otp_service: βœ… OTP Service initialized with Redis storage
12
- INFO: 2025-11-16T12:09:17 - app.main: βœ“ Redis: Connected
13
- INFO: 2025-11-16T12:09:17 - app.main: πŸ”Œ External Services:
14
- INFO: 2025-11-16T12:09:18 - app.main: βœ“ Cloudinary: Connected
15
- INFO: 2025-11-16T12:09:18 - app.main: βœ“ Resend: Configured
16
- INFO: 2025-11-16T12:09:18 - app.main: βœ“ WASender: Connected
17
- INFO: 2025-11-16T12:09:18 - app.main: βœ“ Supabase: Connected | 6 buckets
18
- INFO: 2025-11-16T12:09:18 - app.main: ============================================================
19
- INFO: 2025-11-16T12:09:18 - app.main: βœ… Startup complete | Ready to serve requests
20
- INFO: 2025-11-16T12:09:18 - app.main: ============================================================
21
  INFO: Application startup complete.
22
  INFO: Uvicorn running on http://0.0.0.0:7860 (Press CTRL+C to quit)
23
- INFO: 10.16.6.135:21683 - "GET /health HTTP/1.1" 200 OK
24
- INFO: 2025-11-16T12:11:47 - app.services.otp_service: OTP sent via whatsapp for password_reset (storage: redis)
25
- ERROR: 2025-11-16T12:11:48 - app.services.otp_service: Failed to send OTP: (psycopg2.errors.InvalidTextRepresentation) invalid input value for enum auditaction: "otp_sent"
26
- LINE 1: ...f4c9737343b'::uuid::UUID, NULL::UUID, NULL, NULL, 'otp_sent'...
27
- ^
28
-
29
- [SQL: INSERT INTO audit_logs (id, user_id, user_email, user_role, action, entity_type, entity_id, description, changes, ip_address, user_agent, request_id, latitude, longitude, additional_metadata, created_at) VALUES (%(id)s::UUID, %(user_id)s::UUID, %(user_email)s, %(user_role)s, %(action)s, %(entity_type)s, %(entity_id)s::UUID, %(description)s, %(changes)s, %(ip_address)s, %(user_agent)s, %(request_id)s, %(latitude)s, %(longitude)s, %(additional_metadata)s, %(created_at)s)]
30
- [parameters: {'id': UUID('9ae9e1ef-8b0c-4dc7-959a-4f4c9737343b'), 'user_id': None, 'user_email': None, 'user_role': None, 'action': 'otp_sent', 'entity_type': 'otp', 'entity_id': None, 'description': 'OTP sent via whatsapp for password_reset', 'changes': '{}', 'ip_address': None, 'user_agent': None, 'request_id': None, 'latitude': None, 'longitude': None, 'additional_metadata': '"{\\"purpose\\": \\"password_reset\\", \\"delivery_method\\": \\"whatsapp\\", \\"masked_contact\\": \\"l***y@example.com\\", \\"storage_type\\": \\"redis\\"}"', 'created_at': '2025-11-16T12:11:48.027066'}]
31
- (Background on this error at: https://sqlalche.me/e/20/9h9h)
32
- INFO: 10.16.39.23:4464 - "GET /?logs=container HTTP/1.1" 200 OK
33
- INFO: 10.16.6.135:1179 - "POST /api/v1/otp/send-public HTTP/1.1" 500 Internal Server Error
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ===== Application Startup at 2025-11-16 12:16:24 =====
2
 
3
+ INFO: Started server process [8]
4
  INFO: Waiting for application startup.
5
+ INFO: 2025-11-16T12:16:33 - app.main: ============================================================
6
+ INFO: 2025-11-16T12:16:33 - app.main: πŸš€ SwiftOps API v1.0.0 | PRODUCTION
7
+ INFO: 2025-11-16T12:16:33 - app.main: ============================================================
8
+ INFO: 2025-11-16T12:16:33 - app.main: πŸ“¦ Database:
9
+ INFO: 2025-11-16T12:16:37 - app.main: βœ“ Connected | 42 tables | 10 users
10
+ INFO: 2025-11-16T12:16:37 - app.main: πŸ’Ύ Cache & Sessions:
11
+ INFO: 2025-11-16T12:16:38 - app.services.otp_service: βœ… OTP Service initialized with Redis storage
12
+ INFO: 2025-11-16T12:16:38 - app.main: βœ“ Redis: Connected
13
+ INFO: 2025-11-16T12:16:38 - app.main: πŸ”Œ External Services:
14
+ INFO: 2025-11-16T12:16:39 - app.main: βœ“ Cloudinary: Connected
15
+ INFO: 2025-11-16T12:16:39 - app.main: βœ“ Resend: Configured
16
+ INFO: 2025-11-16T12:16:39 - app.main: βœ“ WASender: Connected
17
+ INFO: 2025-11-16T12:16:39 - app.main: βœ“ Supabase: Connected | 6 buckets
18
+ INFO: 2025-11-16T12:16:39 - app.main: ============================================================
19
+ INFO: 2025-11-16T12:16:39 - app.main: βœ… Startup complete | Ready to serve requests
20
+ INFO: 2025-11-16T12:16:39 - app.main: ============================================================
21
  INFO: Application startup complete.
22
  INFO: Uvicorn running on http://0.0.0.0:7860 (Press CTRL+C to quit)
23
+ INFO: 10.16.39.23:21217 - "GET /health HTTP/1.1" 200 OK
24
+ INFO: 2025-11-16T12:17:25 - app.services.otp_service: OTP sent via whatsapp for password_reset (storage: redis)
25
+ INFO: 2025-11-16T12:17:26 - app.services.audit_service: Audit log created: create on otp by system
26
+ INFO: 10.16.39.23:46042 - "POST /api/v1/otp/send-public HTTP/1.1" 500 Internal Server Error
27
+ ERROR: Exception in ASGI application
28
+ Traceback (most recent call last):
29
+ File "/usr/local/lib/python3.11/site-packages/uvicorn/protocols/http/httptools_impl.py", line 426, in run_asgi
30
+ result = await app( # type: ignore[func-returns-value]
31
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
32
+ File "/usr/local/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__
33
+ return await self.app(scope, receive, send)
34
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
35
+ File "/usr/local/lib/python3.11/site-packages/fastapi/applications.py", line 1106, in __call__
36
+ await super().__call__(scope, receive, send)
37
+ File "/usr/local/lib/python3.11/site-packages/starlette/applications.py", line 122, in __call__
38
+ await self.middleware_stack(scope, receive, send)
39
+ File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 184, in __call__
40
+ raise exc
41
+ File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 162, in __call__
42
+ await self.app(scope, receive, _send)
43
+ File "/usr/local/lib/python3.11/site-packages/starlette/middleware/cors.py", line 83, in __call__
44
+ await self.app(scope, receive, send)
45
+ File "/usr/local/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
46
+ raise exc
47
+ File "/usr/local/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
48
+ await self.app(scope, receive, sender)
49
+ File "/usr/local/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 20, in __call__
50
+ raise e
51
+ File "/usr/local/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 17, in __call__
52
+ await self.app(scope, receive, send)
53
+ File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 718, in __call__
54
+ await route.handle(scope, receive, send)
55
+ File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 276, in handle
56
+ await self.app(scope, receive, send)
57
+ File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 66, in app
58
+ response = await func(request)
59
+ ^^^^^^^^^^^^^^^^^^^
60
+ File "/usr/local/lib/python3.11/site-packages/fastapi/routing.py", line 274, in app
61
+ raw_response = await run_endpoint_function(
62
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
63
+ File "/usr/local/lib/python3.11/site-packages/fastapi/routing.py", line 191, in run_endpoint_function
64
+ return await dependant.call(**values)
65
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
+ File "/usr/local/lib/python3.11/site-packages/slowapi/extension.py", line 738, in async_wrapper
67
+ self._inject_headers(
68
+ File "/usr/local/lib/python3.11/site-packages/slowapi/extension.py", line 382, in _inject_headers
69
+ raise Exception(
70
+ Exception: parameter `response` must be an instance of starlette.responses.Response
src/app/api/v1/otp.py CHANGED
@@ -2,7 +2,7 @@
2
  OTP (One-Time Password) Endpoints
3
  For verification codes via email, WhatsApp, or SMS
4
  """
5
- from fastapi import APIRouter, Depends, HTTPException, status, Request
6
  from sqlalchemy.orm import Session
7
 
8
  from app.api.deps import get_db, get_current_active_user
@@ -32,6 +32,7 @@ def get_otp_service() -> OTPService:
32
  @limiter.limit("5/hour") # 5 OTP requests per hour
33
  async def send_otp(
34
  request: Request,
 
35
  otp_request: OTPRequest,
36
  current_user: User = Depends(get_current_active_user),
37
  db: Session = Depends(get_db)
@@ -94,6 +95,7 @@ async def send_otp(
94
  @limiter.limit("10/hour") # 10 verification attempts per hour
95
  async def verify_otp(
96
  request: Request,
 
97
  otp_verify: OTPVerify,
98
  current_user: User = Depends(get_current_active_user),
99
  db: Session = Depends(get_db)
@@ -143,6 +145,7 @@ async def verify_otp(
143
  @limiter.limit("3/hour") # 3 OTP requests per hour per IP
144
  async def send_otp_public(
145
  request: Request,
 
146
  otp_request: OTPRequest,
147
  db: Session = Depends(get_db)
148
  ):
@@ -208,6 +211,7 @@ async def send_otp_public(
208
  @limiter.limit("5/hour") # 5 verification attempts per hour per IP
209
  async def verify_otp_public(
210
  request: Request,
 
211
  otp_verify: OTPVerify,
212
  db: Session = Depends(get_db)
213
  ):
 
2
  OTP (One-Time Password) Endpoints
3
  For verification codes via email, WhatsApp, or SMS
4
  """
5
+ from fastapi import APIRouter, Depends, HTTPException, status, Request, Response
6
  from sqlalchemy.orm import Session
7
 
8
  from app.api.deps import get_db, get_current_active_user
 
32
  @limiter.limit("5/hour") # 5 OTP requests per hour
33
  async def send_otp(
34
  request: Request,
35
+ response: Response,
36
  otp_request: OTPRequest,
37
  current_user: User = Depends(get_current_active_user),
38
  db: Session = Depends(get_db)
 
95
  @limiter.limit("10/hour") # 10 verification attempts per hour
96
  async def verify_otp(
97
  request: Request,
98
+ response: Response,
99
  otp_verify: OTPVerify,
100
  current_user: User = Depends(get_current_active_user),
101
  db: Session = Depends(get_db)
 
145
  @limiter.limit("3/hour") # 3 OTP requests per hour per IP
146
  async def send_otp_public(
147
  request: Request,
148
+ response: Response,
149
  otp_request: OTPRequest,
150
  db: Session = Depends(get_db)
151
  ):
 
211
  @limiter.limit("5/hour") # 5 verification attempts per hour per IP
212
  async def verify_otp_public(
213
  request: Request,
214
+ response: Response,
215
  otp_verify: OTPVerify,
216
  db: Session = Depends(get_db)
217
  ):