182 lines
5.5 KiB
Python
182 lines
5.5 KiB
Python
import os
|
|
from pathlib import Path
|
|
import urllib.parse
|
|
|
|
# Base directory for the project
|
|
BASE_DIR = Path(__file__).parent.parent.parent
|
|
|
|
|
|
class Config:
|
|
"""Base configuration class."""
|
|
|
|
# Database Configuration
|
|
SQLALCHEMY_DATABASE_URI = os.getenv(
|
|
"DATABASE_URL", f"sqlite:///{BASE_DIR}/data/scriptsmanager.db"
|
|
)
|
|
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
|
|
|
# PostgreSQL-specific database configuration
|
|
SQLALCHEMY_ENGINE_OPTIONS = {
|
|
'pool_size': 10,
|
|
'pool_timeout': 20,
|
|
'pool_recycle': -1,
|
|
'max_overflow': 0,
|
|
'pool_pre_ping': True,
|
|
}
|
|
|
|
# Additional database settings for PostgreSQL
|
|
SQLALCHEMY_ECHO = os.getenv("SQLALCHEMY_ECHO", "False").lower() == "true"
|
|
|
|
@staticmethod
|
|
def get_database_config():
|
|
"""Get database configuration based on DATABASE_URL."""
|
|
database_url = os.getenv("DATABASE_URL", f"sqlite:///{BASE_DIR}/data/scriptsmanager.db")
|
|
|
|
if database_url.startswith('postgresql://'):
|
|
# Parse PostgreSQL URL
|
|
parsed = urllib.parse.urlparse(database_url)
|
|
return {
|
|
'engine': 'postgresql',
|
|
'host': parsed.hostname,
|
|
'port': parsed.port or 5432,
|
|
'database': parsed.path[1:], # Remove leading slash
|
|
'username': parsed.username,
|
|
'password': parsed.password,
|
|
'url': database_url
|
|
}
|
|
else:
|
|
# SQLite configuration (fallback)
|
|
return {
|
|
'engine': 'sqlite',
|
|
'url': database_url,
|
|
'file': database_url.replace('sqlite:///', '')
|
|
}
|
|
|
|
# Application Settings
|
|
SECRET_KEY = os.getenv("SECRET_KEY", "your-secret-key-change-in-production")
|
|
DEBUG = os.getenv("DEBUG", "False").lower() == "true"
|
|
|
|
# Multi-user Settings
|
|
BASE_DATA_PATH = Path(os.getenv("BASE_DATA_PATH", "./data"))
|
|
MAX_PROJECTS_PER_USER = int(os.getenv("MAX_PROJECTS_PER_USER", "50"))
|
|
|
|
# Port Management
|
|
PORT_RANGE_START = int(os.getenv("PORT_RANGE_START", "5200"))
|
|
PORT_RANGE_END = int(os.getenv("PORT_RANGE_END", "5400"))
|
|
|
|
# Backup Configuration
|
|
BACKUP_ENABLED = os.getenv("BACKUP_ENABLED", "True").lower() == "true"
|
|
BACKUP_SCHEDULE_TIME = os.getenv("BACKUP_SCHEDULE_TIME", "02:00")
|
|
BACKUP_RETENTION_DAYS = int(os.getenv("BACKUP_RETENTION_DAYS", "30"))
|
|
|
|
# Conda Environment
|
|
CONDA_AUTO_DETECT = os.getenv("CONDA_AUTO_DETECT", "True").lower() == "true"
|
|
|
|
# Supported Languages
|
|
SUPPORTED_LANGUAGES = ["en", "es", "it", "fr"]
|
|
DEFAULT_LANGUAGE = os.getenv("DEFAULT_LANGUAGE", "en")
|
|
|
|
# Web Interface Management
|
|
WEB_INTERFACE_CONFIG = {
|
|
"port_range": {"start": PORT_RANGE_START, "end": PORT_RANGE_END},
|
|
"session_timeout": 1800,
|
|
"heartbeat_interval": 30,
|
|
"cleanup_interval": 300,
|
|
"max_concurrent_interfaces": 20,
|
|
"max_interfaces_per_user": 5,
|
|
}
|
|
|
|
# Documentation Settings
|
|
DOCUMENTATION_CONFIG = {
|
|
"markdown_extensions": ["codehilite", "tables", "toc", "math"],
|
|
"supported_languages": SUPPORTED_LANGUAGES,
|
|
"default_language": DEFAULT_LANGUAGE,
|
|
"enable_math_rendering": True,
|
|
"enable_diagram_rendering": False,
|
|
}
|
|
|
|
# Tagging Configuration
|
|
TAGGING_CONFIG = {
|
|
"max_tags_per_script": 20,
|
|
"max_tag_length": 30,
|
|
"allowed_tag_chars": "alphanumeric_underscore_dash",
|
|
"enable_tag_suggestions": True,
|
|
}
|
|
|
|
# Security Settings
|
|
SECURITY_CONFIG = {
|
|
"data_directory_permissions": "755",
|
|
"config_file_permissions": "644",
|
|
"enable_project_sharing": False,
|
|
"admin_can_access_all_data": True,
|
|
}
|
|
|
|
|
|
class DevelopmentConfig(Config):
|
|
"""Development configuration."""
|
|
|
|
DEBUG = True
|
|
|
|
# Development-specific database settings
|
|
SQLALCHEMY_ENGINE_OPTIONS = {
|
|
'pool_size': 5,
|
|
'pool_timeout': 10,
|
|
'pool_recycle': 300,
|
|
'max_overflow': 0,
|
|
'pool_pre_ping': True,
|
|
'echo': True, # Log SQL queries in development
|
|
}
|
|
|
|
|
|
class ProductionConfig(Config):
|
|
"""Production configuration."""
|
|
|
|
DEBUG = False
|
|
|
|
# Production-specific database settings with connection pooling
|
|
SQLALCHEMY_ENGINE_OPTIONS = {
|
|
'pool_size': 20,
|
|
'pool_timeout': 30,
|
|
'pool_recycle': 3600, # Recycle connections every hour
|
|
'max_overflow': 10,
|
|
'pool_pre_ping': True,
|
|
'echo': False, # Disable SQL logging in production
|
|
}
|
|
|
|
# Production security enhancements
|
|
SECURITY_CONFIG = {
|
|
**Config.SECURITY_CONFIG,
|
|
"enable_project_sharing": True, # Enable in production
|
|
"session_cookie_secure": True,
|
|
"session_cookie_httponly": True,
|
|
"session_cookie_samesite": "Lax",
|
|
}
|
|
|
|
|
|
class TestingConfig(Config):
|
|
"""Testing configuration."""
|
|
|
|
TESTING = True
|
|
SQLALCHEMY_DATABASE_URI = "sqlite:///:memory:"
|
|
|
|
# Testing-specific settings
|
|
SQLALCHEMY_ENGINE_OPTIONS = {
|
|
'pool_size': 1,
|
|
'pool_timeout': 5,
|
|
'pool_recycle': -1,
|
|
'max_overflow': 0,
|
|
'pool_pre_ping': False,
|
|
}
|
|
|
|
# Disable backup in testing
|
|
BACKUP_ENABLED = False
|
|
|
|
|
|
# Configuration dictionary
|
|
config = {
|
|
"development": DevelopmentConfig,
|
|
"production": ProductionConfig,
|
|
"testing": TestingConfig,
|
|
"default": DevelopmentConfig,
|
|
}
|