Namenskonsistenz + Ablauf der Lizenzen
Dieser Commit ist enthalten in:
@@ -53,13 +53,13 @@ init_error_handlers(app)
|
|||||||
init_monitoring(app)
|
init_monitoring(app)
|
||||||
ErrorHandlingMiddleware(app)
|
ErrorHandlingMiddleware(app)
|
||||||
|
|
||||||
# Scheduler für automatische Backups
|
|
||||||
scheduler = BackgroundScheduler()
|
|
||||||
scheduler.start()
|
|
||||||
|
|
||||||
# Logging konfigurieren
|
# Logging konfigurieren
|
||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
|
# Initialize scheduler from scheduler module
|
||||||
|
from scheduler import init_scheduler
|
||||||
|
scheduler = init_scheduler()
|
||||||
|
|
||||||
# Import and register blueprints
|
# Import and register blueprints
|
||||||
try:
|
try:
|
||||||
from routes.auth_routes import auth_bp
|
from routes.auth_routes import auth_bp
|
||||||
@@ -119,26 +119,7 @@ def debug_routes():
|
|||||||
routes.append(f"{rule.endpoint}: {rule.rule}")
|
routes.append(f"{rule.endpoint}: {rule.rule}")
|
||||||
return "<br>".join(sorted(routes))
|
return "<br>".join(sorted(routes))
|
||||||
|
|
||||||
# Scheduled Backup Job
|
# Scheduled backup job is now handled by scheduler module
|
||||||
def scheduled_backup():
|
|
||||||
"""Erstellt ein automatisches Backup"""
|
|
||||||
try:
|
|
||||||
backup_file = create_backup()
|
|
||||||
logging.info(f"Scheduled backup created: {backup_file}")
|
|
||||||
except Exception as e:
|
|
||||||
logging.error(f"Scheduled backup failed: {str(e)}")
|
|
||||||
|
|
||||||
|
|
||||||
# Schedule daily backup at 3 AM
|
|
||||||
scheduler.add_job(
|
|
||||||
func=scheduled_backup,
|
|
||||||
trigger="cron",
|
|
||||||
hour=3,
|
|
||||||
minute=0,
|
|
||||||
id='daily_backup',
|
|
||||||
name='Daily backup',
|
|
||||||
replace_existing=True
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# Error handlers are now managed by the error handling system in core/error_handlers.py
|
# Error handlers are now managed by the error handling system in core/error_handlers.py
|
||||||
|
|||||||
@@ -1417,3 +1417,25 @@ def test_license_types():
|
|||||||
cur.close()
|
cur.close()
|
||||||
if 'conn' in locals():
|
if 'conn' in locals():
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
@admin_bp.route("/admin/licenses/check-expiration", methods=["POST"])
|
||||||
|
@login_required
|
||||||
|
def check_license_expiration():
|
||||||
|
"""Manually trigger license expiration check"""
|
||||||
|
if session.get('username') not in ['rac00n', 'w@rh@mm3r']:
|
||||||
|
return jsonify({'error': 'Zugriff verweigert'}), 403
|
||||||
|
|
||||||
|
try:
|
||||||
|
from scheduler import deactivate_expired_licenses
|
||||||
|
deactivate_expired_licenses()
|
||||||
|
|
||||||
|
flash('License expiration check completed successfully', 'success')
|
||||||
|
log_audit('MANUAL_LICENSE_EXPIRATION_CHECK', 'system',
|
||||||
|
additional_info="Manual license expiration check triggered")
|
||||||
|
|
||||||
|
return jsonify({'success': True, 'message': 'License expiration check completed'})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.error(f"Error in manual license expiration check: {str(e)}")
|
||||||
|
return jsonify({'error': str(e)}), 500
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import logging
|
|||||||
from apscheduler.schedulers.background import BackgroundScheduler
|
from apscheduler.schedulers.background import BackgroundScheduler
|
||||||
import config
|
import config
|
||||||
from utils.backup import create_backup
|
from utils.backup import create_backup
|
||||||
from utils.db_utils import get_connection
|
from db import get_connection
|
||||||
|
|
||||||
|
|
||||||
def scheduled_backup():
|
def scheduled_backup():
|
||||||
@@ -64,6 +64,66 @@ def cleanup_expired_sessions():
|
|||||||
conn.rollback()
|
conn.rollback()
|
||||||
|
|
||||||
|
|
||||||
|
def deactivate_expired_licenses():
|
||||||
|
"""Deactivate licenses that have expired"""
|
||||||
|
try:
|
||||||
|
conn = get_connection()
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
# Find active licenses that have expired
|
||||||
|
# Check valid_until < today (at midnight)
|
||||||
|
cur.execute("""
|
||||||
|
SELECT id, license_key, customer_id, valid_until
|
||||||
|
FROM licenses
|
||||||
|
WHERE is_active = true
|
||||||
|
AND valid_until IS NOT NULL
|
||||||
|
AND valid_until < CURRENT_DATE
|
||||||
|
AND is_fake = false
|
||||||
|
""")
|
||||||
|
|
||||||
|
expired_licenses = cur.fetchall()
|
||||||
|
|
||||||
|
if expired_licenses:
|
||||||
|
logging.info(f"Found {len(expired_licenses)} expired licenses to deactivate")
|
||||||
|
|
||||||
|
for license in expired_licenses:
|
||||||
|
license_id, license_key, customer_id, valid_until = license
|
||||||
|
|
||||||
|
# Deactivate the license
|
||||||
|
cur.execute("""
|
||||||
|
UPDATE licenses
|
||||||
|
SET is_active = false,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = %s
|
||||||
|
""", (license_id,))
|
||||||
|
|
||||||
|
# Log to audit trail
|
||||||
|
cur.execute("""
|
||||||
|
INSERT INTO audit_log
|
||||||
|
(timestamp, username, action, entity_type, entity_id,
|
||||||
|
old_values, new_values, additional_info)
|
||||||
|
VALUES (CURRENT_TIMESTAMP, 'system', 'DEACTIVATE', 'license', %s,
|
||||||
|
jsonb_build_object('is_active', true),
|
||||||
|
jsonb_build_object('is_active', false),
|
||||||
|
%s)
|
||||||
|
""", (license_id, f"License automatically deactivated due to expiration. Valid until: {valid_until}"))
|
||||||
|
|
||||||
|
logging.info(f"Deactivated expired license: {license_key} (ID: {license_id})")
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
logging.info(f"Successfully deactivated {len(expired_licenses)} expired licenses")
|
||||||
|
else:
|
||||||
|
logging.debug("No expired licenses found to deactivate")
|
||||||
|
|
||||||
|
cur.close()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Error deactivating expired licenses: {str(e)}")
|
||||||
|
if 'conn' in locals():
|
||||||
|
conn.rollback()
|
||||||
|
|
||||||
|
|
||||||
def init_scheduler():
|
def init_scheduler():
|
||||||
"""Initialize and configure the scheduler"""
|
"""Initialize and configure the scheduler"""
|
||||||
scheduler = BackgroundScheduler()
|
scheduler = BackgroundScheduler()
|
||||||
@@ -87,8 +147,19 @@ def init_scheduler():
|
|||||||
replace_existing=True
|
replace_existing=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Configure license expiration job - runs daily at midnight
|
||||||
|
scheduler.add_job(
|
||||||
|
deactivate_expired_licenses,
|
||||||
|
'cron',
|
||||||
|
hour=0,
|
||||||
|
minute=0,
|
||||||
|
id='license_expiration_check',
|
||||||
|
replace_existing=True
|
||||||
|
)
|
||||||
|
|
||||||
scheduler.start()
|
scheduler.start()
|
||||||
logging.info(f"Scheduler started. Daily backup scheduled at {config.SCHEDULER_CONFIG['backup_hour']:02d}:{config.SCHEDULER_CONFIG['backup_minute']:02d}")
|
logging.info(f"Scheduler started. Daily backup scheduled at {config.SCHEDULER_CONFIG['backup_hour']:02d}:{config.SCHEDULER_CONFIG['backup_minute']:02d}")
|
||||||
logging.info("Session cleanup job scheduled to run every 60 seconds")
|
logging.info("Session cleanup job scheduled to run every 60 seconds")
|
||||||
|
logging.info("License expiration check scheduled to run daily at midnight")
|
||||||
|
|
||||||
return scheduler
|
return scheduler
|
||||||
@@ -228,7 +228,7 @@
|
|||||||
{% if show_fake %}checked{% endif %}
|
{% if show_fake %}checked{% endif %}
|
||||||
onchange="toggleTestResources()">
|
onchange="toggleTestResources()">
|
||||||
<label class="form-check-label" for="showTestResources">
|
<label class="form-check-label" for="showTestResources">
|
||||||
Testressourcen anzeigen
|
Fake-Ressourcen anzeigen
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
In neuem Issue referenzieren
Einen Benutzer sperren