From 1b2b462c52d10ab92e5b8a231ccd4f713ad97870 Mon Sep 17 00:00:00 2001 From: AIIrondev Date: Tue, 18 Aug 2026 18:51:49 +0200 Subject: [PATCH] changes to the _upload student to have the field encryptet --- Web/app.py | 95 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 53 insertions(+), 42 deletions(-) diff --git a/Web/app.py b/Web/app.py index 28b9f5c..14ceedd 100755 --- a/Web/app.py +++ b/Web/app.py @@ -2151,14 +2151,15 @@ def generate_ausweis_id_excel(existing_ids_set): print(f"Already found: {new_id}, trying another...") def _upload_student_cards_excel(): - """Bulk import student cards with optional school year rollover (Abgleich).""" + """Bulk import student cards from Excel with automatic name/class mapping, rollover support, and encryption.""" if 'username' not in session: flash('Nicht angemeldet.', 'error') return redirect(url_for('login')) current_permissions = us.get_effective_permissions(session['username']) + if not current_permissions['actions'].get('can_manage_user', False): - flash('Ihnen fehlen die nötigen Berechtigungen.', 'error') + flash('Ihnen fehlen die nötigen Berechtigungen, um diese Aktion auszuführen.', 'error') return redirect(url_for('library_view')) if not cfg.MODULES.is_enabled('student_cards'): @@ -2175,7 +2176,6 @@ def _upload_student_cards_excel(): flash('Nur .xlsx oder .csv Dateien werden unterstützt.', 'error') return redirect(url_for('student_cards_admin')) - # CHECKBOX / SCHALTER: Schuljahres-Abgleich aktiviert? rollover_mode = request.form.get('rollover_mode') in ['true', '1', 'on'] try: @@ -2220,7 +2220,7 @@ def _upload_student_cards_excel(): } validation_only = (request.form.get('excel_action') or '').strip().lower() == 'validate' - max_rows = 15000 + max_rows = 1500 planned_rows = [] validation_errors = [] @@ -2230,11 +2230,14 @@ def _upload_student_cards_excel(): client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT) try: db = client[cfg.MONGODB_DB] - raw_db_cards = list(db['student_cards'].find()) + student_cards_col = db['student_cards'] - for card in raw_db_cards: - if card.get('AusweisId'): - existing_ids.add(str(card.get('AusweisId')).strip().upper()) + student_cards_cursor = student_cards_col.find({}, {'AusweisId': 1}) + existing_ids.update( + str(card.get('AusweisId', '')).strip().upper() + for card in student_cards_cursor + if card.get('AusweisId') + ) processed_rows = 0 for row_number, row_values in enumerate(data_rows, start=2): @@ -2267,6 +2270,20 @@ def _upload_student_cards_excel(): if not student_name: row_errors.append('Vorname und Nachname fehlen') + if not ausweis_id and student_name: + ausweis_id = generate_ausweis_id(existing_ids) + validation_warnings.append((row_number, f'Ausweis-ID wurde automatisch erzeugt: {ausweis_id}')) + existing_ids.add(ausweis_id.upper()) + elif ausweis_id and not rollover_mode: + ausweis_id = str(ausweis_id).strip().upper() + if ausweis_id in existing_ids: + row_errors.append(f'Ausweis-ID {ausweis_id} existiert bereits') + else: + existing_ids.add(ausweis_id) + + if not ausweis_ident: + ausweis_ident = ausweis_id + if row_errors: validation_errors.append((row_number, '; '.join(row_errors))) continue @@ -2276,8 +2293,6 @@ def _upload_student_cards_excel(): 'ausweis_id': ausweis_id, 'ausweis_ident': ausweis_ident, 'student_name': student_name, - 'first_name': first_name, - 'last_name': last_name, 'class_name': class_name, 'notes': notes, 'default_borrow_days': default_borrow_days, @@ -2293,16 +2308,19 @@ def _upload_student_cards_excel(): matched_count = 0 if rollover_mode: + raw_db_cards = list(student_cards_col.find()) decrypted_db_cards = [] - for doc in raw_db_cards: - dec_name = dp.decrypt_text(doc.get('SchülerName')) if doc.get('SchülerName') else "" - dec_class = dp.decrypt_text(doc.get('Klasse')) if doc.get('Klasse') else "" - dec_ident = doc.get('AusweisIdent') or "" - if dec_ident and dec_ident.startswith("gAAAAA"): + for doc in raw_db_cards: + dec_name = decrypt_text(doc.get('SchülerName')) if doc.get('SchülerName') else "" + dec_class = decrypt_text(doc.get('Klasse')) if doc.get('Klasse') else "" + + raw_ident = doc.get('ausweis_ident') or doc.get('AusweisIdent') or "" + dec_ident = raw_ident + if raw_ident and str(raw_ident).startswith("gAAAAA"): try: - dec_ident = dp.decrypt_text(dec_ident) - except: + dec_ident = decrypt_text(raw_ident) + except Exception: pass decrypted_db_cards.append({ @@ -2319,12 +2337,11 @@ def _upload_student_cards_excel(): ex_class = str(excel_row['class_name'] or '').strip().lower() match_found = None - for db_card in decrypted_db_cards: if db_card['_id'] in matched_db_doc_ids: continue - ident_matches = ex_ident and (ex_ident == db_card['AusweisIdent']) + ident_matches = ex_ident and (ex_ident == db_card['AusweisIdent']) secondary_matches = (ex_name and ex_name == db_card['SchülerName']) and \ (ex_class and ex_class == db_card['Klasse']) @@ -2347,15 +2364,18 @@ def _upload_student_cards_excel(): db_ids_to_delete = [] if validation_only: - flash( - f'Validierung erfolgreich ({len(planned_rows)} Excel-Zeilen). ' - f'Abgleich: {matched_count} unverändert, {len(rows_to_create)} neu, {len(db_ids_to_delete)} zum Löschen.', - 'success' - ) + warning_text = f" Hinweise: {'; '.join([f'Zeile {n}: {msg}' for n, msg in validation_warnings[:10]])}" if validation_warnings else "" + if rollover_mode: + flash( + f'Validierung erfolgreich ({len(planned_rows)} Excel-Zeilen). ' + f'Abgleich-Vorschau: {matched_count} unverändert, {len(rows_to_create)} neu, {len(db_ids_to_delete)} zum Löschen.{warning_text}', + 'success' + ) + else: + flash(f'Validierung erfolgreich: {len(planned_rows)} Ausweise würden importiert.{warning_text}', + 'success') return redirect(url_for('student_cards_admin')) - student_cards_col = db['student_cards'] - deleted_count = 0 if db_ids_to_delete: res = student_cards_col.delete_many({'_id': {'$in': db_ids_to_delete}}) @@ -2363,18 +2383,9 @@ def _upload_student_cards_excel(): created_total = 0 for row in rows_to_create: - row_ausweis_id = row['ausweis_id'] - if not row_ausweis_id: - row_ausweis_id = generate_ausweis_id(existing_ids) - existing_ids.add(row_ausweis_id.upper()) - - row_ausweis_ident = row['ausweis_ident'] - if not row_ausweis_ident: - random_chars = "".join(random.choices(string.ascii_uppercase + string.digits, k=5)) - row_ausweis_ident = f"LD-{random_chars}" - encrypted_payload = encrypt_document_fields( { + 'ausweis_ident': row['ausweis_ident'], 'SchülerName': row['student_name'], 'Klasse': row['class_name'], 'Notizen': row['notes'], @@ -2382,8 +2393,7 @@ def _upload_student_cards_excel(): STUDENT_CARD_ENCRYPTED_FIELDS ) student_cards_col.insert_one({ - 'AusweisId': row_ausweis_id, - 'AusweisIdent': row_ausweis_ident, + 'AusweisId': row['ausweis_id'], 'StandardAusleihdauer': int(row['default_borrow_days']), 'Erstellt': datetime.datetime.now(), **encrypted_payload, @@ -2391,20 +2401,21 @@ def _upload_student_cards_excel(): created_total += 1 except Exception as exc: - app.logger.error(f'Error importing student cards: {exc}') - flash('Fehler beim Verarbeiten der Bibliotheksausweise.', 'error') + app.logger.error(f'Error importing student cards from Excel: {exc}') + flash('Fehler beim Import der Bibliotheksausweise.', 'error') return redirect(url_for('student_cards_admin')) finally: client.close() + warning_details = f" Hinweise: {'; '.join([f'Zeile {n}: {msg}' for n, msg in validation_warnings[:10]])}" if validation_warnings else "" if rollover_mode: flash( f'Schuljahres-Abgleich erfolgreich: {matched_count} Schüler beibehalten, ' - f'{created_total} neu hinzugefügt, {deleted_count} alte Einträge gelöscht.', + f'{created_total} neu hinzugefügt, {deleted_count} alte Einträge gelöscht.{warning_details}', 'success' ) else: - flash(f'Excel-Import erfolgreich: {created_total} Ausweise importiert.', 'success') + flash(f'Excel-Import erfolgreich: {created_total} Ausweise importiert.{warning_details}', 'success') return redirect(url_for('student_cards_admin'))