""" Quality App v2 - Flask Application Factory Robust, modular application with login, dashboard, and multiple modules """ from flask import Flask from flask_session import Session from datetime import datetime, timedelta import os import logging from logging.handlers import RotatingFileHandler def create_app(config=None): """ Application factory function Creates and configures the Flask application """ app = Flask(__name__) # Load configuration if config is None: from app.config import Config config = Config app.config.from_object(config) # Setup logging setup_logging(app) logger = logging.getLogger(__name__) logger.info("=" * 80) logger.info("Flask App Initialization Started") logger.info("=" * 80) # Configure session app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(hours=8) app.config['SESSION_COOKIE_SECURE'] = False # Set True in production with HTTPS app.config['SESSION_COOKIE_HTTPONLY'] = True app.config['SESSION_COOKIE_SAMESITE'] = 'Lax' app.config['SESSION_COOKIE_NAME'] = 'quality_app_session' app.config['SESSION_REFRESH_EACH_REQUEST'] = True # Use filesystem for session storage (works with multiple gunicorn workers) sessions_dir = os.path.join(app.config.get('LOG_DIR', '/app/data/logs'), '..', 'sessions') os.makedirs(sessions_dir, exist_ok=True) app.config['SESSION_TYPE'] = 'filesystem' app.config['SESSION_FILE_DIR'] = sessions_dir app.config['SESSION_FILE_THRESHOLD'] = 500 # Initialize Flask-Session Session(app) # Initialize database connection logger.info("Initializing database connection...") from app.database import init_db, close_db init_db(app) app.teardown_appcontext(close_db) # Register blueprints logger.info("Registering blueprints...") register_blueprints(app) # Register error handlers logger.info("Registering error handlers...") register_error_handlers(app) # Add template globals app.jinja_env.globals['now'] = datetime.now # Add context processor for app name @app.context_processor def inject_app_settings(): """Inject app settings into all templates""" try: from app.database import get_db conn = get_db() cursor = conn.cursor() cursor.execute( "SELECT setting_value FROM application_settings WHERE setting_key = %s", ('app_name',) ) result = cursor.fetchone() cursor.close() app_name = result[0] if result else 'Quality App v2' except: app_name = 'Quality App v2' return {'app_name': app_name} # Add before_request handlers register_request_handlers(app) # Initialize backup scheduler logger.info("Initializing backup scheduler...") try: from app.scheduler import init_scheduler init_scheduler(app) except Exception as e: logger.error(f"Failed to initialize backup scheduler: {e}") logger.info("=" * 80) logger.info("Flask App Initialization Completed Successfully") logger.info("=" * 80) return app def setup_logging(app): """Configure application logging""" log_dir = app.config.get('LOG_DIR', '/app/data/logs') # Create log directory if it doesn't exist if not os.path.exists(log_dir): os.makedirs(log_dir, exist_ok=True) # Configure rotating file handler log_file = os.path.join(log_dir, 'app.log') handler = RotatingFileHandler( log_file, maxBytes=10485760, # 10MB backupCount=10 ) # Create formatter formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) handler.setFormatter(formatter) # Set logging level log_level = app.config.get('LOG_LEVEL', 'INFO') handler.setLevel(getattr(logging, log_level)) # Add handler to app logger app.logger.addHandler(handler) app.logger.setLevel(getattr(logging, log_level)) def register_blueprints(app): """Register application blueprints""" from app.routes import main_bp from app.modules.quality.routes import quality_bp from app.modules.settings.routes import settings_bp from app.modules.warehouse.routes import warehouse_bp from app.modules.warehouse.boxes_routes import boxes_bp app.register_blueprint(main_bp) app.register_blueprint(quality_bp, url_prefix='/quality') app.register_blueprint(settings_bp, url_prefix='/settings') app.register_blueprint(warehouse_bp, url_prefix='/warehouse') app.register_blueprint(boxes_bp) app.logger.info("Blueprints registered: main, quality, settings, warehouse, boxes") def register_error_handlers(app): """Register error handlers""" @app.errorhandler(404) def page_not_found(e): from flask import render_template return render_template('errors/404.html'), 404 @app.errorhandler(500) def internal_error(e): from flask import render_template app.logger.error(f"Internal error: {e}") return render_template('errors/500.html'), 500 @app.errorhandler(403) def forbidden(e): from flask import render_template return render_template('errors/403.html'), 403 def register_request_handlers(app): """Register before/after request handlers""" @app.before_request def before_request(): """Handle pre-request logic""" from flask import session, request, redirect, url_for # Skip authentication check for login and static files if request.endpoint and ( request.endpoint in ['static', 'main.login', 'main.index'] or request.path.startswith('/static/') ): return None # Check if user is logged in if 'user_id' not in session: return redirect(url_for('main.login')) return None @app.after_request def after_request(response): """Handle post-request logic""" return response