"feat: Implement new notification system in frontend
This commit is contained in:
@@ -3957,6 +3957,101 @@ def export_admin_logs():
|
||||
|
||||
# ===== ENDE FEHLENDE ADMIN-API-ENDPUNKTE =====
|
||||
|
||||
# ===== BENACHRICHTIGUNGS-API-ENDPUNKTE =====
|
||||
|
||||
@app.route('/api/notifications', methods=['GET'])
|
||||
@login_required
|
||||
def get_notifications():
|
||||
"""Holt alle Benachrichtigungen für den aktuellen Benutzer"""
|
||||
try:
|
||||
db_session = get_db_session()
|
||||
|
||||
# Benachrichtigungen für den aktuellen Benutzer laden
|
||||
notifications = db_session.query(Notification).filter(
|
||||
Notification.user_id == current_user.id
|
||||
).order_by(Notification.created_at.desc()).limit(50).all()
|
||||
|
||||
notifications_data = [notification.to_dict() for notification in notifications]
|
||||
|
||||
db_session.close()
|
||||
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"notifications": notifications_data
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
app_logger.error(f"Fehler beim Laden der Benachrichtigungen: {str(e)}")
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"message": f"Fehler beim Laden der Benachrichtigungen: {str(e)}"
|
||||
}), 500
|
||||
|
||||
@app.route('/api/notifications/<int:notification_id>/read', methods=['POST'])
|
||||
@login_required
|
||||
def mark_notification_read(notification_id):
|
||||
"""Markiert eine Benachrichtigung als gelesen"""
|
||||
try:
|
||||
db_session = get_db_session()
|
||||
|
||||
notification = db_session.query(Notification).filter(
|
||||
Notification.id == notification_id,
|
||||
Notification.user_id == current_user.id
|
||||
).first()
|
||||
|
||||
if not notification:
|
||||
db_session.close()
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"message": "Benachrichtigung nicht gefunden"
|
||||
}), 404
|
||||
|
||||
notification.read = True
|
||||
db_session.commit()
|
||||
db_session.close()
|
||||
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"message": "Benachrichtigung als gelesen markiert"
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
app_logger.error(f"Fehler beim Markieren der Benachrichtigung: {str(e)}")
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"message": f"Fehler beim Markieren: {str(e)}"
|
||||
}), 500
|
||||
|
||||
@app.route('/api/notifications/mark-all-read', methods=['POST'])
|
||||
@login_required
|
||||
def mark_all_notifications_read():
|
||||
"""Markiert alle Benachrichtigungen als gelesen"""
|
||||
try:
|
||||
db_session = get_db_session()
|
||||
|
||||
# Alle ungelesenen Benachrichtigungen des Benutzers finden und als gelesen markieren
|
||||
updated_count = db_session.query(Notification).filter(
|
||||
Notification.user_id == current_user.id,
|
||||
Notification.read == False
|
||||
).update({"read": True})
|
||||
|
||||
db_session.commit()
|
||||
db_session.close()
|
||||
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"message": f"{updated_count} Benachrichtigungen als gelesen markiert"
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
app_logger.error(f"Fehler beim Markieren aller Benachrichtigungen: {str(e)}")
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"message": f"Fehler beim Markieren: {str(e)}"
|
||||
}), 500
|
||||
|
||||
# ===== ENDE BENACHRICHTIGUNGS-API-ENDPUNKTE =====
|
||||
|
||||
|
||||
# ===== STARTUP UND MAIN =====
|
||||
if __name__ == "__main__":
|
||||
|
Binary file not shown.
Binary file not shown.
287
backend/app/static/js/notifications.js
Normal file
287
backend/app/static/js/notifications.js
Normal file
@@ -0,0 +1,287 @@
|
||||
/**
|
||||
* Benachrichtigungssystem für die MYP 3D-Druck Platform
|
||||
* Verwaltet die Anzeige und Interaktion mit Benachrichtigungen
|
||||
*/
|
||||
|
||||
class NotificationManager {
|
||||
constructor() {
|
||||
this.notificationToggle = document.getElementById('notificationToggle');
|
||||
this.notificationDropdown = document.getElementById('notificationDropdown');
|
||||
this.notificationBadge = document.getElementById('notificationBadge');
|
||||
this.notificationList = document.getElementById('notificationList');
|
||||
this.markAllReadBtn = document.getElementById('markAllRead');
|
||||
|
||||
this.isOpen = false;
|
||||
this.notifications = [];
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
if (!this.notificationToggle) return;
|
||||
|
||||
// Event Listeners
|
||||
this.notificationToggle.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
this.toggleDropdown();
|
||||
});
|
||||
|
||||
if (this.markAllReadBtn) {
|
||||
this.markAllReadBtn.addEventListener('click', () => {
|
||||
this.markAllAsRead();
|
||||
});
|
||||
}
|
||||
|
||||
// Dropdown schließen bei Klick außerhalb
|
||||
document.addEventListener('click', (e) => {
|
||||
if (!this.notificationDropdown.contains(e.target) && !this.notificationToggle.contains(e.target)) {
|
||||
this.closeDropdown();
|
||||
}
|
||||
});
|
||||
|
||||
// Benachrichtigungen laden
|
||||
this.loadNotifications();
|
||||
|
||||
// Regelmäßige Updates
|
||||
setInterval(() => {
|
||||
this.loadNotifications();
|
||||
}, 30000); // Alle 30 Sekunden
|
||||
}
|
||||
|
||||
toggleDropdown() {
|
||||
if (this.isOpen) {
|
||||
this.closeDropdown();
|
||||
} else {
|
||||
this.openDropdown();
|
||||
}
|
||||
}
|
||||
|
||||
openDropdown() {
|
||||
this.notificationDropdown.classList.remove('hidden');
|
||||
this.notificationToggle.setAttribute('aria-expanded', 'true');
|
||||
this.isOpen = true;
|
||||
|
||||
// Animation
|
||||
this.notificationDropdown.style.opacity = '0';
|
||||
this.notificationDropdown.style.transform = 'translateY(-10px)';
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
this.notificationDropdown.style.transition = 'opacity 0.2s ease, transform 0.2s ease';
|
||||
this.notificationDropdown.style.opacity = '1';
|
||||
this.notificationDropdown.style.transform = 'translateY(0)';
|
||||
});
|
||||
}
|
||||
|
||||
closeDropdown() {
|
||||
this.notificationDropdown.style.transition = 'opacity 0.2s ease, transform 0.2s ease';
|
||||
this.notificationDropdown.style.opacity = '0';
|
||||
this.notificationDropdown.style.transform = 'translateY(-10px)';
|
||||
|
||||
setTimeout(() => {
|
||||
this.notificationDropdown.classList.add('hidden');
|
||||
this.notificationToggle.setAttribute('aria-expanded', 'false');
|
||||
this.isOpen = false;
|
||||
}, 200);
|
||||
}
|
||||
|
||||
async loadNotifications() {
|
||||
try {
|
||||
const response = await fetch('/api/notifications');
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
this.notifications = data.notifications || [];
|
||||
this.updateUI();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Laden der Benachrichtigungen:', error);
|
||||
}
|
||||
}
|
||||
|
||||
updateUI() {
|
||||
this.updateBadge();
|
||||
this.updateNotificationList();
|
||||
}
|
||||
|
||||
updateBadge() {
|
||||
const unreadCount = this.notifications.filter(n => !n.read).length;
|
||||
|
||||
if (unreadCount > 0) {
|
||||
this.notificationBadge.textContent = unreadCount > 99 ? '99+' : unreadCount.toString();
|
||||
this.notificationBadge.classList.remove('hidden');
|
||||
} else {
|
||||
this.notificationBadge.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
updateNotificationList() {
|
||||
if (this.notifications.length === 0) {
|
||||
this.notificationList.innerHTML = `
|
||||
<div class="p-4 text-center text-slate-500 dark:text-slate-400">
|
||||
Keine neuen Benachrichtigungen
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
const notificationHTML = this.notifications.map(notification => {
|
||||
const isUnread = !notification.read;
|
||||
const timeAgo = this.formatTimeAgo(new Date(notification.created_at));
|
||||
|
||||
return `
|
||||
<div class="notification-item p-4 border-b border-slate-200 dark:border-slate-600 hover:bg-slate-50 dark:hover:bg-slate-700 transition-colors ${isUnread ? 'bg-blue-50 dark:bg-blue-900/20' : ''}"
|
||||
data-notification-id="${notification.id}">
|
||||
<div class="flex items-start space-x-3">
|
||||
<div class="flex-shrink-0">
|
||||
${this.getNotificationIcon(notification.type)}
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<p class="text-sm font-medium text-slate-900 dark:text-white">
|
||||
${this.getNotificationTitle(notification.type)}
|
||||
</p>
|
||||
${isUnread ? '<div class="w-2 h-2 bg-blue-500 rounded-full"></div>' : ''}
|
||||
</div>
|
||||
<p class="text-sm text-slate-600 dark:text-slate-400 mt-1">
|
||||
${this.getNotificationMessage(notification)}
|
||||
</p>
|
||||
<p class="text-xs text-slate-500 dark:text-slate-500 mt-2">
|
||||
${timeAgo}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
this.notificationList.innerHTML = notificationHTML;
|
||||
|
||||
// Event Listeners für Benachrichtigungen
|
||||
this.notificationList.querySelectorAll('.notification-item').forEach(item => {
|
||||
item.addEventListener('click', (e) => {
|
||||
const notificationId = item.dataset.notificationId;
|
||||
this.markAsRead(notificationId);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getNotificationIcon(type) {
|
||||
const icons = {
|
||||
'guest_request': `
|
||||
<div class="w-8 h-8 bg-blue-100 dark:bg-blue-900 rounded-full flex items-center justify-center">
|
||||
<svg class="w-4 h-4 text-blue-600 dark:text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"/>
|
||||
</svg>
|
||||
</div>
|
||||
`,
|
||||
'job_completed': `
|
||||
<div class="w-8 h-8 bg-green-100 dark:bg-green-900 rounded-full flex items-center justify-center">
|
||||
<svg class="w-4 h-4 text-green-600 dark:text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
|
||||
</svg>
|
||||
</div>
|
||||
`,
|
||||
'system': `
|
||||
<div class="w-8 h-8 bg-gray-100 dark:bg-gray-900 rounded-full flex items-center justify-center">
|
||||
<svg class="w-4 h-4 text-gray-600 dark:text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
||||
</svg>
|
||||
</div>
|
||||
`
|
||||
};
|
||||
|
||||
return icons[type] || icons['system'];
|
||||
}
|
||||
|
||||
getNotificationTitle(type) {
|
||||
const titles = {
|
||||
'guest_request': 'Neue Gastanfrage',
|
||||
'job_completed': 'Druckauftrag abgeschlossen',
|
||||
'system': 'System-Benachrichtigung'
|
||||
};
|
||||
|
||||
return titles[type] || 'Benachrichtigung';
|
||||
}
|
||||
|
||||
getNotificationMessage(notification) {
|
||||
try {
|
||||
const payload = JSON.parse(notification.payload || '{}');
|
||||
|
||||
switch (notification.type) {
|
||||
case 'guest_request':
|
||||
return `${payload.guest_name || 'Ein Gast'} hat eine neue Druckanfrage gestellt.`;
|
||||
case 'job_completed':
|
||||
return `Der Druckauftrag "${payload.job_name || 'Unbekannt'}" wurde erfolgreich abgeschlossen.`;
|
||||
default:
|
||||
return payload.message || 'Neue Benachrichtigung erhalten.';
|
||||
}
|
||||
} catch (error) {
|
||||
return 'Neue Benachrichtigung erhalten.';
|
||||
}
|
||||
}
|
||||
|
||||
formatTimeAgo(date) {
|
||||
const now = new Date();
|
||||
const diffInSeconds = Math.floor((now - date) / 1000);
|
||||
|
||||
if (diffInSeconds < 60) {
|
||||
return 'Gerade eben';
|
||||
} else if (diffInSeconds < 3600) {
|
||||
const minutes = Math.floor(diffInSeconds / 60);
|
||||
return `vor ${minutes} Minute${minutes !== 1 ? 'n' : ''}`;
|
||||
} else if (diffInSeconds < 86400) {
|
||||
const hours = Math.floor(diffInSeconds / 3600);
|
||||
return `vor ${hours} Stunde${hours !== 1 ? 'n' : ''}`;
|
||||
} else {
|
||||
const days = Math.floor(diffInSeconds / 86400);
|
||||
return `vor ${days} Tag${days !== 1 ? 'en' : ''}`;
|
||||
}
|
||||
}
|
||||
|
||||
async markAsRead(notificationId) {
|
||||
try {
|
||||
const response = await fetch(`/api/notifications/${notificationId}/read`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
// Benachrichtigung als gelesen markieren
|
||||
const notification = this.notifications.find(n => n.id == notificationId);
|
||||
if (notification) {
|
||||
notification.read = true;
|
||||
this.updateUI();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Markieren als gelesen:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async markAllAsRead() {
|
||||
try {
|
||||
const response = await fetch('/api/notifications/mark-all-read', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
// Alle Benachrichtigungen als gelesen markieren
|
||||
this.notifications.forEach(notification => {
|
||||
notification.read = true;
|
||||
});
|
||||
this.updateUI();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Markieren aller als gelesen:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialisierung nach DOM-Load
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
new NotificationManager();
|
||||
});
|
@@ -252,6 +252,41 @@
|
||||
</div>
|
||||
|
||||
{% if current_user.is_authenticated %}
|
||||
<!-- Benachrichtigungen -->
|
||||
<div class="relative">
|
||||
<button
|
||||
id="notificationToggle"
|
||||
class="relative p-2 rounded-full text-slate-700 dark:text-slate-300 hover:bg-slate-100/80 dark:hover:bg-slate-800/50 transition-all duration-200"
|
||||
aria-label="Benachrichtigungen anzeigen"
|
||||
title="Benachrichtigungen"
|
||||
>
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"/>
|
||||
</svg>
|
||||
<!-- Badge für ungelesene Benachrichtigungen -->
|
||||
<span id="notificationBadge" class="absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full h-5 w-5 flex items-center justify-center font-medium hidden">
|
||||
0
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<!-- Benachrichtigungs-Dropdown -->
|
||||
<div id="notificationDropdown" class="absolute right-0 mt-2 w-80 bg-white dark:bg-slate-800 rounded-lg shadow-lg border border-slate-200 dark:border-slate-600 z-50 hidden">
|
||||
<div class="p-4 border-b border-slate-200 dark:border-slate-600">
|
||||
<h3 class="text-lg font-semibold text-slate-900 dark:text-white">Benachrichtigungen</h3>
|
||||
</div>
|
||||
<div id="notificationList" class="max-h-96 overflow-y-auto">
|
||||
<div class="p-4 text-center text-slate-500 dark:text-slate-400">
|
||||
Keine neuen Benachrichtigungen
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-3 border-t border-slate-200 dark:border-slate-600">
|
||||
<button id="markAllRead" class="w-full text-sm text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 transition-colors">
|
||||
Alle als gelesen markieren
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- User Profile Dropdown - neues Design -->
|
||||
<div class="relative" id="user-menu-container">
|
||||
<button
|
||||
@@ -436,6 +471,9 @@
|
||||
<!-- JavaScript -->
|
||||
<script src="{{ url_for('static', filename='js/ui-components.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/dark-mode-fix.js') }}"></script>
|
||||
{% if current_user.is_authenticated %}
|
||||
<script src="{{ url_for('static', filename='js/notifications.js') }}"></script>
|
||||
{% endif %}
|
||||
|
||||
{% block scripts %}{% endblock %}
|
||||
</body>
|
||||
|
@@ -64,7 +64,19 @@ EMOJI_FALLBACK = {
|
||||
'🔧': '[PRINT]',
|
||||
'💥': '[ERR]',
|
||||
'👤': '[USER]',
|
||||
'📺': '[KIOSK]'
|
||||
'📺': '[KIOSK]',
|
||||
'🐞': '[BUG]',
|
||||
'🚀': '[START]',
|
||||
'📂': '[FOLDER]',
|
||||
'📊': '[CHART]',
|
||||
'💻': '[PC]',
|
||||
'🌐': '[WEB]',
|
||||
'📅': '[TIME]',
|
||||
'📡': '[SIGNAL]',
|
||||
'🧩': '[CONTENT]',
|
||||
'📋': '[HEADER]',
|
||||
'✅': '[OK]',
|
||||
'📦': '[SIZE]'
|
||||
}
|
||||
|
||||
def safe_emoji(emoji: str) -> str:
|
||||
@@ -86,12 +98,22 @@ def supports_color() -> bool:
|
||||
# Aktiviere VT100-Unterstützung unter Windows
|
||||
kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
|
||||
|
||||
# Setze Console-Output auf UTF-8 für bessere Emoji-Unterstützung
|
||||
try:
|
||||
kernel32.SetConsoleOutputCP(65001) # UTF-8
|
||||
except:
|
||||
pass
|
||||
|
||||
# Versuche UTF-8-Encoding für Emojis zu setzen
|
||||
try:
|
||||
import locale
|
||||
locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
# Fallback für deutsche Lokalisierung
|
||||
locale.setlocale(locale.LC_ALL, 'de_DE.UTF-8')
|
||||
except:
|
||||
pass
|
||||
|
||||
return True
|
||||
except:
|
||||
@@ -219,7 +241,8 @@ def setup_logging(debug_mode: bool = False):
|
||||
|
||||
# Wenn Debug-Modus aktiv, Konfiguration loggen
|
||||
if debug_mode:
|
||||
root_logger.debug(f"🐞 Debug-Modus aktiviert - Ausführliche Logs werden generiert")
|
||||
bug_emoji = safe_emoji("🐞")
|
||||
root_logger.debug(f"{bug_emoji} Debug-Modus aktiviert - Ausführliche Logs werden generiert")
|
||||
|
||||
def get_logger(category: str) -> logging.Logger:
|
||||
"""
|
||||
@@ -280,13 +303,20 @@ def get_logger(category: str) -> logging.Logger:
|
||||
def log_startup_info():
|
||||
"""Loggt Startup-Informationen."""
|
||||
app_logger = get_logger("app")
|
||||
rocket_emoji = safe_emoji("🚀")
|
||||
folder_emoji = safe_emoji("📂")
|
||||
chart_emoji = safe_emoji("📊")
|
||||
computer_emoji = safe_emoji("💻")
|
||||
globe_emoji = safe_emoji("🌐")
|
||||
calendar_emoji = safe_emoji("📅")
|
||||
|
||||
app_logger.info("=" * 50)
|
||||
app_logger.info("🚀 MYP (Manage Your Printers) wird gestartet...")
|
||||
app_logger.info(f"📂 Log-Verzeichnis: {LOG_DIR}")
|
||||
app_logger.info(f"📊 Log-Level: {LOG_LEVEL}")
|
||||
app_logger.info(f"💻 Betriebssystem: {platform.system()} {platform.release()}")
|
||||
app_logger.info(f"🌐 Hostname: {socket.gethostname()}")
|
||||
app_logger.info(f"📅 Startzeit: {datetime.now().strftime('%d.%m.%Y %H:%M:%S')}")
|
||||
app_logger.info(f"{rocket_emoji} MYP (Manage Your Printers) wird gestartet...")
|
||||
app_logger.info(f"{folder_emoji} Log-Verzeichnis: {LOG_DIR}")
|
||||
app_logger.info(f"{chart_emoji} Log-Level: {LOG_LEVEL}")
|
||||
app_logger.info(f"{computer_emoji} Betriebssystem: {platform.system()} {platform.release()}")
|
||||
app_logger.info(f"{globe_emoji} Hostname: {socket.gethostname()}")
|
||||
app_logger.info(f"{calendar_emoji} Startzeit: {datetime.now().strftime('%d.%m.%Y %H:%M:%S')}")
|
||||
app_logger.info("=" * 50)
|
||||
|
||||
# Hilfsfunktionen für das Debugging
|
||||
@@ -302,22 +332,28 @@ def debug_request(logger: logging.Logger, request):
|
||||
if logger.level > logging.DEBUG:
|
||||
return
|
||||
|
||||
logger.debug(f"🌐 HTTP-Anfrage: {request.method} {request.path}")
|
||||
logger.debug(f"📡 Remote-Adresse: {request.remote_addr}")
|
||||
logger.debug(f"🧩 Inhaltstyp: {request.content_type}")
|
||||
web_emoji = safe_emoji("🌐")
|
||||
signal_emoji = safe_emoji("📡")
|
||||
puzzle_emoji = safe_emoji("🧩")
|
||||
clipboard_emoji = safe_emoji("📋")
|
||||
search_emoji = safe_emoji("🔍")
|
||||
|
||||
logger.debug(f"{web_emoji} HTTP-Anfrage: {request.method} {request.path}")
|
||||
logger.debug(f"{signal_emoji} Remote-Adresse: {request.remote_addr}")
|
||||
logger.debug(f"{puzzle_emoji} Inhaltstyp: {request.content_type}")
|
||||
|
||||
# Nur relevante Headers ausgeben
|
||||
important_headers = ['User-Agent', 'Referer', 'X-Forwarded-For', 'Authorization']
|
||||
headers = {k: v for k, v in request.headers.items() if k in important_headers}
|
||||
if headers:
|
||||
logger.debug(f"📋 Wichtige Headers: {headers}")
|
||||
logger.debug(f"{clipboard_emoji} Wichtige Headers: {headers}")
|
||||
|
||||
# Request-Parameter (max. 1000 Zeichen)
|
||||
if request.args:
|
||||
args_str = str(request.args)
|
||||
if len(args_str) > 1000:
|
||||
args_str = args_str[:997] + "..."
|
||||
logger.debug(f"🔍 URL-Parameter: {args_str}")
|
||||
logger.debug(f"{search_emoji} URL-Parameter: {args_str}")
|
||||
|
||||
def debug_response(logger: logging.Logger, response, duration_ms: float = None):
|
||||
"""
|
||||
@@ -331,16 +367,18 @@ def debug_response(logger: logging.Logger, response, duration_ms: float = None):
|
||||
if logger.level > logging.DEBUG:
|
||||
return
|
||||
|
||||
status_emoji = "✅" if response.status_code < 400 else "❌"
|
||||
status_emoji = safe_emoji("✅") if response.status_code < 400 else safe_emoji("❌")
|
||||
logger.debug(f"{status_emoji} HTTP-Antwort: {response.status_code}")
|
||||
|
||||
if duration_ms is not None:
|
||||
logger.debug(f"⏱️ Verarbeitungsdauer: {duration_ms:.2f} ms")
|
||||
timer_emoji = safe_emoji("⏱️")
|
||||
logger.debug(f"{timer_emoji} Verarbeitungsdauer: {duration_ms:.2f} ms")
|
||||
|
||||
content_length = response.content_length or 0
|
||||
if content_length > 0:
|
||||
size_str = f"{content_length / 1024:.1f} KB" if content_length > 1024 else f"{content_length} Bytes"
|
||||
logger.debug(f"📦 Antwortgröße: {size_str}")
|
||||
package_emoji = safe_emoji("📦")
|
||||
logger.debug(f"{package_emoji} Antwortgröße: {size_str}")
|
||||
|
||||
def measure_execution_time(func=None, logger=None, task_name=None):
|
||||
"""
|
||||
@@ -367,10 +405,11 @@ def measure_execution_time(func=None, logger=None, task_name=None):
|
||||
name = task_name or f.__name__
|
||||
|
||||
if logger:
|
||||
timer_emoji = safe_emoji('⏱️')
|
||||
if duration_ms > 1000: # Länger als 1 Sekunde
|
||||
logger.warning(f"⏱️ Langsame Ausführung: {name} - {duration_ms:.2f} ms")
|
||||
logger.warning(f"{timer_emoji} Langsame Ausführung: {name} - {duration_ms:.2f} ms")
|
||||
else:
|
||||
logger.debug(f"⏱️ Ausführungszeit: {name} - {duration_ms:.2f} ms")
|
||||
logger.debug(f"{timer_emoji} Ausführungszeit: {name} - {duration_ms:.2f} ms")
|
||||
|
||||
return result
|
||||
return wrapper
|
||||
|
Reference in New Issue
Block a user