# -*- coding: utf-8 -*- """ Application Configuration Module for MYP Platform ================================================ Flask configuration classes for different environments. """ import os from datetime import timedelta # Base configuration directory BASE_DIR = os.path.abspath(os.path.dirname(__file__)) PROJECT_ROOT = os.path.abspath(os.path.join(BASE_DIR, '..', '..')) class Config: """Base configuration class with common settings.""" # Secret key for Flask sessions and CSRF protection SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-secret-key-change-in-production-744563017196A' # Session configuration PERMANENT_SESSION_LIFETIME = timedelta(hours=24) SESSION_COOKIE_SECURE = False # Set to True in production with HTTPS SESSION_COOKIE_HTTPONLY = True SESSION_COOKIE_SAMESITE = 'Lax' # Database configuration DATABASE_URL = os.environ.get('DATABASE_URL') or f'sqlite:///{os.path.join(PROJECT_ROOT, "data", "myp_platform.db")}' SQLALCHEMY_DATABASE_URI = DATABASE_URL SQLALCHEMY_TRACK_MODIFICATIONS = False SQLALCHEMY_ENGINE_OPTIONS = { 'pool_pre_ping': True, 'pool_recycle': 300, } # Upload configuration UPLOAD_FOLDER = os.path.join(PROJECT_ROOT, 'uploads') MAX_CONTENT_LENGTH = 500 * 1024 * 1024 # 500MB max file size ALLOWED_EXTENSIONS = {'gcode', 'stl', 'obj', '3mf', 'amf'} # Security configuration WTF_CSRF_ENABLED = True WTF_CSRF_TIME_LIMIT = 3600 # 1 hour # Mail configuration (optional) MAIL_SERVER = os.environ.get('MAIL_SERVER') MAIL_PORT = int(os.environ.get('MAIL_PORT') or 587) MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS', 'true').lower() in ['true', 'on', '1'] MAIL_USERNAME = os.environ.get('MAIL_USERNAME') MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD') # Logging configuration LOG_LEVEL = os.environ.get('LOG_LEVEL', 'INFO') LOG_FILE_MAX_BYTES = 10 * 1024 * 1024 # 10MB LOG_BACKUP_COUNT = 5 # Application-specific settings SCHEDULER_ENABLED = os.environ.get('SCHEDULER_ENABLED', 'true').lower() in ['true', 'on', '1'] SCHEDULER_INTERVAL = int(os.environ.get('SCHEDULER_INTERVAL', '60')) # seconds # SSL/HTTPS configuration SSL_ENABLED = os.environ.get('SSL_ENABLED', 'false').lower() in ['true', 'on', '1'] SSL_CERT_PATH = os.environ.get('SSL_CERT_PATH') SSL_KEY_PATH = os.environ.get('SSL_KEY_PATH') # Network configuration DEFAULT_PORT = int(os.environ.get('PORT', '5000')) DEFAULT_HOST = os.environ.get('HOST', '0.0.0.0') @staticmethod def init_app(app): """Initialize application with this configuration.""" pass class DevelopmentConfig(Config): """Development environment configuration.""" DEBUG = True TESTING = False # More verbose logging in development LOG_LEVEL = 'DEBUG' # Disable some security features for easier development SESSION_COOKIE_SECURE = False WTF_CSRF_ENABLED = False # Disable CSRF for easier API testing @staticmethod def init_app(app): Config.init_app(app) # Development-specific initialization import logging logging.basicConfig(level=logging.DEBUG) class TestingConfig(Config): """Testing environment configuration.""" TESTING = True DEBUG = True # Use in-memory database for testing DATABASE_URL = 'sqlite:///:memory:' SQLALCHEMY_DATABASE_URI = DATABASE_URL # Disable CSRF for testing WTF_CSRF_ENABLED = False # Shorter session lifetime for testing PERMANENT_SESSION_LIFETIME = timedelta(minutes=5) @staticmethod def init_app(app): Config.init_app(app) class ProductionConfig(Config): """Production environment configuration.""" DEBUG = False TESTING = False # Strict security settings for production SESSION_COOKIE_SECURE = True # Requires HTTPS WTF_CSRF_ENABLED = True # Production logging LOG_LEVEL = 'WARNING' # SSL should be enabled in production SSL_ENABLED = True @staticmethod def init_app(app): Config.init_app(app) # Production-specific initialization import logging from logging.handlers import RotatingFileHandler # Set up file logging for production log_dir = os.path.join(os.path.dirname(app.instance_path), 'logs') if not os.path.exists(log_dir): os.makedirs(log_dir) file_handler = RotatingFileHandler( os.path.join(log_dir, 'myp_platform.log'), maxBytes=Config.LOG_FILE_MAX_BYTES, backupCount=Config.LOG_BACKUP_COUNT ) file_handler.setFormatter(logging.Formatter( '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]' )) file_handler.setLevel(logging.WARNING) app.logger.addHandler(file_handler) app.logger.setLevel(logging.WARNING) # Configuration dictionary for easy access config = { 'development': DevelopmentConfig, 'testing': TestingConfig, 'production': ProductionConfig, 'default': DevelopmentConfig } def get_config_by_name(config_name): """ Get configuration class by name. Args: config_name (str): Name of the configuration ('development', 'testing', 'production') Returns: Config: Configuration class """ return config.get(config_name, config['default'])