File size: 4,247 Bytes
7644eac 7362a57 7644eac 7362a57 7644eac 7362a57 7644eac 7362a57 a5cfef0 e7ac0a2 7362a57 e7ac0a2 7644eac 9b44947 7644eac 9b44947 7644eac 9b44947 7644eac e7ac0a2 7644eac |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
import os
import redis
from rq import Queue
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from flask_migrate import Migrate
from flask_cors import CORS
from flask_wtf.csrf import CSRFProtect
from config import Config
from werkzeug.middleware.proxy_fix import ProxyFix
db = SQLAlchemy()
login_manager = LoginManager()
login_manager.login_view = 'auth.login' # Route for @login_required
login_manager.login_message_category = 'info'
migrate = Migrate()
csrf = CSRFProtect()
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(config_class)
# If the app is running behind a proxy (like on Render or HF Spaces), fix the WSGI environment
if os.environ.get('RENDER') or os.environ.get('SPACE_ID'):
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1,
x_proto=1, x_host=1, x_prefix=1)
# Initialize CSRF protection
csrf.init_app(app)
# Exempt API endpoints from CSRF (they use token auth)
@csrf.exempt
def csrf_exempt_api():
pass
# Enable CORS for API routes only (not for auth pages)
# This allows requests from Codespace frontend and mobile app
allowed_origins = [
"http://localhost:3000", # React frontend
"http://localhost:8081", # Expo mobile app (web)
"http://127.0.0.1:3000",
"http://127.0.0.1:8081",
"http://localhost:19006", # Expo web
"http://127.0.0.1:19006",
"http://localhost:8082", # Expo web alternate
"http://127.0.0.1:8082",
]
# Add any additional origins from environment
extra_origin = os.environ.get('FRONTEND_ORIGIN')
if extra_origin and extra_origin not in allowed_origins:
allowed_origins.append(extra_origin)
# Apply CORS to /api/* and /auth/api/* routes for mobile app support
CORS(app,
resources={
r"/api/*": {"origins": "*"},
r"/auth/api/*": {"origins": "*"},
r"/health": {"origins": "*"}
},
methods=["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"],
allow_headers=["Content-Type", "Authorization", "X-Requested-With"],
supports_credentials=False,
max_age=3600)
# Set DEV_MODE from environment
app.config['DEV_MODE'] = os.environ.get(
'DEV_MODE', 'False').lower() == 'true'
if app.config['DEV_MODE']:
print("\033[93m⚠️ Running in DEV_MODE - API calls will be stubbed!\033[0m")
db.init_app(app)
login_manager.init_app(app)
migrate.init_app(app, db)
# Initialize Redis connection for RQ
try:
redis_url = os.environ.get('REDIS_URL')
if not redis_url:
raise ValueError(
"REDIS_URL not set, worker queue will not be available.")
# ssl_cert_reqs=None is important for managed services like Upstash/Render Redis
app.redis = redis.from_url(redis_url, ssl_cert_reqs=None)
app.logger.info("Redis connection for RQ initialized successfully.")
except Exception as e:
app.logger.error(f"Failed to initialize Redis connection: {e}")
app.redis = None
# Import and register blueprints
from web_app.main_routes import bp as main_bp
app.register_blueprint(main_bp)
from web_app.auth_routes import bp as auth_bp
app.register_blueprint(auth_bp, url_prefix='/auth')
from web_app.api_endpoints import api_bp
app.register_blueprint(api_bp)
# Assessment API blueprint
from web_app.assessment_routes import assessment_bp
app.register_blueprint(assessment_bp)
# Import models here to ensure they are registered with SQLAlchemy
from web_app import models
# Google OAuth blueprint (Flask-Dance)
from web_app.google_oauth import google_bp, bp as google_auth_bp
# Register Flask-Dance blueprint at /login/google
app.register_blueprint(google_bp, url_prefix="/login")
# Register our auth blueprint for callbacks and helper routes under /auth
app.register_blueprint(google_auth_bp, url_prefix="/auth")
# Flask-Dance will use session storage by default
# This works better for our use case since we create the user in our callback
return app
|