diff --git a/Web/app.py b/Web/app.py index 951c25b..017e624 100755 --- a/Web/app.py +++ b/Web/app.py @@ -2177,7 +2177,7 @@ def _upload_student_cards_excel(): client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT) try: db = client[cfg.MONGODB_DB] - student_cards = db['student_cards'] + student_cards = list(db['student_cards'].find()) existing_ids.update( str(card.get('AusweisId', '')).strip().upper() for card in student_cards.find({}, {'AusweisId': 1}) @@ -4108,28 +4108,20 @@ def student_cards_admin(): app.logger.error(f"Error adding student card: {e}") flash('Fehler beim Hinzufügen des Ausweises.', 'error') - # Get all student cards + # Get all student cards and decrypt them all_cards = list(student_cards.find().sort('AusweisId', 1)) all_cards = [_decrypt_student_card_doc(card) for card in all_cards] client.close() - # Alle eindeutigen Klassen für das Dropdown ermitteln - client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT) - db = client[cfg.MONGODB_DB] - student_cards_collection = db['student_cards'] - - # Extrahiere alle vorhandenen Klassen, entferne leere/None Werte und sortiere sie - raw_classes = student_cards_collection.distinct('Klasse') - available_classes = sorted([c for c in raw_classes if c]) - - client.close() + raw_classes = set(card.get('Klasse', '').strip() for card in all_cards if card.get('Klasse')) + available_classes = sorted(list(raw_classes)) return render_template( 'student_cards_admin.html', - student_cards=student_cards, + student_cards=all_cards, # Hier all_cards übergeben edit_mode=edit_mode, form_data=form_data, - available_classes=available_classes, + available_classes=available_classes, # Enthält nun die lesbaren Klassen config=cfg.get_school_info() ) @@ -4439,10 +4431,19 @@ def student_card_class_barcode_download(): db = client[cfg.MONGODB_DB] student_cards = db['student_cards'] - class_cards = list(student_cards.find({'Klasse': class_name}).sort('AusweisId', 1)) - class_cards = [_decrypt_student_card_doc(card) for card in class_cards] + # 1. Alle Ausweise laden + all_cards = list(student_cards.find().sort('AusweisId', 1)) client.close() + # 2. Alle entschlüsseln + decrypted_cards = [_decrypt_student_card_doc(card) for card in all_cards] + + # 3. Im Speicher nach der Klartext-Klasse filtern + class_cards = [ + card for card in decrypted_cards + if card.get('Klasse', '').strip() == class_name + ] + if not class_cards: flash(f'Keine Ausweise für die Klasse "{class_name}" gefunden.', 'error') return redirect(url_for('student_cards_admin')) diff --git a/Web/templates/library_table.html b/Web/templates/library_table.html index 28a32db..ad0e00f 100644 --- a/Web/templates/library_table.html +++ b/Web/templates/library_table.html @@ -805,71 +805,92 @@ deleteLibraryItem(itemId); } - // ========================================================================= - // 3. CORE SCANNER ROUTING ENGINE (QUAGGA2) - // ========================================================================= - function startScanner(targetCallback) { - const readerWrap = document.getElementById('scanReaderWrap'); + async function startScanner(callback = null) { + if (scannerRunning) { + console.warn("Scanner is already running. Stopping it first..."); + await stopScanner(); + } + + activeScannerCallback = callback; + + const scannerWrap = document.querySelector('.library-scan-reader-wrap'); const toggleBtn = document.getElementById('toggleScannerBtn'); - activeScannerCallback = targetCallback; + // 1. CRITICAL FIX: Make the container visible BEFORE Quagga initializes + // Quagga cannot calculate video dimensions if display is 'none' + if (scannerWrap) { + scannerWrap.style.display = 'block'; + } - if (readerWrap) readerWrap.style.display = 'block'; - setScanStatus('Initializing camera...', 'warn'); + setScanStatus('Starte Kamera...', 'warn'); - Quagga.init({ - inputStream: { - name: "Live", - type: "LiveStream", - target: document.querySelector('#library-scanner-container'), - constraints: { - width: 640, - height: 480, - facingMode: "environment" + // 2. Initialize Quagga with a slight delay to allow the DOM to render the block + setTimeout(() => { + Quagga.init({ + inputStream: { + name: "Live", + type: "LiveStream", + // This MUST match the inner div where the video should appear + target: document.querySelector('.library-scan-reader'), + constraints: { + width: 640, + height: 480, + facingMode: "environment" // Prefer back camera on mobile + } }, - }, - decoder: { - readers: [ - "code_128_reader", - "ean_reader", - "code_39_reader", - "upc_reader", - "codabar_reader", - "i2of5_reader" - ] - } - }, function(err) { - if (err) { - console.error('Scanner start failed:', err); - if (readerWrap) readerWrap.style.display = 'none'; - const detail = (err && (err.message || err.name)) ? ` (${err.message || err.name})` : ''; - setScanStatus(`Scanner konnte nicht gestartet werden${detail}`, 'error'); - return; - } + locator: { + patchSize: "medium", + halfSample: true + }, + decoder: { + // Keep only the barcode types you actually use to improve performance + readers: ["code_128_reader", "ean_reader", "code_39_reader"] + }, + locate: true + }, function(err) { + if (err) { + // This will finally log the actual error (e.g., NotAllowedError) if permissions fail + console.error("Quagga initialization failed:", err); + setScanStatus('Kamera-Fehler: ' + (err.name || err), 'error'); - Quagga.start(); - scannerRunning = true; + if (scannerWrap) scannerWrap.style.display = 'none'; + scannerRunning = false; + return; + } - if (!targetCallback && toggleBtn) { - toggleBtn.textContent = 'Scanner stoppen'; - } - setScanStatus('Scanner aktiv. Jetzt Code scannen.', 'warn'); - }); + Quagga.start(); + scannerRunning = true; + setScanStatus('Scanner bereit.', 'ok'); + + if (toggleBtn) { + toggleBtn.textContent = 'Scanner stoppen'; + } + }); + }, 50); } - function stopScanner() { + async function stopScanner() { if (!scannerRunning) return; - const readerWrap = document.getElementById('scanReaderWrap'); - const toggleBtn = document.getElementById('toggleScannerBtn'); + try { + Quagga.stop(); + } catch (e) { + console.warn("Error stopping Quagga (it may not have been running):", e); + } - Quagga.stop(); scannerRunning = false; activeScannerCallback = null; - if (readerWrap) readerWrap.style.display = 'none'; - if (toggleBtn) toggleBtn.textContent = 'Scanner starten'; - setScanStatus('Scanner gestoppt.', 'warn'); + // Hide the container to free up UI space + const scannerWrap = document.querySelector('.library-scan-reader-wrap'); + if (scannerWrap) { + scannerWrap.style.display = 'none'; + } + + const toggleBtn = document.getElementById('toggleScannerBtn'); + if (toggleBtn) { + toggleBtn.textContent = 'Kamera Scanner'; // Reset button text + } } async function isStudentCardBarcode(code) {