🗑️ Refactor: Remove obsolete printer check scripts and update app logic

**Änderungen:**
-  check_printer_ips.py und check_printers.py: Entfernt nicht mehr benötigte Skripte zur Überprüfung von Drucker-IP-Adressen.
-  DRUCKER_STATUS_REQUIREMENTS.md: Veraltete Anforderungen entfernt.
-  setup_standard_printers.py: Anpassungen zur Vereinheitlichung der Drucker-IP.
-  app.py: Logik zur Filterung offline/unreachable Drucker aktualisiert.

**Ergebnis:**
- Bereinigung des Codes durch Entfernen nicht mehr benötigter Dateien.
- Optimierte Logik zur Handhabung von Druckerstatus in der Anwendung.

🤖 Generated with [Claude Code](https://claude.ai/code)
This commit is contained in:
2025-06-15 23:59:39 +02:00
parent 956c24d8ca
commit c4e65a07a9
1258 changed files with 11101 additions and 609 deletions

View File

@ -199,6 +199,15 @@
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(8px);
z-index: 50;
display: flex;
align-items: center;
justify-content: center;
padding: 1rem;
cursor: pointer;
}
.modal-overlay.hidden {
display: none !important;
}
.dark .modal-overlay {
@ -211,6 +220,18 @@
border-radius: 20px;
box-shadow: var(--shadow-modal);
backdrop-filter: var(--glass-blur);
max-width: 90vw;
max-height: 90vh;
overflow-y: auto;
transform: scale(0.95);
opacity: 0;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
cursor: default;
}
.modal.show {
transform: scale(1);
opacity: 1;
}
.modal-header {
@ -222,6 +243,88 @@
color: var(--text-secondary);
}
/* Mercedes Modal Specific Styling */
.mercedes-modal {
background: var(--gradient-modal);
border: 1px solid var(--border-primary);
border-radius: 20px;
box-shadow: var(--shadow-modal);
backdrop-filter: var(--glass-blur);
max-width: 90vw;
max-height: 90vh;
overflow-y: auto;
transform: scale(0.95);
opacity: 0;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
scrollbar-width: thin;
scrollbar-color: rgba(0, 115, 206, 0.2) transparent;
cursor: default;
}
.mercedes-modal.show {
transform: scale(1);
opacity: 1;
}
.mercedes-modal::-webkit-scrollbar {
width: 8px;
}
.mercedes-modal::-webkit-scrollbar-track {
background: transparent;
border-radius: 4px;
}
.mercedes-modal::-webkit-scrollbar-thumb {
background: rgba(0, 115, 206, 0.2);
border-radius: 4px;
transition: all 0.3s ease;
}
.mercedes-modal::-webkit-scrollbar-thumb:hover {
background: rgba(0, 115, 206, 0.4);
}
.dark .mercedes-modal::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.2);
}
.dark .mercedes-modal::-webkit-scrollbar-thumb:hover {
background: rgba(255, 255, 255, 0.4);
}
/* Modal Animation Classes */
.modal-enter {
opacity: 0;
transform: scale(0.9) translateY(-20px);
}
.modal-enter-active {
opacity: 1;
transform: scale(1) translateY(0);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.modal-exit {
opacity: 1;
transform: scale(1) translateY(0);
}
.modal-exit-active {
opacity: 0;
transform: scale(0.9) translateY(-20px);
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
/* Modal Overlay Click-to-Close Functionality */
.modal-overlay[data-closable="true"] {
cursor: pointer;
}
.modal-overlay[data-closable="true"] .mercedes-modal {
cursor: default;
}
/* === FORM ELEMENTS === */
.form-input {
@apply w-full px-4 py-3 rounded-lg transition-all duration-200;
@ -420,10 +523,6 @@
}
/* === LEGACY COMPATIBILITY === */
.mercedes-modal {
@extend .modal;
}
.glass-modal {
@extend .modal;
@extend .glass-card;

View File

@ -0,0 +1,160 @@
/**
* MYP Platform - Globaler CSRF-Token-Fix
* Automatisches Hinzufügen von CSRF-Token zu allen AJAX-Anfragen
*/
(function() {
'use strict';
// CSRF-Token aus verschiedenen Quellen abrufen
function getCSRFToken() {
// Methode 1: Meta-Tag (bevorzugt)
const metaToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
if (metaToken && metaToken.trim()) {
console.log('🔒 CSRF-Token aus Meta-Tag geladen');
return metaToken.trim();
}
// Methode 2: Hidden Input
const hiddenInput = document.querySelector('input[name="csrf_token"]')?.value;
if (hiddenInput && hiddenInput.trim()) {
console.log('🔒 CSRF-Token aus Hidden Input geladen');
return hiddenInput.trim();
}
// Methode 3: Cookie (falls verfügbar)
const cookieMatch = document.cookie.match(/csrf_token=([^;]+)/);
if (cookieMatch && cookieMatch[1]) {
console.log('🔒 CSRF-Token aus Cookie geladen');
return cookieMatch[1];
}
console.error('❌ CSRF-Token konnte nicht gefunden werden!');
return null;
}
// Token beim Laden der Seite abrufen
let csrfToken = getCSRFToken();
// Token regelmäßig aktualisieren (alle 30 Minuten)
setInterval(() => {
const newToken = getCSRFToken();
if (newToken && newToken !== csrfToken) {
csrfToken = newToken;
console.log('🔄 CSRF-Token aktualisiert');
}
}, 30 * 60 * 1000);
// Globale Funktion für andere Scripts
window.getCSRFToken = function() {
return csrfToken || getCSRFToken();
};
// Fetch API abfangen und CSRF-Token hinzufügen
const originalFetch = window.fetch;
window.fetch = function(url, options = {}) {
// Nur für POST, PUT, DELETE, PATCH Anfragen
const method = (options.method || 'GET').toUpperCase();
const needsCSRF = ['POST', 'PUT', 'DELETE', 'PATCH'].includes(method);
if (needsCSRF) {
const token = window.getCSRFToken();
if (token) {
// Headers initialisieren falls nicht vorhanden
options.headers = options.headers || {};
// CSRF-Token hinzufügen (mehrere Methoden für Kompatibilität)
options.headers['X-CSRFToken'] = token;
options.headers['X-CSRF-Token'] = token;
// Für FormData: Token als Feld hinzufügen
if (options.body instanceof FormData) {
options.body.append('csrf_token', token);
}
// Für JSON: Token in Headers (bereits oben gemacht)
else if (options.headers['Content-Type']?.includes('application/json')) {
// Token ist bereits in Headers
}
// Für URL-encoded: Token hinzufügen
else if (typeof options.body === 'string' && options.headers['Content-Type']?.includes('application/x-www-form-urlencoded')) {
options.body += (options.body ? '&' : '') + 'csrf_token=' + encodeURIComponent(token);
}
console.log(`🔒 CSRF-Token zu ${method} ${url} hinzugefügt`);
} else {
console.warn(`⚠️ Kein CSRF-Token für ${method} ${url} verfügbar`);
}
}
return originalFetch.call(this, url, options);
};
// XMLHttpRequest abfangen (für ältere AJAX-Bibliotheken)
const originalXHROpen = XMLHttpRequest.prototype.open;
const originalXHRSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.open = function(method, url, async, user, password) {
this._method = method.toUpperCase();
this._url = url;
return originalXHROpen.call(this, method, url, async, user, password);
};
XMLHttpRequest.prototype.send = function(data) {
const needsCSRF = ['POST', 'PUT', 'DELETE', 'PATCH'].includes(this._method);
if (needsCSRF) {
const token = window.getCSRFToken();
if (token) {
// Header hinzufügen
this.setRequestHeader('X-CSRFToken', token);
this.setRequestHeader('X-CSRF-Token', token);
// Für FormData: Token hinzufügen
if (data instanceof FormData) {
data.append('csrf_token', token);
}
// Für String-Data: Token hinzufügen
else if (typeof data === 'string' && !this.getResponseHeader('Content-Type')?.includes('application/json')) {
data += (data ? '&' : '') + 'csrf_token=' + encodeURIComponent(token);
}
console.log(`🔒 CSRF-Token zu XHR ${this._method} ${this._url} hinzugefügt`);
} else {
console.warn(`⚠️ Kein CSRF-Token für XHR ${this._method} ${this._url} verfügbar`);
}
}
return originalXHRSend.call(this, data);
};
// jQuery AJAX Setup (falls jQuery verwendet wird)
document.addEventListener('DOMContentLoaded', function() {
if (window.jQuery) {
jQuery.ajaxSetup({
beforeSend: function(xhr, settings) {
const needsCSRF = ['POST', 'PUT', 'DELETE', 'PATCH'].includes(settings.type?.toUpperCase());
if (needsCSRF && !this.crossDomain) {
const token = window.getCSRFToken();
if (token) {
xhr.setRequestHeader('X-CSRFToken', token);
xhr.setRequestHeader('X-CSRF-Token', token);
console.log(`🔒 CSRF-Token zu jQuery ${settings.type} ${settings.url} hinzugefügt`);
}
}
}
});
}
});
// Debug-Funktion für Entwicklung
window.debugCSRF = function() {
console.log('🔍 CSRF Debug Info:');
console.log('Meta-Tag:', document.querySelector('meta[name="csrf-token"]')?.getAttribute('content'));
console.log('Hidden Input:', document.querySelector('input[name="csrf_token"]')?.value);
console.log('Current Token:', window.getCSRFToken());
console.log('Cookie:', document.cookie);
};
console.log('🔒 CSRF-Fix geladen - automatisches Token-Management aktiv');
})();

308
backend/static/sw.js Normal file
View File

@ -0,0 +1,308 @@
/**
* MYP Service Worker
* =================
*
* Service Worker für das Mercedes-Benz 3D-Druck-Management-System
* Bietet Offline-Funktionalität und Caching für bessere Performance
*/
const CACHE_NAME = 'myp-v1.0.0';
const STATIC_CACHE_NAME = 'myp-static-v1.0.0';
const DYNAMIC_CACHE_NAME = 'myp-dynamic-v1.0.0';
// Statische Ressourcen, die immer gecacht werden sollen
const STATIC_ASSETS = [
'/',
'/static/css/tailwind.min.css',
'/static/css/dark-light-unified.css',
'/static/fontawesome/css/all.min.css',
'/static/js/jobs-safety-fix.js',
'/static/manifest.json',
'/static/favicon.svg',
'/static/icons/icon-192.png',
'/static/icons/icon-512.png'
];
// API-Endpunkte, die gecacht werden können
const CACHEABLE_APIS = [
'/api/printers',
'/api/jobs',
'/api/stats'
];
// Installation des Service Workers
self.addEventListener('install', event => {
console.log('🔧 MYP Service Worker wird installiert...');
event.waitUntil(
caches.open(STATIC_CACHE_NAME)
.then(cache => {
console.log('📦 Statische Assets werden gecacht...');
return cache.addAll(STATIC_ASSETS);
})
.then(() => {
console.log('✅ MYP Service Worker erfolgreich installiert');
return self.skipWaiting();
})
.catch(error => {
console.error('❌ Fehler bei Service Worker Installation:', error);
})
);
});
// Aktivierung des Service Workers
self.addEventListener('activate', event => {
console.log('🚀 MYP Service Worker wird aktiviert...');
event.waitUntil(
caches.keys()
.then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
// Alte Caches löschen
if (cacheName !== STATIC_CACHE_NAME &&
cacheName !== DYNAMIC_CACHE_NAME &&
cacheName !== CACHE_NAME) {
console.log('🗑️ Lösche alten Cache:', cacheName);
return caches.delete(cacheName);
}
})
);
})
.then(() => {
console.log('✅ MYP Service Worker aktiviert');
return self.clients.claim();
})
);
});
// Fetch-Event Handler für Caching-Strategien
self.addEventListener('fetch', event => {
const request = event.request;
const url = new URL(request.url);
// Nur GET-Requests cachen
if (request.method !== 'GET') {
return;
}
// Statische Assets: Cache First
if (STATIC_ASSETS.some(asset => url.pathname.endsWith(asset) || url.pathname === asset)) {
event.respondWith(cacheFirst(request));
return;
}
// API-Endpunkte: Network First mit Cache Fallback
if (CACHEABLE_APIS.some(api => url.pathname.startsWith(api))) {
event.respondWith(networkFirst(request));
return;
}
// Statische Dateien (CSS, JS, Bilder): Cache First
if (url.pathname.startsWith('/static/')) {
event.respondWith(cacheFirst(request));
return;
}
// HTML-Seiten: Network First
if (request.headers.get('accept').includes('text/html')) {
event.respondWith(networkFirst(request));
return;
}
// Alle anderen Requests: Network Only
event.respondWith(fetch(request));
});
/**
* Cache First Strategie
* Versucht zuerst aus dem Cache zu laden, dann aus dem Netzwerk
*/
async function cacheFirst(request) {
try {
const cache = await caches.open(STATIC_CACHE_NAME);
const cachedResponse = await cache.match(request);
if (cachedResponse) {
console.log('📦 Aus Cache geladen:', request.url);
return cachedResponse;
}
const networkResponse = await fetch(request);
if (networkResponse.ok) {
cache.put(request, networkResponse.clone());
console.log('🌐 Aus Netzwerk geladen und gecacht:', request.url);
}
return networkResponse;
} catch (error) {
console.error('❌ Cache First Fehler:', error);
// Fallback für kritische Ressourcen
if (request.url.includes('tailwind.min.css')) {
return new Response('/* Offline CSS Fallback */', {
headers: { 'Content-Type': 'text/css' }
});
}
throw error;
}
}
/**
* Network First Strategie
* Versucht zuerst aus dem Netzwerk zu laden, dann aus dem Cache
*/
async function networkFirst(request) {
try {
const networkResponse = await fetch(request);
if (networkResponse.ok) {
const cache = await caches.open(DYNAMIC_CACHE_NAME);
cache.put(request, networkResponse.clone());
console.log('🌐 Aus Netzwerk geladen:', request.url);
return networkResponse;
}
throw new Error(`Network response not ok: ${networkResponse.status}`);
} catch (error) {
console.log('📦 Netzwerk nicht verfügbar, versuche Cache:', request.url);
const cache = await caches.open(DYNAMIC_CACHE_NAME);
const cachedResponse = await cache.match(request);
if (cachedResponse) {
console.log('📦 Aus Cache geladen (Offline):', request.url);
return cachedResponse;
}
// Offline-Fallback für API-Requests
if (request.url.includes('/api/')) {
return new Response(JSON.stringify({
success: false,
error: 'Offline - Keine Verbindung zum Server',
offline: true
}), {
status: 503,
headers: { 'Content-Type': 'application/json' }
});
}
// Offline-Fallback für HTML-Seiten
if (request.headers.get('accept').includes('text/html')) {
const offlineHtml = `
<!DOCTYPE html>
<html>
<head>
<title>MYP - Offline</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body { font-family: Arial, sans-serif; text-align: center; padding: 50px; }
.offline-message { max-width: 500px; margin: 0 auto; }
.icon { font-size: 64px; margin-bottom: 20px; }
</style>
</head>
<body>
<div class="offline-message">
<div class="icon">📡</div>
<h1>Offline</h1>
<p>Sie sind derzeit offline. Bitte überprüfen Sie Ihre Internetverbindung.</p>
<button onclick="window.location.reload()">Erneut versuchen</button>
</div>
</body>
</html>
`;
return new Response(offlineHtml, {
headers: { 'Content-Type': 'text/html' }
});
}
throw error;
}
}
// Background Sync für Offline-Aktionen
self.addEventListener('sync', event => {
console.log('🔄 Background Sync Event:', event.tag);
if (event.tag === 'background-sync-jobs') {
event.waitUntil(syncJobs());
}
});
/**
* Synchronisiert Jobs im Hintergrund
*/
async function syncJobs() {
try {
console.log('🔄 Synchronisiere Jobs im Hintergrund...');
// Hier könnten offline gespeicherte Aktionen synchronisiert werden
const response = await fetch('/api/jobs');
if (response.ok) {
console.log('✅ Jobs erfolgreich synchronisiert');
}
} catch (error) {
console.error('❌ Fehler bei Job-Synchronisation:', error);
}
}
// Push-Benachrichtigungen
self.addEventListener('push', event => {
console.log('📬 Push-Benachrichtigung erhalten');
const options = {
body: 'Sie haben eine neue Benachrichtigung',
icon: '/static/icons/icon-192.png',
badge: '/static/icons/icon-192.png',
vibrate: [100, 50, 100],
data: {
dateOfArrival: Date.now(),
primaryKey: 1
},
actions: [
{
action: 'explore',
title: 'Anzeigen',
icon: '/static/icons/icon-192.png'
},
{
action: 'close',
title: 'Schließen',
icon: '/static/icons/icon-192.png'
}
]
};
if (event.data) {
const data = event.data.json();
options.body = data.message || options.body;
options.title = data.title || 'MYP Benachrichtigung';
}
event.waitUntil(
self.registration.showNotification('MYP System', options)
);
});
// Benachrichtigung-Click Handler
self.addEventListener('notificationclick', event => {
console.log('🔔 Benachrichtigung geklickt:', event.action);
event.notification.close();
if (event.action === 'explore') {
event.waitUntil(
clients.openWindow('/')
);
}
});
console.log('🚀 MYP Service Worker geladen');