| from fastapi import FastAPI, HTTPException |
| from fastapi.staticfiles import StaticFiles |
| from fastapi.responses import FileResponse |
| from pydantic import BaseModel, Field |
| from database.supabase_manager import SupabaseManager |
| from services.scheduler import DailyChallengeScheduler |
| from services.challenge_agent import ChallengeAgentService |
| from services.challenge_service import challenge_service |
| from config.settings import settings |
| from utils.logger import configure_app_logging |
| from utils.error_handler import StandardAPIResponse, create_http_exception |
|
|
| |
| logger = configure_app_logging() |
|
|
| |
| class UserRegistrationRequest(BaseModel): |
| """Request model for user registration.""" |
| email: str = Field(description="User's email address") |
| preferences: str = Field(description="User's challenge preferences in natural language") |
|
|
| class UserToggleRequest(BaseModel): |
| """Request model for toggling user active status.""" |
| email: str = Field(description="User's email address") |
| active: bool = Field(description="Whether notifications should be active") |
|
|
| class TestNotificationRequest(BaseModel): |
| """Request model for test notifications.""" |
| email: str = Field(description="User's email address") |
| preferences: str = Field(description="User's challenge preferences for testing") |
|
|
| app = FastAPI(title="Topcoder Challenge Steward Agent", version="1.0.0") |
|
|
| |
| app.mount("/static", StaticFiles(directory="static"), name="static") |
|
|
| @app.get("/") |
| def serve_index(): |
| return FileResponse("static/index.html") |
|
|
| @app.post("/api/topcoder-dry-run") |
| def topcoder_dry_run(request: dict): |
| """Dry run endpoint showing Topcoder MCP server integration with JSON response""" |
| try: |
| |
| user_preferences = request.get("preferences", "") |
| logger.info(f"Dry run request with preferences: {user_preferences}") |
| |
| |
| result = challenge_service.get_challenges_dry_run(user_preferences) |
| |
| |
| if result.get("success"): |
| |
| challenges = result.get("data", {}).get("challenges", []) |
| return {"challenges": challenges} |
| else: |
| |
| return { |
| "error": result.get("error", "Unknown error occurred"), |
| "raw_response": result |
| } |
| |
| except Exception as e: |
| logger.error(f"Error in topcoder_dry_run: {e}") |
| return {"error": f"Topcoder dry run failed: {str(e)}"} |
|
|
| |
|
|
| |
| supabase_manager = SupabaseManager() |
| challenge_agent_service = ChallengeAgentService() |
| daily_scheduler = DailyChallengeScheduler() |
|
|
| @app.post("/api/register-user") |
| async def register_user(request: UserRegistrationRequest): |
| """Register a user with email and preferences for challenge notifications""" |
| try: |
| logger.info(f"Registering user: {request.email}") |
| |
| user_data = await supabase_manager.save_user_preferences( |
| email=request.email, |
| preferences=request.preferences |
| ) |
| |
| |
| actual_user = await supabase_manager.get_user_by_email(request.email) |
| |
| return { |
| "success": True, |
| "message": "User registered successfully", |
| "user": { |
| "email": request.email, |
| "preferences": request.preferences, |
| "active": actual_user.get("active", True) if actual_user else True |
| } |
| } |
| |
| except Exception as e: |
| logger.error(f"Error registering user: {e}") |
| raise HTTPException(status_code=500, detail=f"Failed to register user: {str(e)}") |
|
|
| @app.post("/api/toggle-user") |
| async def toggle_user_active(request: UserToggleRequest): |
| """Toggle user's active status for notifications""" |
| try: |
| logger.info(f"Toggling user {request.email} to active={request.active}") |
| |
| success = await supabase_manager.toggle_user_active( |
| email=request.email, |
| active=request.active |
| ) |
| |
| if success: |
| action = "activated" if request.active else "deactivated" |
| return { |
| "success": True, |
| "message": f"User notifications {action} successfully" |
| } |
| else: |
| raise HTTPException(status_code=404, detail="User not found") |
| |
| except HTTPException: |
| |
| raise |
| except Exception as e: |
| logger.error(f"Error toggling user status: {e}") |
| raise HTTPException(status_code=500, detail=f"Failed to toggle user status: {str(e)}") |
|
|
| @app.post("/api/update-preferences") |
| async def update_user_preferences(request: UserRegistrationRequest): |
| """Update existing user's preferences""" |
| try: |
| logger.info(f"Updating preferences for user: {request.email}") |
| |
| |
| existing_user = await supabase_manager.get_user_by_email(request.email) |
| if not existing_user: |
| raise HTTPException(status_code=404, detail="User not found") |
| |
| user_data = await supabase_manager.save_user_preferences( |
| email=request.email, |
| preferences=request.preferences |
| ) |
| |
| return { |
| "success": True, |
| "message": "User preferences updated successfully", |
| "user": { |
| "email": request.email, |
| "preferences": request.preferences, |
| "active": existing_user.get("active", True) |
| } |
| } |
| |
| except HTTPException: |
| raise |
| except Exception as e: |
| logger.error(f"Error updating user preferences: {e}") |
| raise HTTPException(status_code=500, detail=f"Failed to update user preferences: {str(e)}") |
|
|
| @app.get("/api/user/{email}") |
| async def get_user(email: str): |
| """Get user information by email""" |
| try: |
| user = await supabase_manager.get_user_by_email(email) |
| |
| if user: |
| return { |
| "success": True, |
| "user": user |
| } |
| else: |
| raise HTTPException(status_code=404, detail="User not found") |
| |
| except HTTPException: |
| |
| raise |
| except Exception as e: |
| logger.error(f"Error getting user: {e}") |
| raise HTTPException(status_code=500, detail=f"Failed to get user: {str(e)}") |
|
|
| @app.post("/api/trigger-daily-notifications") |
| async def trigger_daily_notifications(): |
| """Manually trigger daily notifications for testing""" |
| try: |
| logger.info("Manually triggering daily notifications") |
| |
| await daily_scheduler.run_now_for_testing() |
| |
| return { |
| "success": True, |
| "message": "Daily notifications triggered successfully" |
| } |
| |
| except Exception as e: |
| logger.error(f"Error triggering daily notifications: {e}") |
| raise HTTPException(status_code=500, detail=f"Failed to trigger daily notifications: {str(e)}") |
|
|
| |
| @app.on_event("startup") |
| async def startup_event(): |
| """Initialize the daily challenge scheduler on app startup""" |
| try: |
| logger.info("Starting up Topcoder Challenge Steward Agent") |
| logger.info("Initializing daily challenge scheduler...") |
| |
| |
| daily_scheduler.start_scheduler() |
| logger.info("🚀 Topcoder Challenge Steward Agent is running at http://localhost:8000/") |
| |
| except Exception as e: |
| logger.error(f"Error during startup: {e}") |
|
|
| @app.on_event("shutdown") |
| async def shutdown_event(): |
| """Clean up on app shutdown""" |
| try: |
| logger.info("Shutting down Topcoder Challenge Steward Agent") |
| daily_scheduler.stop_scheduler() |
| logger.info("Application shutdown completed successfully") |
| |
| except Exception as e: |
| logger.error(f"Error during shutdown: {e}") |
|
|