Proxies GET /customers/{uuid} to Novi AMS server-to-server so members'
browser IPs are no longer in the call path, eliminating false "Access
Denied" for users on hotel/conference WiFi, VPNs, and CDN-filtered nets.
- New router: GET /v3/action/idaa/novi_member/{uuid}
- Business logic in app/methods/idaa_novi_verify_methods.py
- Redis cache (4h TTL, key: idaa:novi_member:{uuid})
- 404 never cached (recently-joined member anti-pattern)
- Email space→+ normalization (Novi quirk)
- Display name: "FirstName L." format with Name field fallback
- Registered in registry.py under /v3/action/idaa tag
- 9 unit tests covering all response paths (200/404/429/503/unreachable,
cache hit, email normalization, display name format)
- Frontend guide (Section 12) and tests/README updated with full spec
and migration table for frontend hand-off
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
42 lines
1.4 KiB
Python
42 lines
1.4 KiB
Python
import asyncio
|
|
|
|
from fastapi import APIRouter, Depends
|
|
|
|
from app.lib_general_v3 import AccountContext, get_account_context, DelayParams
|
|
from app.models.response_models import Resp_Body_Base, mk_resp
|
|
from app.methods.idaa_novi_verify_methods import verify_novi_member
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get('/novi_member/{uuid}', response_model=Resp_Body_Base)
|
|
async def get_novi_member_verification(
|
|
uuid: str,
|
|
account: AccountContext = Depends(get_account_context),
|
|
delay: DelayParams = Depends(),
|
|
):
|
|
"""
|
|
Proxy Novi AMS member lookup server-to-server.
|
|
Returns verified member identity or an appropriate error code.
|
|
"""
|
|
if delay.sleep_time_s > 0:
|
|
await asyncio.sleep(delay.sleep_time_s)
|
|
|
|
result = verify_novi_member(uuid)
|
|
status = result.get('status', 503)
|
|
|
|
if status == 200:
|
|
return mk_resp(data={
|
|
'verified': result['verified'],
|
|
'full_name': result['full_name'],
|
|
'email': result['email'],
|
|
})
|
|
|
|
if status == 404:
|
|
return mk_resp(data=False, status_code=404, status_message=result.get('reason', 'Member not found.'))
|
|
|
|
if status == 429:
|
|
return mk_resp(data=False, status_code=429, status_message=result.get('reason', 'Novi rate limit exceeded.'))
|
|
|
|
return mk_resp(data=False, status_code=503, status_message=result.get('reason', 'Novi API unavailable.'))
|