2af04e1db3
- Content model: add url column + is_weblink() for web page content items - Player model: add deployment tracking fields (status, timestamps, message) - Content blueprint: add add_weblink and add_weblink_to_playlist routes; weblinks auto-deleted when removed from playlist - Players blueprint: add SSH deploy mode in add_player; weblink-aware playlist - API blueprint: weblink URL served directly in playlist response; add /api/deploy/test-ssh and /api/deploy/player endpoints - Admin blueprint: add build-player page (clone from Gitea, write base config); replace nginx status card with Caddy status on HTTPS config page - caddy_manager: rewritten to generate proper HTTPS/internal-CA Caddyfiles and reload Caddy via admin API (/load) for live config updates - ssh_deploy, background_tasks, player_build: new utils for SSH deployment - background_tasks: push Flask app context into background thread so DB updates after deployment complete correctly - ssh_deploy: robust install script detection with passwordless sudo injection (uses SSH credentials, cleaned up after install) - Dockerfile: add git, sshpass, openssh-client, rsync - docker-compose: switch nginx to Caddy on ports 80/443; add port 5000 for dev - Templates: add_player deploy mode UI, weblink form in playlist/upload pages, build_player admin page, Caddy status on HTTPS config page - Migrations: add_url_to_content, add_deployment_fields_to_player - app.py: call db.create_all() on startup for schema bootstrap - config.py: add PLAYER_CODE_DIR and PLAYER_REPO_URL settings
132 lines
3.7 KiB
Python
132 lines
3.7 KiB
Python
"""
|
|
Configuration settings for DigiServer v2
|
|
Environment-based configuration with sensible defaults
|
|
"""
|
|
import os
|
|
from datetime import timedelta
|
|
|
|
|
|
class Config:
|
|
"""Base configuration"""
|
|
|
|
# Basic Flask config
|
|
SECRET_KEY = os.getenv('SECRET_KEY', 'dev-secret-key-change-in-production')
|
|
|
|
# Database
|
|
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
|
SQLALCHEMY_ECHO = False
|
|
|
|
# File Upload - use absolute paths
|
|
MAX_CONTENT_LENGTH = 2048 * 1024 * 1024 # 2GB
|
|
_basedir = os.path.abspath(os.path.dirname(__file__))
|
|
UPLOAD_FOLDER = os.path.join(_basedir, 'static', 'uploads')
|
|
UPLOAD_FOLDERLOGO = os.path.join(_basedir, 'static', 'resurse')
|
|
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'bmp', 'mp4', 'avi', 'mkv', 'mov', 'webm', 'pdf', 'ppt', 'pptx'}
|
|
|
|
# Session
|
|
PERMANENT_SESSION_LIFETIME = timedelta(minutes=30)
|
|
SESSION_COOKIE_SECURE = False # Set to True in production with HTTPS
|
|
SESSION_COOKIE_HTTPONLY = True
|
|
SESSION_COOKIE_SAMESITE = 'Lax'
|
|
|
|
# Reverse proxy trust (for Nginx/Caddy with ProxyFix middleware)
|
|
# These are set by werkzeug.middleware.proxy_fix
|
|
TRUSTED_PROXIES = os.getenv('TRUSTED_PROXIES', '127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16')
|
|
PREFERRED_URL_SCHEME = os.getenv('PREFERRED_URL_SCHEME', 'https')
|
|
|
|
# Cache
|
|
SEND_FILE_MAX_AGE_DEFAULT = 300 # 5 minutes for static files
|
|
|
|
# Server Info
|
|
SERVER_VERSION = "2.0.0"
|
|
BUILD_DATE = "2025-11-12"
|
|
|
|
# Pagination
|
|
ITEMS_PER_PAGE = 20
|
|
|
|
# Admin defaults
|
|
DEFAULT_ADMIN_USER = os.getenv('ADMIN_USER', 'admin')
|
|
DEFAULT_ADMIN_PASSWORD = os.getenv('ADMIN_PASSWORD', 'Initial01!')
|
|
|
|
# Player deployment — staged code directory and default repo
|
|
PLAYER_CODE_DIR = os.getenv('PLAYER_CODE_DIR', '/app/data/player')
|
|
PLAYER_REPO_URL = os.getenv('PLAYER_REPO_URL', '')
|
|
|
|
|
|
class DevelopmentConfig(Config):
|
|
"""Development configuration"""
|
|
|
|
DEBUG = True
|
|
TESTING = False
|
|
|
|
# Database - construct absolute path
|
|
_basedir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
|
|
SQLALCHEMY_DATABASE_URI = os.getenv(
|
|
'DATABASE_URL',
|
|
f'sqlite:///{os.path.join(_basedir, "instance", "dev.db")}'
|
|
)
|
|
|
|
# Cache (simple in-memory for development)
|
|
CACHE_TYPE = 'simple'
|
|
CACHE_DEFAULT_TIMEOUT = 60
|
|
|
|
# Security (relaxed for development)
|
|
WTF_CSRF_ENABLED = True
|
|
WTF_CSRF_TIME_LIMIT = None
|
|
|
|
|
|
class ProductionConfig(Config):
|
|
"""Production configuration"""
|
|
|
|
DEBUG = False
|
|
TESTING = False
|
|
TEMPLATES_AUTO_RELOAD = True # Force template reload
|
|
|
|
# Database - construct absolute path
|
|
_basedir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
|
|
SQLALCHEMY_DATABASE_URI = os.getenv(
|
|
'DATABASE_URL',
|
|
f'sqlite:///{os.path.join(_basedir, "instance", "dashboard.db")}'
|
|
)
|
|
|
|
# Cache - use simple cache instead of Redis
|
|
CACHE_TYPE = 'simple'
|
|
CACHE_DEFAULT_TIMEOUT = 300
|
|
|
|
# Security
|
|
SESSION_COOKIE_SECURE = True
|
|
SESSION_COOKIE_SAMESITE = 'Lax'
|
|
WTF_CSRF_ENABLED = True
|
|
|
|
|
|
class TestingConfig(Config):
|
|
"""Testing configuration"""
|
|
|
|
DEBUG = True
|
|
TESTING = True
|
|
|
|
# Database (in-memory for tests)
|
|
SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:'
|
|
|
|
# Cache (simple for tests)
|
|
CACHE_TYPE = 'simple'
|
|
|
|
# Security (disabled for tests)
|
|
WTF_CSRF_ENABLED = False
|
|
|
|
|
|
# Configuration dictionary
|
|
config = {
|
|
'development': DevelopmentConfig,
|
|
'production': ProductionConfig,
|
|
'testing': TestingConfig,
|
|
'default': DevelopmentConfig
|
|
}
|
|
|
|
|
|
def get_config(env=None):
|
|
"""Get configuration based on environment"""
|
|
if env is None:
|
|
env = os.getenv('FLASK_ENV', 'development')
|
|
return config.get(env, config['default'])
|