"Feat: Integrate new user request template for guests"

This commit is contained in:
Till Tomczak 2025-05-29 09:54:15 +02:00
parent d1d3cbdafd
commit 0b79e1265f
6 changed files with 149 additions and 17 deletions

View File

@ -29,12 +29,17 @@ from config.settings import (
SCHEDULER_INTERVAL, SCHEDULER_ENABLED, get_ssl_context, FLASK_FALLBACK_PORT,
SSL_ENABLED, SSL_CERT_PATH, SSL_KEY_PATH
)
from utils.logging_config import setup_logging, get_logger, log_startup_info
from models import User, Printer, Job, Stats, get_db_session, init_database, create_initial_admin
from utils.logging_config import setup_logging, get_logger, log_startup_info, debug_request, debug_response, measure_execution_time
from models import User, Printer, Job, Stats, GuestRequest, UserPermission, Notification, get_db_session, init_database, create_initial_admin
from utils.job_scheduler import scheduler
from utils.template_helpers import register_template_helpers
from utils.database_utils import backup_manager, database_monitor, maintenance_scheduler
# Blueprints importieren
from blueprints.guest import guest_blueprint
from blueprints.calendar import calendar_blueprint
from blueprints.users import users_blueprint
# Flask-App initialisieren
app = Flask(__name__)
app.secret_key = SECRET_KEY
@ -45,6 +50,11 @@ app.config["WTF_CSRF_ENABLED"] = True
# CSRF-Schutz initialisieren
csrf = CSRFProtect(app)
# Blueprints registrieren
app.register_blueprint(guest_blueprint)
app.register_blueprint(calendar_blueprint)
app.register_blueprint(users_blueprint)
# Login-Manager initialisieren
login_manager = LoginManager()
login_manager.init_app(app)
@ -90,6 +100,34 @@ printers_logger = get_logger("printers")
user_logger = get_logger("user")
kiosk_logger = get_logger("kiosk")
# HTTP-Request/Response-Middleware für automatisches Debug-Logging
@app.before_request
def log_request_info():
"""Loggt detaillierte Informationen über eingehende HTTP-Anfragen."""
# Nur für API-Endpunkte und wenn Debug-Level aktiviert ist
if request.path.startswith('/api/') or app_logger.level <= logging.DEBUG:
debug_request(app_logger, request)
@app.after_request
def log_response_info(response):
"""Loggt detaillierte Informationen über ausgehende HTTP-Antworten."""
# Nur für API-Endpunkte und wenn Debug-Level aktiviert ist
if request.path.startswith('/api/') or app_logger.level <= logging.DEBUG:
# Berechne Response-Zeit aus dem g-Objekt wenn verfügbar
duration_ms = None
if hasattr(request, '_start_time'):
duration_ms = (time.time() - request._start_time) * 1000
debug_response(app_logger, response, duration_ms)
return response
# Start-Zeit für Request-Timing setzen
@app.before_request
def start_timer():
"""Setzt einen Timer für die Request-Bearbeitung."""
request._start_time = time.time()
# Sicheres Passwort-Hash für Kiosk-Deaktivierung
KIOSK_PASSWORD_HASH = generate_password_hash("744563017196A")

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -89,6 +89,67 @@
</select>
</div>
<!-- Berechtigungen -->
<div class="border-t border-slate-200 dark:border-slate-600 pt-6">
<h3 class="text-lg font-medium text-slate-900 dark:text-white mb-4">Benutzerberechtigungen</h3>
<div class="space-y-4">
<!-- Jobs ohne Genehmigung starten -->
<div class="flex items-center justify-between">
<div>
<label for="can_start_jobs" class="text-sm font-medium text-slate-700 dark:text-slate-300">
Jobs ohne Genehmigung starten
</label>
<p class="text-xs text-slate-500 dark:text-slate-400">
Benutzer kann eigene Druckjobs ohne Admin-Genehmigung starten
</p>
</div>
<div class="relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in">
<input type="checkbox" name="can_start_jobs" id="can_start_jobs"
{% if user.permissions and user.permissions.can_start_jobs %}checked{% endif %}
class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 appearance-none cursor-pointer">
<label for="can_start_jobs" class="toggle-label block overflow-hidden h-6 rounded-full bg-gray-300 cursor-pointer"></label>
</div>
</div>
<!-- Genehmigungspflicht -->
<div class="flex items-center justify-between">
<div>
<label for="needs_approval" class="text-sm font-medium text-slate-700 dark:text-slate-300">
Genehmigungspflicht für Jobs
</label>
<p class="text-xs text-slate-500 dark:text-slate-400">
Jobs des Benutzers müssen von einem Admin genehmigt werden
</p>
</div>
<div class="relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in">
<input type="checkbox" name="needs_approval" id="needs_approval"
{% if not user.permissions or user.permissions.needs_approval %}checked{% endif %}
class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 appearance-none cursor-pointer">
<label for="needs_approval" class="toggle-label block overflow-hidden h-6 rounded-full bg-gray-300 cursor-pointer"></label>
</div>
</div>
<!-- Jobs genehmigen -->
<div class="flex items-center justify-between">
<div>
<label for="can_approve_jobs" class="text-sm font-medium text-slate-700 dark:text-slate-300">
Jobs genehmigen
</label>
<p class="text-xs text-slate-500 dark:text-slate-400">
Benutzer kann Gastanfragen und fremde Jobs genehmigen
</p>
</div>
<div class="relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in">
<input type="checkbox" name="can_approve_jobs" id="can_approve_jobs"
{% if user.permissions and user.permissions.can_approve_jobs %}checked{% endif %}
class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 appearance-none cursor-pointer">
<label for="can_approve_jobs" class="toggle-label block overflow-hidden h-6 rounded-full bg-gray-300 cursor-pointer"></label>
</div>
</div>
</div>
</div>
<!-- Buttons -->
<div class="flex items-center justify-end space-x-4 pt-4">
<a href="{{ url_for('admin_page', tab='users') }}"

