changes to the _upload student to have the field encryptet
Release Inventarsystem / release-docker (push) Successful in 2m17s
Release Inventarsystem / release-docker (push) Successful in 2m17s
This commit is contained in:
+53
-42
@@ -2151,14 +2151,15 @@ def generate_ausweis_id_excel(existing_ids_set):
|
|||||||
print(f"Already found: {new_id}, trying another...")
|
print(f"Already found: {new_id}, trying another...")
|
||||||
|
|
||||||
def _upload_student_cards_excel():
|
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:
|
if 'username' not in session:
|
||||||
flash('Nicht angemeldet.', 'error')
|
flash('Nicht angemeldet.', 'error')
|
||||||
return redirect(url_for('login'))
|
return redirect(url_for('login'))
|
||||||
|
|
||||||
current_permissions = us.get_effective_permissions(session['username'])
|
current_permissions = us.get_effective_permissions(session['username'])
|
||||||
|
|
||||||
if not current_permissions['actions'].get('can_manage_user', False):
|
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'))
|
return redirect(url_for('library_view'))
|
||||||
|
|
||||||
if not cfg.MODULES.is_enabled('student_cards'):
|
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')
|
flash('Nur .xlsx oder .csv Dateien werden unterstützt.', 'error')
|
||||||
return redirect(url_for('student_cards_admin'))
|
return redirect(url_for('student_cards_admin'))
|
||||||
|
|
||||||
# CHECKBOX / SCHALTER: Schuljahres-Abgleich aktiviert?
|
|
||||||
rollover_mode = request.form.get('rollover_mode') in ['true', '1', 'on']
|
rollover_mode = request.form.get('rollover_mode') in ['true', '1', 'on']
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -2220,7 +2220,7 @@ def _upload_student_cards_excel():
|
|||||||
}
|
}
|
||||||
|
|
||||||
validation_only = (request.form.get('excel_action') or '').strip().lower() == 'validate'
|
validation_only = (request.form.get('excel_action') or '').strip().lower() == 'validate'
|
||||||
max_rows = 15000
|
max_rows = 1500
|
||||||
|
|
||||||
planned_rows = []
|
planned_rows = []
|
||||||
validation_errors = []
|
validation_errors = []
|
||||||
@@ -2230,11 +2230,14 @@ def _upload_student_cards_excel():
|
|||||||
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
||||||
try:
|
try:
|
||||||
db = client[cfg.MONGODB_DB]
|
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:
|
student_cards_cursor = student_cards_col.find({}, {'AusweisId': 1})
|
||||||
if card.get('AusweisId'):
|
existing_ids.update(
|
||||||
existing_ids.add(str(card.get('AusweisId')).strip().upper())
|
str(card.get('AusweisId', '')).strip().upper()
|
||||||
|
for card in student_cards_cursor
|
||||||
|
if card.get('AusweisId')
|
||||||
|
)
|
||||||
|
|
||||||
processed_rows = 0
|
processed_rows = 0
|
||||||
for row_number, row_values in enumerate(data_rows, start=2):
|
for row_number, row_values in enumerate(data_rows, start=2):
|
||||||
@@ -2267,6 +2270,20 @@ def _upload_student_cards_excel():
|
|||||||
if not student_name:
|
if not student_name:
|
||||||
row_errors.append('Vorname und Nachname fehlen')
|
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:
|
if row_errors:
|
||||||
validation_errors.append((row_number, '; '.join(row_errors)))
|
validation_errors.append((row_number, '; '.join(row_errors)))
|
||||||
continue
|
continue
|
||||||
@@ -2276,8 +2293,6 @@ def _upload_student_cards_excel():
|
|||||||
'ausweis_id': ausweis_id,
|
'ausweis_id': ausweis_id,
|
||||||
'ausweis_ident': ausweis_ident,
|
'ausweis_ident': ausweis_ident,
|
||||||
'student_name': student_name,
|
'student_name': student_name,
|
||||||
'first_name': first_name,
|
|
||||||
'last_name': last_name,
|
|
||||||
'class_name': class_name,
|
'class_name': class_name,
|
||||||
'notes': notes,
|
'notes': notes,
|
||||||
'default_borrow_days': default_borrow_days,
|
'default_borrow_days': default_borrow_days,
|
||||||
@@ -2293,16 +2308,19 @@ def _upload_student_cards_excel():
|
|||||||
matched_count = 0
|
matched_count = 0
|
||||||
|
|
||||||
if rollover_mode:
|
if rollover_mode:
|
||||||
|
raw_db_cards = list(student_cards_col.find())
|
||||||
decrypted_db_cards = []
|
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:
|
try:
|
||||||
dec_ident = dp.decrypt_text(dec_ident)
|
dec_ident = decrypt_text(raw_ident)
|
||||||
except:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
decrypted_db_cards.append({
|
decrypted_db_cards.append({
|
||||||
@@ -2319,12 +2337,11 @@ def _upload_student_cards_excel():
|
|||||||
ex_class = str(excel_row['class_name'] or '').strip().lower()
|
ex_class = str(excel_row['class_name'] or '').strip().lower()
|
||||||
|
|
||||||
match_found = None
|
match_found = None
|
||||||
|
|
||||||
for db_card in decrypted_db_cards:
|
for db_card in decrypted_db_cards:
|
||||||
if db_card['_id'] in matched_db_doc_ids:
|
if db_card['_id'] in matched_db_doc_ids:
|
||||||
continue
|
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 \
|
secondary_matches = (ex_name and ex_name == db_card['SchülerName']) and \
|
||||||
(ex_class and ex_class == db_card['Klasse'])
|
(ex_class and ex_class == db_card['Klasse'])
|
||||||
|
|
||||||
@@ -2347,15 +2364,18 @@ def _upload_student_cards_excel():
|
|||||||
db_ids_to_delete = []
|
db_ids_to_delete = []
|
||||||
|
|
||||||
if validation_only:
|
if validation_only:
|
||||||
flash(
|
warning_text = f" Hinweise: {'; '.join([f'Zeile {n}: {msg}' for n, msg in validation_warnings[:10]])}" if validation_warnings else ""
|
||||||
f'Validierung erfolgreich ({len(planned_rows)} Excel-Zeilen). '
|
if rollover_mode:
|
||||||
f'Abgleich: {matched_count} unverändert, {len(rows_to_create)} neu, {len(db_ids_to_delete)} zum Löschen.',
|
flash(
|
||||||
'success'
|
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'))
|
return redirect(url_for('student_cards_admin'))
|
||||||
|
|
||||||
student_cards_col = db['student_cards']
|
|
||||||
|
|
||||||
deleted_count = 0
|
deleted_count = 0
|
||||||
if db_ids_to_delete:
|
if db_ids_to_delete:
|
||||||
res = student_cards_col.delete_many({'_id': {'$in': 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
|
created_total = 0
|
||||||
for row in rows_to_create:
|
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(
|
encrypted_payload = encrypt_document_fields(
|
||||||
{
|
{
|
||||||
|
'ausweis_ident': row['ausweis_ident'],
|
||||||
'SchülerName': row['student_name'],
|
'SchülerName': row['student_name'],
|
||||||
'Klasse': row['class_name'],
|
'Klasse': row['class_name'],
|
||||||
'Notizen': row['notes'],
|
'Notizen': row['notes'],
|
||||||
@@ -2382,8 +2393,7 @@ def _upload_student_cards_excel():
|
|||||||
STUDENT_CARD_ENCRYPTED_FIELDS
|
STUDENT_CARD_ENCRYPTED_FIELDS
|
||||||
)
|
)
|
||||||
student_cards_col.insert_one({
|
student_cards_col.insert_one({
|
||||||
'AusweisId': row_ausweis_id,
|
'AusweisId': row['ausweis_id'],
|
||||||
'AusweisIdent': row_ausweis_ident,
|
|
||||||
'StandardAusleihdauer': int(row['default_borrow_days']),
|
'StandardAusleihdauer': int(row['default_borrow_days']),
|
||||||
'Erstellt': datetime.datetime.now(),
|
'Erstellt': datetime.datetime.now(),
|
||||||
**encrypted_payload,
|
**encrypted_payload,
|
||||||
@@ -2391,20 +2401,21 @@ def _upload_student_cards_excel():
|
|||||||
created_total += 1
|
created_total += 1
|
||||||
|
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
app.logger.error(f'Error importing student cards: {exc}')
|
app.logger.error(f'Error importing student cards from Excel: {exc}')
|
||||||
flash('Fehler beim Verarbeiten der Bibliotheksausweise.', 'error')
|
flash('Fehler beim Import der Bibliotheksausweise.', 'error')
|
||||||
return redirect(url_for('student_cards_admin'))
|
return redirect(url_for('student_cards_admin'))
|
||||||
finally:
|
finally:
|
||||||
client.close()
|
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:
|
if rollover_mode:
|
||||||
flash(
|
flash(
|
||||||
f'Schuljahres-Abgleich erfolgreich: {matched_count} Schüler beibehalten, '
|
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'
|
'success'
|
||||||
)
|
)
|
||||||
else:
|
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'))
|
return redirect(url_for('student_cards_admin'))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user