Compare commits

...

7 Commits

3 changed files with 91 additions and 44 deletions
+51 -40
View File
@@ -158,6 +158,19 @@ def print(*args, **kwargs):
STUDENT_CARD_ENCRYPTED_FIELDS = ('ausweis_ident', 'SchülerName', 'Klasse', 'Notizen')
def _display_username(user_value):
"""Return a username for a stored user ID, with legacy value support."""
if user_value is None or str(user_value).strip() == '':
return ''
raw_value = str(user_value).strip()
user_doc = us.get_user_by_id(raw_value)
if user_doc:
return str(user_doc.get('Username') or user_doc.get('username') or raw_value)
return decrypt_text(raw_value)
def _decrypt_student_card_doc(card_doc):
if not card_doc:
return card_doc
@@ -1212,7 +1225,7 @@ def create_return_reminders():
# Falls der Benutzername verschlüsselt ist, hier entschlüsseln,
# damit der Admin den echten Namen/Ausweis lesen kann.
display_user = decrypt_text(username) if 'decrypt_text' in globals() else username
display_user = _display_username(username)
item_id = str(borrow_doc.get('Item', '')).strip()
item_doc = item_docs.get(item_id, {})
@@ -1383,7 +1396,7 @@ def update_appointment_statuses():
old_status = appointment.get('Status')
activation_user = str(appointment.get('User') or '').strip()
try:
activation_user = decrypt_text(activation_user) if activation_user else ''
activation_user = _display_username(activation_user)
except Exception:
pass
activation_item_name = str(appointment.get('Item') or 'Termin')
@@ -1450,7 +1463,7 @@ def update_appointment_statuses():
holder = ''
if item_doc and item_doc.get('User'):
try:
holder = decrypt_text(str(item_doc['User']))
holder = _display_username(item_doc['User'])
except Exception:
holder = str(item_doc['User'])
if not holder:
@@ -1464,12 +1477,12 @@ def update_appointment_statuses():
)
if active_holder and active_holder.get('User'):
try:
holder = decrypt_text(str(active_holder['User']))
holder = _display_username(active_holder['User'])
except Exception:
holder = str(active_holder['User'])
requested_user = str(appointment.get('User') or '').strip()
try:
requested_user = decrypt_text(requested_user) if requested_user else ''
requested_user = _display_username(requested_user)
except Exception:
pass
item_name = (item_doc or {}).get('Name') or str(item_id)
@@ -1647,7 +1660,7 @@ def update_appointment_statuses():
raw_user = str(appt.get('User', '')).strip()
# Entschlüsselung der AusweisId
decrypted_user = decrypt_text(raw_user) if 'decrypt_text' in globals() else raw_user
decrypted_user = _display_username(raw_user)
target_ausweis_id = decrypted_user if decrypted_user else raw_user
item_id = appt.get('Item')
@@ -4498,24 +4511,32 @@ def api_item_detail(item_id):
else:
status_label = 'Verfügbar'
# Helper function to get borrower display name
def get_borrower_name(user_raw):
if not user_raw:
return ''
try:
user_doc = student_cards_col.find_one({'_id': ObjectId(user_raw)})
if user_doc:
if user_doc.get('SchülerName'):
return decrypt_text(str(user_doc.get('SchülerName', '')))
return str(user_doc.get('AusweisId', ''))
except Exception:
pass
return str(user_raw)
# Prefer the most recent active borrower across the group
borrower_value = ''
for rec in borrow_records:
if rec.get('Status') == 'active' and rec.get('User'):
try:
user_raw = rec.get('User')
user_doc = student_cards_col.find_one({'_id': ObjectId(user_raw)}) if user_raw else None
if user_doc:
borrower_value = decrypt_text(str(user_doc.get('SchülerName', ''))) if user_doc.get('SchülerName') else str(user_doc.get('AusweisId', ''))
except Exception:
borrower_value = str(rec.get('User', ''))
borrower_value = get_borrower_name(rec.get('User'))
break
if not borrower_value and item.get('User'):
try:
item_user = item.get('User')
if item_user is not None:
borrower_value = decrypt_text(str(item_user))
borrower_value = _display_username(item_user)
except Exception:
borrower_value = str(item.get('User', ''))
@@ -4531,18 +4552,13 @@ def api_item_detail(item_id):
rows = []
for rec in borrow_records[:3]:
user_raw = rec.get('User')
user_doc = student_cards_col.find_one({'_id': ObjectId(user_raw)}) if user_raw else None
try:
user = user_doc if user_doc is not None else ''
except Exception:
user = user_doc
rec_borrower_name = get_borrower_name(rec.get('User')) or '-'
status = rec.get('Status', '')
start = fmt_dt(rec.get('Start'))
end = fmt_dt(rec.get('End'))
notes = html.escape(str(rec.get('Notes') or ''))
rows.append(
f"<li><strong>{html.escape(str(user or '-'))}</strong> — "
f"<li><strong>{html.escape(rec_borrower_name)}</strong> — "
f"{html.escape(str(status))} — "
f"{html.escape(str(start))} → {html.escape(str(end))}"
f"{(' — ' + notes) if notes else ''}</li>"
@@ -8016,10 +8032,7 @@ def get_planned_bookings(item_id):
bookings = []
for r in cursor:
raw_user = r.get('User') or ''
try:
booking_user = decrypt_text(raw_user) if raw_user else ''
except Exception:
booking_user = str(raw_user)
booking_user = _display_username(raw_user)
bookings.append({
'id': str(r.get('_id')),
'user': booking_user,
@@ -8050,10 +8063,7 @@ def get_planned_bookings_public(item_id):
bookings = []
for r in cursor:
raw_user = r.get('User') or ''
try:
booking_user = decrypt_text(raw_user) if raw_user else ''
except Exception:
booking_user = str(raw_user)
booking_user = _display_username(raw_user)
bookings.append({
'user': booking_user,
'period': r.get('Period'),
@@ -8897,7 +8907,7 @@ def user_del():
fullname = None
users_list.append({
'username': decrypt_text(username),
'username': _display_username(username),
'admin': user.get('Admin', False),
'fullname': fullname,
'name': name,
@@ -9038,7 +9048,8 @@ def admin_borrowings():
has_damage = False
raw_user = r.get('User', '')
decrypted_user = decrypt_text(raw_user) if raw_user else ''
decrypted_user = _display_username(raw_user)
entries.append({
'id': str(r.get('_id')),
@@ -10272,8 +10283,8 @@ def library_item_invoices(item_id):
entries.append({
'borrow_id': str(borrow_doc.get('_id')),
'borrow_status': borrow_doc.get('Status', ''),
'borrow_user': decrypt_text(borrow_doc.get('User', '')) if hasattr(borrow_doc,
'get') and borrow_doc.get(
'borrow_user': _display_username(borrow_doc.get('User', '')) if hasattr(borrow_doc,
'get') and borrow_doc.get(
'User') else '',
'borrow_start': borrow_doc.get('Start').strftime('%d.%m.%Y %H:%M') if isinstance(
borrow_doc.get('Start'), datetime.datetime) else '',
@@ -10373,7 +10384,7 @@ def library_item_invoices(item_id):
))
for b in damage_borrow_docs:
borrow_user = decrypt_text(b.get('User', '')) if b.get('User') else '—'
borrow_user = _display_username(b.get('User', '')) if b.get('User') else '—'
d_data = b.get('DamageData') or {}
if not isinstance(d_data, dict): d_data = {}
@@ -10663,7 +10674,7 @@ def logs():
formatted_items.append({
'Item': item_name,
'User': decrypt_text(username),
'User': _display_username(username),
'Start': start_date,
'End': end_date,
'Duration': duration,
@@ -10705,7 +10716,7 @@ def logs():
note = log_item.get('note', '')
formatted_items.append({
'Item': item_name,
'User': decrypt_text(log_item.get('user', 'Unknown User')),
'User': _display_username(log_item.get('user', 'Unknown User')),
'Start': ts_display,
'End': '-',
'Duration': '-',
@@ -10719,7 +10730,7 @@ def logs():
resolved_count = log_item.get('resolved_count', 0)
formatted_items.append({
'Item': item_name,
'User': decrypt_text(log_item.get('user', 'Unknown User')),
'User': _display_username(log_item.get('user', 'Unknown User')),
'Start': ts_display,
'End': '-',
'Duration': '-',
@@ -11924,10 +11935,10 @@ def admin_damaged_items():
# Benutzernamen der Ausleihe entschlüsseln
if active_borrow and active_borrow.get('User'):
active_borrow['User'] = decrypt_text(active_borrow['User'])
active_borrow['User'] = _display_username(active_borrow['User'])
# Direkt am Item hinterlegten Nutzer entschlüsseln
item_user = decrypt_text(item.get('User')) if item.get('User') else ''
item_user = _display_username(item.get('User')) if item.get('User') else ''
# Datenstruktur exakt für dein Jinja2 Template aufbauen
damaged_items.append({
@@ -12500,7 +12511,7 @@ def cancel_ausleihung_route(id):
ausleihung_status = ausleihung.get('Status', 'unknown')
raw_ausleihung_user = ausleihung.get('User', '')
try:
ausleihung_user = decrypt_text(raw_ausleihung_user) if raw_ausleihung_user else ''
ausleihung_user = _display_username(raw_ausleihung_user)
except Exception:
ausleihung_user = str(raw_ausleihung_user or '')
print(f"Found ausleihung: ID={id}, Status={ausleihung_status}")
+36
View File
@@ -874,6 +874,42 @@ def get_user(username):
client.close()
def get_user_by_id(user_id):
"""Retrieve a user by MongoDB document ID."""
if user_id is None:
return None
lookup_values = [str(user_id)]
if ObjectId.is_valid(str(user_id)):
lookup_values.insert(0, ObjectId(str(user_id)))
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
try:
def find_in_db(database_name):
users = client[database_name]['users']
for lookup_value in lookup_values:
user = users.find_one({'_id': lookup_value})
if user:
return user
return None
tenant_db, tenant_id = _resolve_request_tenant_db()
if tenant_db:
user = find_in_db(tenant_db)
if user:
return user
if _has_tenant_configs() and tenant_db is None:
logger.warning(
"Refusing default DB fallback for user ID lookup because tenant configs exist and no tenant was resolved."
)
return None
return find_in_db(cfg.MONGODB_DB)
finally:
client.close()
def check_admin(username):
"""Check if a user has administrator privileges."""
user = get_user(username)
+4 -4
View File
@@ -3368,10 +3368,11 @@ document.addEventListener('DOMContentLoaded', ()=>{
function loadItems(offset = 0, append = false, searchTerm = '', searchScope = 'all') {
// Keep list payload lightweight; full details are fetched on-demand in openItemQuick.
const searchParams = searchTerm
const searchParams = searchTerm && searchScope === 'title_description'
? `&search=${encodeURIComponent(searchTerm)}&search_scope=${encodeURIComponent(searchScope)}`
: '';
return fetch(`{{ url_for('get_items') }}?offset=${offset}&limit=${MAIN_ADMIN_ITEMS_PAGE_SIZE}&light_mode=true${searchParams}`)
const limit = (searchTerm && searchScope === 'all') ? 5000 : MAIN_ADMIN_ITEMS_PAGE_SIZE;
return fetch(`{{ url_for('get_items') }}?offset=${offset}&limit=${limit}&light_mode=true${searchParams}`)
.then(response => response.json())
.then(data => {
const itemsContainer = document.querySelector('#items-container');
@@ -3390,8 +3391,7 @@ document.addEventListener('DOMContentLoaded', ()=>{
if (!append && (!pageItems || pageItems.length === 0)) {
itemsContainer.innerHTML = `
<div class="no-items-message">
<div>Keine Objekte gefunden</div>
<a class="empty-state-cta" href="{{ url_for('upload_admin') }}">Erstellen sie hier ihr erstes Item</a>
<div>Kein Item gefunden</div>
</div>
`;
if (itemsIndicator) {