View File

@ -188,20 +188,52 @@
</svg>
</button>
<!-- Dark Mode Toggle - neues Design -->
<button
id="darkModeToggle"
class="dark-mode-toggle-new"
aria-label="Dark Mode umschalten"
data-action="toggle-dark-mode"
>
<svg class="w-5 h-5 sm:w-5 sm:h-5 sun-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
</svg>
<svg class="w-5 h-5 sm:w-5 sm:h-5 moon-icon hidden" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
</svg>
</button>
<!-- Dark Mode Toggle - Moderner, schöner Design -->
<div class="relative">
<button
id="darkModeToggle"
class="dark-mode-toggle-premium group"
aria-label="Dark Mode umschalten"
data-action="toggle-dark-mode"
title="Design wechseln"
>
<!-- Hintergrund-Ring für besseren visuellen Effekt -->
<div class="absolute inset-0 rounded-full bg-gradient-to-r from-amber-300 to-orange-400 dark:from-blue-400 dark:to-purple-500 opacity-0 group-hover:opacity-100 blur-sm transition-all duration-500"></div>
<!-- Haupt-Container -->
<div class="relative flex items-center justify-center w-11 h-11 rounded-full bg-white/80 dark:bg-slate-800/80 backdrop-blur-md border border-slate-200/50 dark:border-slate-600/50 shadow-lg dark:shadow-slate-900/20 transition-all duration-300 group-hover:scale-105 group-active:scale-95">
<!-- Sonnen-Icon (Light Mode) -->
<div class="sun-icon absolute inset-0 flex items-center justify-center transition-all duration-500 ease-in-out opacity-100 dark:opacity-0 scale-100 dark:scale-75 rotate-0 dark:rotate-90">
<svg class="w-5 h-5 text-amber-500 drop-shadow-sm" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 2.25a.75.75 0 01.75.75v2.25a.75.75 0 01-1.5 0V3a.75.75 0 01.75-.75zM7.5 12a4.5 4.5 0 119 0 4.5 4.5 0 01-9 0zM18.894 6.166a.75.75 0 00-1.06-1.06l-1.591 1.59a.75.75 0 101.06 1.061l1.591-1.59zM21.75 12a.75.75 0 01-.75.75h-2.25a.75.75 0 010-1.5H21a.75.75 0 01.75.75zM17.834 18.894a.75.75 0 001.06-1.06l-1.59-1.591a.75.75 0 10-1.061 1.06l1.59 1.591zM12 18a.75.75 0 01.75.75V21a.75.75 0 01-1.5 0v-2.25A.75.75 0 0112 18zM7.758 17.303a.75.75 0 00-1.061-1.06l-1.591 1.59a.75.75 0 001.06 1.061l1.591-1.59zM6 12a.75.75 0 01-.75.75H3a.75.75 0 010-1.5h2.25A.75.75 0 016 12zM6.697 7.757a.75.75 0 001.06-1.06l-1.59-1.591a.75.75 0 00-1.061 1.06l1.59 1.591z"/>
</svg>
</div>
<!-- Mond-Icon (Dark Mode) -->
<div class="moon-icon absolute inset-0 flex items-center justify-center transition-all duration-500 ease-in-out opacity-0 dark:opacity-100 scale-75 dark:scale-100 rotate-90 dark:rotate-0">
<svg class="w-5 h-5 text-blue-400 drop-shadow-sm" fill="currentColor" viewBox="0 0 24 24">
<path fill-rule="evenodd" d="M9.528 1.718a.75.75 0 01.162.819A8.97 8.97 0 009 6a9 9 0 009 9 8.97 8.97 0 003.463-.69.75.75 0 01.981.98 10.503 10.503 0 01-9.694 6.46c-5.799 0-10.5-4.701-10.5-10.5 0-4.368 2.667-8.112 6.46-9.694a.75.75 0 01.818.162z" clip-rule="evenodd"/>
</svg>
</div>
<!-- Animierte Punkte für zusätzlichen visuellen Effekt -->
<div class="absolute -inset-1 rounded-full opacity-0 group-hover:opacity-100 transition-opacity duration-300">
<div class="animate-pulse absolute top-0 left-1/2 w-1 h-1 bg-amber-400 dark:bg-blue-400 rounded-full transform -translate-x-1/2 -translate-y-1"></div>
<div class="animate-pulse absolute bottom-0 left-1/2 w-1 h-1 bg-amber-400 dark:bg-blue-400 rounded-full transform -translate-x-1/2 translate-y-1 animation-delay-500"></div>
<div class="animate-pulse absolute top-1/2 left-0 w-1 h-1 bg-amber-400 dark:bg-blue-400 rounded-full transform -translate-y-1/2 -translate-x-1 animation-delay-1000"></div>
<div class="animate-pulse absolute top-1/2 right-0 w-1 h-1 bg-amber-400 dark:bg-blue-400 rounded-full transform -translate-y-1/2 translate-x-1 animation-delay-1500"></div>
</div>
</div>
</button>
<!-- Tooltip -->
<div class="absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 px-2 py-1 bg-slate-900 dark:bg-slate-700 text-white text-xs rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition-opacity duration-200 pointer-events-none z-50">
<span class="dark:hidden">Dark Mode aktivieren</span>
<span class="hidden dark:inline">Light Mode aktivieren</span>
<div class="absolute top-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-l-4 border-r-4 border-t-4 border-transparent border-t-slate-900 dark:border-t-slate-700"></div>
</div>
</div>
{% if current_user.is_authenticated %}
<!-- User Profile Dropdown - neues Design -->

View File

@ -0,0 +1 @@