feat: add appointments, campaigns, admin, storage, tests and various updates

- Add new routers: admin, appointments, campaigns
- Add storage service and logging config
- Add migrations directory and test suite with pytest config
- Add supabase_migration_features.sql
- Update models, dependencies, config, and existing routers
- Remove whatsapp_service (deleted)
- Update pyproject.toml and uv.lock dependencies

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
belviskhoremk
2026-04-03 09:11:58 +00:00
parent 9dccc83293
commit 92d4c2fc5e
51 changed files with 7076 additions and 515 deletions

View File

@@ -29,7 +29,24 @@ async def get_current_user(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid or expired token",
)
return response.user
user = response.user
# Check for suspension
try:
profile = supabase.table("user_profiles").select("suspended_at").eq("user_id", user.id).execute()
if profile.data and profile.data[0].get("suspended_at"):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Account suspended. Please contact support.",
)
except HTTPException:
raise
except Exception:
pass # Don't block login if profile lookup fails
return user
except HTTPException:
raise
except Exception as e:
logger.error(f"Auth error: {e}")
raise HTTPException(
@@ -38,6 +55,29 @@ async def get_current_user(
)
async def get_admin_user(
current_user=Depends(get_current_user),
):
"""Require the current user to be an admin."""
supabase = get_supabase()
try:
profile = supabase.table("user_profiles").select("is_admin").eq("user_id", current_user.id).execute()
if not profile.data or not profile.data[0].get("is_admin"):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Admin access required",
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Admin check failed: {e}")
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Admin access required",
)
return current_user
async def get_optional_user(
credentials: Optional[HTTPAuthorizationCredentials] = Depends(security),
):