Skip to content

Commit 46c969e

Browse files
committed
fix(auth): enhance user existence check with cache-first lookup and Airtable fallback
1 parent d986c05 commit 46c969e

File tree

2 files changed

+19
-18
lines changed

2 files changed

+19
-18
lines changed

backend/podium/cache/operations.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -449,24 +449,25 @@ async def get_user_by_email(email: str, model: Type[TModel]) -> Optional[TModel]
449449
if user_id:
450450
# Try primary cache with the user_id
451451
user = await get_one(Entity.USERS, user_id, model)
452-
if user:
452+
if user and getattr(user, "email", "").lower().strip() == email:
453453
return user
454454

455455
# Fall back to Airtable query
456456
_mark_cache("MISS")
457-
try:
458-
loop = asyncio.get_event_loop()
459-
records = await loop.run_in_executor(None, tables[Entity.USERS].all, match({"email": email}))
460-
if not records:
461-
return None
462-
463-
fields = {**records[0]["fields"], "id": records[0]["id"]}
464-
validated = _to_model(model, fields)
465-
466-
# Cache both primary and secondary
467-
await _cache_save(Entity.USERS, validated.model_dump())
468-
await _cache_secondary_save(Entity.USERS, "email", email, validated.id)
469-
470-
return validated
471-
except Exception:
457+
loop = asyncio.get_event_loop()
458+
459+
def _fetch_by_email():
460+
return tables[Entity.USERS].all(formula=match({"email": email}))
461+
462+
records = await loop.run_in_executor(None, _fetch_by_email)
463+
if not records:
472464
return None
465+
466+
fields = {**records[0]["fields"], "id": records[0]["id"]}
467+
validated = _to_model(model, fields)
468+
469+
# Cache both primary and secondary
470+
await _cache_save(Entity.USERS, validated.model_dump())
471+
await _cache_secondary_save(Entity.USERS, "email", email, validated.id)
472+
473+
return validated

backend/podium/routers/users.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ class UserExistsResponse(BaseModel):
2323
@router.get("/exists")
2424
async def user_exists(email: Annotated[EmailStr, Query(...)]) -> UserExistsResponse:
2525
email = email.strip().lower()
26-
# Use cache-first lookup
27-
exists = True if await cache.get_by_formula(Entity.USERS, {"email": email}, UserInternal) else False
26+
# Use cache-first lookup with Airtable fallback (no tombstone check needed - we want to know if user exists)
27+
exists = True if await cache.get_user_by_email(email, UserInternal) else False
2828
return UserExistsResponse(exists=exists)
2929

3030

0 commit comments

Comments
 (0)