diff --git a/v2_adminpanel/app.py b/v2_adminpanel/app.py
index 51772eb..e84b8d0 100644
--- a/v2_adminpanel/app.py
+++ b/v2_adminpanel/app.py
@@ -53,13 +53,13 @@ init_error_handlers(app)
init_monitoring(app)
ErrorHandlingMiddleware(app)
-# Scheduler für automatische Backups
-scheduler = BackgroundScheduler()
-scheduler.start()
-
# Logging konfigurieren
logging.basicConfig(level=logging.INFO)
+# Initialize scheduler from scheduler module
+from scheduler import init_scheduler
+scheduler = init_scheduler()
+
# Import and register blueprints
try:
from routes.auth_routes import auth_bp
@@ -119,26 +119,7 @@ def debug_routes():
routes.append(f"{rule.endpoint}: {rule.rule}")
return "
".join(sorted(routes))
-# Scheduled Backup Job
-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
-)
+# Scheduled backup job is now handled by scheduler module
# Error handlers are now managed by the error handling system in core/error_handlers.py
diff --git a/v2_adminpanel/routes/admin_routes.py b/v2_adminpanel/routes/admin_routes.py
index edfb682..067726d 100644
--- a/v2_adminpanel/routes/admin_routes.py
+++ b/v2_adminpanel/routes/admin_routes.py
@@ -1417,3 +1417,25 @@ def test_license_types():
cur.close()
if 'conn' in locals():
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
diff --git a/v2_adminpanel/scheduler.py b/v2_adminpanel/scheduler.py
index 8ff046c..9626ed4 100644
--- a/v2_adminpanel/scheduler.py
+++ b/v2_adminpanel/scheduler.py
@@ -5,7 +5,7 @@ import logging
from apscheduler.schedulers.background import BackgroundScheduler
import config
from utils.backup import create_backup
-from utils.db_utils import get_connection
+from db import get_connection
def scheduled_backup():
@@ -64,6 +64,66 @@ def cleanup_expired_sessions():
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():
"""Initialize and configure the scheduler"""
scheduler = BackgroundScheduler()
@@ -87,8 +147,19 @@ def init_scheduler():
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()
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("License expiration check scheduled to run daily at midnight")
return scheduler
\ No newline at end of file
diff --git a/v2_adminpanel/templates/resources.html b/v2_adminpanel/templates/resources.html
index 6d7411d..8253652 100644
--- a/v2_adminpanel/templates/resources.html
+++ b/v2_adminpanel/templates/resources.html
@@ -228,7 +228,7 @@
{% if show_fake %}checked{% endif %}
onchange="toggleTestResources()">