Compare commits

...

3 Commits

Author SHA1 Message Date
Aiirondev_dev ae4a7226fa Changes to implement the ausweis_ident variable to correctly idententify students with the same name
Release Inventarsystem / release-docker (push) Successful in 2m15s
2026-08-18 14:46:55 +02:00
Aiirondev_dev 16a10a8c09 fix of breaking error
Release Inventarsystem / release-docker (push) Successful in 2m14s
2026-08-18 12:35:15 +02:00
Aiirondev_dev 3d4048d23b esential bugs being fixed and some new adjustemnets for the student card functionality
Release Inventarsystem / release-docker (push) Failing after 1m2s
2026-08-18 12:28:55 +02:00
3 changed files with 75 additions and 14 deletions
+33 -13
View File
@@ -68,6 +68,7 @@ import logging
from logging.handlers import RotatingFileHandler
import secrets
import importlib
import atexit
try:
redis = importlib.import_module('redis')
except Exception:
@@ -152,7 +153,7 @@ def print(*args, **kwargs):
app.logger.info(message)
STUDENT_CARD_ENCRYPTED_FIELDS = ('SchülerName', 'Klasse', 'Notizen')
STUDENT_CARD_ENCRYPTED_FIELDS = ('ausweis_ident', 'SchülerName', 'Klasse', 'Notizen')
def _decrypt_student_card_doc(card_doc):
@@ -2190,12 +2191,12 @@ def _upload_student_cards_excel():
synonyms = {
'ausweis_id': ['ausweis_id', 'ausweisid', 'ausweis-id', 'karte', 'kartennummer', 'card_id', 'id'],
'first_name': ['vorname', 'first_name', 'firstname', 'rufname'],
'last_name': ['nachname', 'last_name', 'lastname'],
'class_name': ['klasse', 'class', 'class_name', 'jahrgang', 'jahrgangsstufe', 'stufe', 'gruppe', 'asv_klasse'],
'notes': ['notizen', 'notes', 'bemerkungen', 'bemerkung', 'hinweis', 'hinweise'],
'default_borrow_days': ['standard_ausleihdauer', 'ausleihdauer', 'borrow_days', 'tage', 'leihtage',
'max_borrow_days'],
'ausweis_ident': ['lokales Differenzierungsmerkmal', 'lokales differenzierungsmerkmal', 'lokales_differenzierungsmerkmal', 'ausweis_ident', 'differenzierungsmerkmal'],
'first_name': ['vorname', 'first_name', 'firstname', 'rufname', 'Vorname'],
'last_name': ['nachname', 'last_name', 'lastname', 'Nachname'],
'class_name': ['klasse', 'class', 'class_name', 'jahrgang', 'jahrgangsstufe', 'stufe', 'gruppe', 'asv_klasse', 'Jahrgang', 'Klasse'],
'notes': ['notizen', 'notes', 'bemerkungen', 'bemerkung', 'hinweis', 'hinweise', 'Notizen', 'Bemerkung', 'Hinweis', 'Hinweise'],
'default_borrow_days': ['standard_ausleihdauer', 'ausleihdauer', 'borrow_days', 'tage', 'leihtage', 'max_borrow_days', 'Ausleihdauer'],
}
def col_index(key):
@@ -2207,6 +2208,7 @@ def _upload_student_cards_excel():
mapped_indices = {
'ausweis_id': col_index('ausweis_id'),
'ausweis_ident': col_index('ausweis_ident'),
'first_name': col_index('first_name'),
'last_name': col_index('last_name'),
'class_name': col_index('class_name'),
@@ -2215,7 +2217,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 = []
@@ -2225,7 +2227,7 @@ def _upload_student_cards_excel():
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
try:
db = client[cfg.MONGODB_DB]
student_cards_cursor = db['student_cards'].find({}, {'AusweisId': 1})
existing_ids.update(
str(card.get('AusweisId', '')).strip().upper()
@@ -2247,29 +2249,34 @@ def _upload_student_cards_excel():
return row_values[idx]
ausweis_id = sanitize_form_value(val('ausweis_id'))
ausweis_ident = sanitize_form_value(val('ausweis_ident'))
class_name = sanitize_form_value(val('class_name'))
notes = sanitize_form_value(val('notes'))
# Ausleihdauer extrahieren und standardmäßig auf 14 setzen
default_borrow_days = _excel_int(val('default_borrow_days'))
if not default_borrow_days:
default_borrow_days = 14
# Vor- und Nachname sicher auslesen und zusammensetzen
first_name = sanitize_form_value(val('first_name')) or ""
last_name = sanitize_form_value(val('last_name')) or ""
student_name = f"{first_name} {last_name}".strip()
# Leere Zeilen überspringen
if not ausweis_id and not student_name and not class_name:
continue
row_errors = []
if not student_name:
row_errors.append('Vorname und Nachname fehlen')
# Logik für die Haupt-AusweisID
if not ausweis_id and student_name:
ausweis_id = generate_ausweis_id_excel(existing_ids)
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())
existing_ids.add(ausweis_id.upper())
elif ausweis_id:
ausweis_id = str(ausweis_id).strip().upper()
if ausweis_id in existing_ids:
@@ -2277,6 +2284,9 @@ def _upload_student_cards_excel():
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
@@ -2284,6 +2294,7 @@ def _upload_student_cards_excel():
planned_rows.append({
'row_number': row_number,
'ausweis_id': ausweis_id,
'ausweis_ident': ausweis_ident,
'student_name': student_name,
'class_name': class_name,
'notes': notes,
@@ -2314,6 +2325,7 @@ def _upload_student_cards_excel():
for row in planned_rows:
encrypted_payload = encrypt_document_fields(
{
'ausweis_ident': row['ausweis_ident'],
'SchülerName': row['student_name'],
'Klasse': row['class_name'],
'Notizen': row['notes'],
@@ -4085,6 +4097,7 @@ def student_cards_admin():
edit_mode = True
form_data = {
'card_id': str(card['_id']),
'ausweis_ident': card.get('ausweis_ident', ''),
'ausweis_id': card.get('AusweisId', ''),
'student_name': card.get('SchülerName', ''),
'default_borrow_days': card.get('StandardAusleihdauer', 14),
@@ -4099,6 +4112,7 @@ def student_cards_admin():
if request.method == 'POST':
action = request.form.get('action', 'add')
ausweis_id = request.form.get('ausweis_id', '').strip().upper()
ausweis_ident = request.form.get('ausweis_ident', '').strip()
student_name = request.form.get('student_name', '').strip()
student_name_alias = student_name
default_borrow_days = request.form.get('default_borrow_days', 14)
@@ -4124,9 +4138,12 @@ def student_cards_admin():
existing = student_cards.find_one({'AusweisId': ausweis_id, '_id': {'$ne': ObjectId(card_id)}})
if existing:
flash('Diese Ausweis-ID existiert bereits.', 'error')
if not ausweis_ident:
ausweis_ident = ausweis_id
else:
encrypted_payload = encrypt_document_fields(
{
'ausweis_ident': ausweis_ident,
'SchülerName': student_name_alias,
'Klasse': class_name,
'Notizen': notes,
@@ -4158,6 +4175,8 @@ def student_cards_admin():
else:
ausweis_id = generate_ausweis_id()
existing = False
if not ausweis_ident:
ausweis_ident = ausweis_id
if existing:
flash('Diese ID existiert bereits.', 'error')
@@ -4165,6 +4184,7 @@ def student_cards_admin():
try:
encrypted_payload = encrypt_document_fields(
{
'ausweis_ident': ausweis_ident,
'SchülerName': student_name_alias,
'Klasse': class_name,
'Notizen': notes,
+35
View File
@@ -704,6 +704,41 @@ def get_user_by_student_card(student_card_id):
# Do not call dp.decrypt_text() here because found_user is a MongoDB dictionary.
return found_user
def get_user_by_student_ident(student_ident):
"""Return user dict by student ident by decrypting all cards and matching."""
if not student_ident:
return None
# Normalisiere den Suchbegriff, den wir finden wollen
normalized_target = str(student_ident).strip()
if not normalized_target:
return None
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
try:
db = _get_tenant_db(client)
all_student_cards = db['student_cards'].find()
for user_doc in all_student_cards:
encrypted_ident = user_doc.get('AusweisIdent')
if encrypted_ident:
try:
decrypted_ident = dp.decrypt_text(encrypted_ident)
if decrypted_ident and str(decrypted_ident).strip() == normalized_target:
return user_doc
except Exception as e:
app.logger.error(f"Entschlüsselungsfehler bei ID {user_doc.get('_id')}: {e}")
continue
except Exception as exc:
app.logger.error(f"Datenbankfehler in get_user_by_student_ident: {exc}")
finally:
client.close()
return None
def make_admin(username):
"""Grant administrator privileges to a user."""
+7 -1
View File
@@ -249,7 +249,7 @@
<div style="border:1px solid #dbe4ee; border-radius:8px; padding:14px; margin-bottom:16px; background:#f8fbff;">
<h3 style="margin:0 0 8px 0;">Excel-Import Bibliotheksausweise</h3>
<p style="margin:0 0 10px 0; color:#555;">Laden Sie eine <strong>.xlsx</strong>- oder <strong>.csv</strong>-Datei hoch, zum Beispiel aus <strong>ASV (Amtliche Schuldaten)</strong>. Erkannt werden automatisch Spalten wie <strong>Name</strong>, <strong>Nachname</strong, <strong>Klasse</strong>, <strong>Ausweis-ID (optional)</strong>, <strong>Notizen (optional)</strong> und <strong>Standard-Ausleihdauer (optional)</strong>.</p>
<p style="margin:0 0 10px 0; color:#555;">Laden Sie eine <strong>.xlsx</strong>- oder <strong>.csv</strong>-Datei hoch, zum Beispiel aus <strong>ASV (Amtliche Schuldaten)</strong>. Erkannt werden automatisch Spalten wie <strong>Name</strong>, <strong>Nachname</strong, <strong>Klasse</strong>, <strong>Ausweis-ID (optional)</strong>, <strong>lokales Differenzierungsmerkmal (optional aber empfohlen)</strong>, <strong>Notizen (optional)</strong> und <strong>Standard-Ausleihdauer (optional)</strong>.</p>
<form method="POST" action="{{ url_for('upload_student_cards_excel') }}" enctype="multipart/form-data" style="display:flex; gap:10px; flex-wrap:wrap; align-items:center;">
<input type="file" name="student_cards_excel" accept=".xlsx,.csv" required>
<button type="submit" class="btn btn-secondary" name="excel_action" value="validate">Nur validieren</button>
@@ -276,6 +276,12 @@
value="{{ form_data.get('ausweis_id', '') }}"
placeholder="z.B. SIS2024001">
</div>
<div class="form-group">
<label for="ausweis_ident">Lokales Differenzierungsmerkmal</label>
<input type="text" id="ausweis_ident" name="ausweis_ident"
value="{{ form_data.get('ausweis_ident', '') }}"
placeholder="z.B. xw5oo123bbe">
</div>
<div class="form-group">
<label for="student_name">Schüler Name *</label>
<input type="text" id="student_name" name="student_name" required