slight correction to also account for name and last_name
Release Inventarsystem / release-docker (push) Successful in 2m16s
Release Inventarsystem / release-docker (push) Successful in 2m16s
This commit is contained in:
+112
-59
@@ -7865,6 +7865,82 @@ def register():
|
||||
permission_page_options=PERMISSION_PAGE_OPTIONS
|
||||
)
|
||||
|
||||
def parse_csv_users(file_bytes):
|
||||
"""
|
||||
Liest CSV-Dateien extrem robust ein:
|
||||
- Erkennt automatisch UTF-8, UTF-8-SIG und Latin-1 (für Excel-Umlaute).
|
||||
- Erkennt automatisch das Trennzeichen (; oder , oder Tab).
|
||||
- Erkennt Vor- und Nachname unabhängig von der Spaltenreihenfolge und Headernamen.
|
||||
"""
|
||||
# 1. Dekodierung mit Fallback für deutsche Excel-Dateien
|
||||
try:
|
||||
content = file_bytes.decode('utf-8-sig')
|
||||
except UnicodeDecodeError:
|
||||
content = file_bytes.decode('latin-1')
|
||||
|
||||
lines = [line.strip() for line in content.splitlines() if line.strip()]
|
||||
if not lines:
|
||||
return []
|
||||
|
||||
# 2. Trennzeichen ermitteln (; , oder \t)
|
||||
first_line = lines[0]
|
||||
if first_line.count(';') >= first_line.count(','):
|
||||
delimiter = ';'
|
||||
elif first_line.count('\t') > first_line.count(','):
|
||||
delimiter = '\t'
|
||||
else:
|
||||
delimiter = ','
|
||||
|
||||
stream = io.StringIO(content, newline=None)
|
||||
reader = csv.DictReader(stream, delimiter=delimiter)
|
||||
|
||||
parsed_users = []
|
||||
|
||||
# 3. Auswertung mit DictReader (wenn Header vorhanden sind)
|
||||
if reader.fieldnames:
|
||||
for row in reader:
|
||||
# Keys normalisieren (kleingeschrieben, ohne Leerzeichen)
|
||||
cleaned_row = {str(k).strip().lower(): str(v).strip() for k, v in row.items() if k and v}
|
||||
|
||||
# Dynamisches Mapping für Vornamen
|
||||
name = (
|
||||
cleaned_row.get('vorname') or
|
||||
cleaned_row.get('first_name') or
|
||||
cleaned_row.get('firstname') or
|
||||
cleaned_row.get('name') or ''
|
||||
)
|
||||
|
||||
# Dynamisches Mapping für Nachnamen
|
||||
last_name = (
|
||||
cleaned_row.get('nachname') or
|
||||
cleaned_row.get('last_name') or
|
||||
cleaned_row.get('lastname') or
|
||||
cleaned_row.get('surname') or
|
||||
cleaned_row.get('familienname') or ''
|
||||
)
|
||||
|
||||
# Falls Header nicht erkannt wurden, aber Werte vorhanden sind (z.B. CSV ohne Header)
|
||||
if not name and not last_name:
|
||||
vals = [str(v).strip() for v in row.values() if v]
|
||||
if len(vals) >= 2:
|
||||
name, last_name = vals[0], vals[1]
|
||||
|
||||
if name or last_name:
|
||||
parsed_users.append({'name': name, 'last_name': last_name})
|
||||
else:
|
||||
# Fallback für dateien ohne Header
|
||||
stream.seek(0)
|
||||
raw_reader = csv.reader(stream, delimiter=delimiter)
|
||||
for row in raw_reader:
|
||||
clean_row = [str(cell).strip() for cell in row if str(cell).strip()]
|
||||
if len(clean_row) >= 2:
|
||||
# Header-Zeilen überspringen
|
||||
if clean_row[0].lower() in ['vorname', 'first_name', 'name'] and clean_row[1].lower() in ['nachname', 'last_name']:
|
||||
continue
|
||||
parsed_users.append({'name': clean_row[0], 'last_name': clean_row[1]})
|
||||
|
||||
return parsed_users
|
||||
|
||||
def generate_compliant_password(length=16):
|
||||
lowers = string.ascii_lowercase
|
||||
uppers = string.ascii_uppercase
|
||||
@@ -7983,77 +8059,54 @@ def register_csv():
|
||||
|
||||
permission_preset = (request.form.get('permission_preset') or 'standard_user').strip()
|
||||
|
||||
# 1. CSV über die robuste Funktion einlesen
|
||||
file_bytes = file.stream.read()
|
||||
raw_users = parse_csv_users(file_bytes)
|
||||
|
||||
if not raw_users:
|
||||
flash('Keine gültigen Benutzer in der CSV-Datei gefunden. Bitte prüfen Sie das Format.', 'error')
|
||||
return redirect(url_for('register'))
|
||||
|
||||
created_users = []
|
||||
|
||||
try:
|
||||
# Read file stream handling UTF-8 and BOM (Excel exports)
|
||||
file_stream = io.StringIO(file.stream.read().decode("utf-8-sig"), newline=None)
|
||||
for entry in raw_users:
|
||||
name = entry['name']
|
||||
last_name = entry['last_name']
|
||||
|
||||
# Sniff delimiter (comma or semicolon)
|
||||
sample = file_stream.read(2048)
|
||||
file_stream.seek(0)
|
||||
delimiter = ';' if ';' in sample else ','
|
||||
if not name or not last_name:
|
||||
continue
|
||||
|
||||
reader = csv.reader(file_stream, delimiter=delimiter)
|
||||
# Benutzernamen & Passwort generieren
|
||||
username = us.build_unique_username_from_name(name, last_name)
|
||||
password = generate_compliant_password(16)
|
||||
|
||||
for row_num, row in enumerate(reader, start=1):
|
||||
if not row or all(field.strip() == '' for field in row):
|
||||
continue # Skip empty rows
|
||||
# In DB speichern
|
||||
success = us.add_user(
|
||||
username=username,
|
||||
password=password,
|
||||
name=name,
|
||||
last_name=last_name,
|
||||
is_student=False,
|
||||
student_card_id=None,
|
||||
max_borrow_days=None,
|
||||
permission_preset=permission_preset,
|
||||
)
|
||||
|
||||
# Clean entries
|
||||
row = [field.strip() for field in row]
|
||||
|
||||
# Header row detection (Skip row if it looks like "Name, Nachname")
|
||||
if row_num == 1 and ('name' in row[0].lower() or 'vorname' in row[0].lower()):
|
||||
continue
|
||||
|
||||
if len(row) < 2:
|
||||
continue
|
||||
|
||||
name = row[0]
|
||||
last_name = row[1]
|
||||
|
||||
if not name or not last_name:
|
||||
continue
|
||||
|
||||
# 1. Generate Username via backend logic
|
||||
username = us.build_unique_username_from_name(name, last_name)
|
||||
|
||||
# 2. Generate Random Secure Password
|
||||
password = generate_compliant_password(16)
|
||||
|
||||
# 3. Add User to DB
|
||||
success = us.add_user(
|
||||
username=username,
|
||||
password=password,
|
||||
name=name,
|
||||
last_name=last_name,
|
||||
is_student=False,
|
||||
student_card_id=None,
|
||||
max_borrow_days=None,
|
||||
permission_preset=permission_preset,
|
||||
)
|
||||
|
||||
if success:
|
||||
created_users.append({
|
||||
'name': name,
|
||||
'last_name': last_name,
|
||||
'username': username,
|
||||
'password': password
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
flash(f'Fehler beim Verarbeiten der CSV-Datei: {str(e)}', 'error')
|
||||
return redirect(url_for('register'))
|
||||
if success:
|
||||
created_users.append({
|
||||
'name': name,
|
||||
'last_name': last_name,
|
||||
'username': username,
|
||||
'password': password
|
||||
})
|
||||
|
||||
if not created_users:
|
||||
flash('Keine gültigen Benutzer in der CSV-Datei gefunden.', 'error')
|
||||
flash('Fehler beim Erstellen der Benutzer aus der CSV.', 'error')
|
||||
return redirect(url_for('register'))
|
||||
|
||||
# Generate PDF
|
||||
# PDF mit Zugangsdaten generieren
|
||||
pdf_buffer = generate_credentials_pdf(created_users)
|
||||
|
||||
# Return downloadable PDF file
|
||||
return send_file(
|
||||
pdf_buffer,
|
||||
as_attachment=True,
|
||||
|
||||
Reference in New Issue
Block a user