Files
quality_app/py_app/app/__init__.py
Quality App System 64b67b2979 Implement database connection pooling with context manager pattern
- Added DBUtils PooledDB for intelligent connection pooling
- Created db_pool.py with lazy-initialized connection pool (max 20 connections)
- Added db_connection_context() context manager for safe connection handling
- Refactored all 19 database operations to use context manager pattern
- Ensures proper connection cleanup and exception handling
- Prevents connection exhaustion on POST requests
- Added logging configuration for debugging

Changes:
- py_app/app/db_pool.py: New connection pool manager
- py_app/app/logging_config.py: Centralized logging
- py_app/app/__init__.py: Updated to use connection pool
- py_app/app/routes.py: Refactored all DB operations to use context manager
- py_app/app/settings.py: Updated settings handlers
- py_app/requirements.txt: Added DBUtils dependency

This solves the connection timeout issues experienced with the fgscan page.
2026-01-22 22:07:06 +02:00

180 lines
7.3 KiB
Python

from flask import Flask
from datetime import datetime
import os
def create_app():
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'
# Initialize logging first
from app.logging_config import setup_logging
log_dir = os.path.join(app.instance_path, '..', 'logs')
logger = setup_logging(app=app, log_dir=log_dir)
logger.info("Flask app initialization started")
# Configure session persistence
from datetime import timedelta
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)
app.config['SESSION_COOKIE_SECURE'] = False # Set to True in production with HTTPS
app.config['SESSION_COOKIE_HTTPONLY'] = True
app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'
# Set max upload size to 10GB for large database backups
app.config['MAX_CONTENT_LENGTH'] = 10 * 1024 * 1024 * 1024 # 10GB
# Note: Database connection pool is lazily initialized on first use
# This is to avoid trying to read configuration before it's created
# during application startup. See app.db_pool.get_db_pool() for details.
logger.info("Database connection pool will be lazily initialized on first use")
# Application uses direct MariaDB connections via external_server.conf
# Connection pooling via DBUtils prevents connection exhaustion
logger.info("Registering Flask blueprints...")
from app.routes import bp as main_bp, warehouse_bp
from app.daily_mirror import daily_mirror_bp
app.register_blueprint(main_bp, url_prefix='/')
app.register_blueprint(warehouse_bp, url_prefix='/warehouse')
app.register_blueprint(daily_mirror_bp)
logger.info("Blueprints registered successfully")
# Add 'now' function to Jinja2 globals
app.jinja_env.globals['now'] = datetime.now
# Add license check middleware
@app.before_request
def check_license_middleware():
from flask import session, request, redirect, url_for, flash, render_template
import os
import json
from datetime import datetime
# Skip license check for static files, login page, and superadmin users
if request.endpoint and (
request.endpoint == 'static' or
request.endpoint == 'main.login' or
request.path.startswith('/static/')
):
return None
# Skip if user is not logged in (will be redirected to login by other means)
if 'user' not in session:
return None
# Skip license check for superadmin
if session.get('role') == 'superadmin':
return None
# Check license validity
license_path = os.path.join(app.instance_path, 'app_license.json')
if not os.path.exists(license_path):
session.clear()
flash('⚠️ Application License Missing - Please contact your superadmin to generate a license key.', 'danger')
return redirect(url_for('main.login'))
try:
with open(license_path, 'r') as f:
license_data = json.load(f)
valid_until = datetime.strptime(license_data['valid_until'], '%Y-%m-%d')
if datetime.utcnow().date() > valid_until.date():
session.clear()
flash(f'⚠️ Application License Expired on {license_data["valid_until"]} - Please contact your superadmin to renew the license.', 'danger')
return redirect(url_for('main.login'))
except Exception as e:
session.clear()
flash('⚠️ License Validation Error - Please contact your superadmin.', 'danger')
return redirect(url_for('main.login'))
return None
# Initialize user modules validation and repair on app startup
def validate_user_modules_on_startup():
"""Validate and repair user modules during app startup"""
try:
import mariadb
import json
import os
# Get database config from instance folder
instance_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../instance'))
config_path = os.path.join(instance_path, 'external_server.conf')
if not os.path.exists(config_path):
print("⚠️ Database config not found, skipping user modules validation")
return
# Parse config
db_config = {}
try:
with open(config_path, 'r') as f:
for line in f:
if '=' in line:
key, value = line.strip().split('=', 1)
db_config[key] = value
db_config = {
'user': db_config.get('username', 'trasabilitate'),
'password': db_config.get('password', 'Initial01!'),
'host': db_config.get('server_domain', 'localhost'),
'port': int(db_config.get('port', 3306)),
'database': db_config.get('database_name', 'trasabilitate')
}
except Exception as e:
print(f"⚠️ Could not parse database config: {e}")
return
# Connect and validate users
conn = mariadb.connect(**db_config)
cursor = conn.cursor()
# Check if users table exists
cursor.execute("SHOW TABLES LIKE 'users'")
if not cursor.fetchone():
print("⚠️ Users table not found, skipping validation")
conn.close()
return
# Get all users and validate/repair modules
cursor.execute("SELECT id, username, role, modules FROM users")
users = cursor.fetchall()
users_repaired = 0
for user_id, username, role, modules in users:
# Determine correct modules
if role == 'superadmin':
correct_modules = None
elif role == 'admin':
correct_modules = json.dumps(['quality', 'warehouse', 'labels', 'daily_mirror'])
elif role in ['manager', 'quality_manager', 'warehouse_manager']:
correct_modules = json.dumps(['quality', 'warehouse'])
else:
correct_modules = json.dumps([])
# Repair if needed
if modules != correct_modules:
cursor.execute("UPDATE users SET modules = %s WHERE id = %s", (correct_modules, user_id))
users_repaired += 1
if users_repaired > 0:
conn.commit()
print(f"✅ User modules validation complete: {users_repaired} users repaired")
cursor.close()
conn.close()
except Exception as e:
print(f"⚠️ Error during user modules validation: {e}")
# Run validation on startup
with app.app_context():
validate_user_modules_on_startup()
# Initialize automatic backup scheduler
from app.backup_scheduler import init_backup_scheduler
init_backup_scheduler(app)
print("✅ Automatic backup scheduler initialized")
return app