From 01637c31ee149007e7074d14b92229a70c7331a9 Mon Sep 17 00:00:00 2001 From: AIIrondev Date: Fri, 21 Aug 2026 12:32:53 +0200 Subject: [PATCH] feat(library): add class filtering and sorting to library loans admin view - Add class filter dropdown and class column to borrowings table - Implement interactive client-side column sorting for tables - Update backend route to resolve and map user class information --- Web/app.py | 55 +++++++- Web/templates/library_borrowings_admin.html | 139 +++++++++++++++++--- 2 files changed, 168 insertions(+), 26 deletions(-) diff --git a/Web/app.py b/Web/app.py index 0a11cf8..de05efa 100755 --- a/Web/app.py +++ b/Web/app.py @@ -3314,7 +3314,7 @@ def library_loans_admin(): if 'username' not in session: flash('Ihnen ist es nicht gestattet auf dieser Internetanwendung, die eben besuchte Adrrese zu nutzen, versuchen sie es erneut nach dem sie sich mit einem berechtigten Nutzer angemeldet haben!', 'error') return redirect(url_for('login')) - + current_permissions = us.get_effective_permissions(session['username']) if not current_permissions['pages'].get('library_loans_admin', False): @@ -3342,10 +3342,12 @@ def library_loans_admin(): db = client[MONGODB_DB] items_col = db['items'] ausleihungen_col = db['ausleihungen'] + users_col = db['users'] library_items = list(items_col.find( {'ItemType': {'$in': LIBRARY_ITEM_TYPES}, 'Deleted': {'$ne': True}}, - {'Name': 1, 'Code_4': 1, 'Anschaffungskosten': 1, 'Condition': 1, 'HasDamage': 1, 'DamageReports': 1, 'Verfuegbar': 1, 'User': 1, 'ItemType': 1, 'Author': 1, 'ISBN': 1} + {'Name': 1, 'Code_4': 1, 'Anschaffungskosten': 1, 'Condition': 1, 'HasDamage': 1, 'DamageReports': 1, + 'Verfuegbar': 1, 'User': 1, 'ItemType': 1, 'Author': 1, 'ISBN': 1} )) item_map = {str(item['_id']): item for item in library_items if item.get('_id')} item_ids = list(item_map.keys()) @@ -3354,28 +3356,68 @@ def library_loans_admin(): if item_ids: active_records = list(ausleihungen_col.find( {'Item': {'$in': item_ids}, 'Status': {'$in': ['active', 'planned', 'completed']}}, - {'User': 1, 'Item': 1, 'Status': 1, 'Start': 1, 'End': 1, 'Period': 1, 'Notes': 1, 'InvoiceData': 1} + {'User': 1, 'Item': 1, 'Status': 1, 'Start': 1, 'End': 1, 'Period': 1, 'Notes': 1, 'InvoiceData': 1, + 'Klasse': 1, 'Class': 1, 'school_class': 1} ).sort('Start', -1)) + user_map = {} + if active_records: + raw_users = list({r.get('User') for r in active_records if r.get('User')}) + decrypted_users = [] + for ru in raw_users: + try: + du = decrypt_text(ru) if ru else '' + if du: + decrypted_users.append(du) + except Exception: + pass + + query_identifiers = list(set(raw_users + decrypted_users)) + if query_identifiers: + user_docs = list(users_col.find( + {'$or': [ + {'Username': {'$in': query_identifiers}}, + {'Name': {'$in': query_identifiers}}, + {'User': {'$in': query_identifiers}} + ]}, + {'Username': 1, 'Name': 1, 'User': 1, 'Klasse': 1, 'Class': 1, 'school_class': 1} + )) + for u in user_docs: + cls = u.get('Klasse') or u.get('Class') or u.get('school_class') or '' + if cls: + if u.get('Username'): user_map[u['Username']] = cls + if u.get('Name'): user_map[u['Name']] = cls + if u.get('User'): user_map[u['User']] = cls + active_item_ids = set() loan_entries = [] for record in active_records: item_id = str(record.get('Item') or '') - item_doc = item_map.get(item_id) if item_id and record.get('Status') == 'active': active_item_ids.add(item_id) + item_doc = item_map.get(item_id) if not item_doc: continue invoice_data = record.get('InvoiceData') or {} condition_value = str(item_doc.get('Condition', '')).strip().lower() - item_has_damage = bool(item_doc.get('HasDamage')) or condition_value == 'destroyed' or bool(item_doc.get('DamageReports')) + item_has_damage = bool(item_doc.get('HasDamage')) or condition_value == 'destroyed' or bool( + item_doc.get('DamageReports')) damage_reports = item_doc.get('DamageReports', []) or [] raw_user = record.get('User', '') decrypted_user = decrypt_text(raw_user) if raw_user else '' + user_class = ( + record.get('Klasse') + or record.get('Class') + or record.get('school_class') + or user_map.get(raw_user, '') + or user_map.get(decrypted_user, '') + or '' + ) + loan_entries.append({ 'id': str(record.get('_id')), 'item_id': item_id, @@ -3384,7 +3426,8 @@ def library_loans_admin(): 'item_author': item_doc.get('Author', ''), 'item_isbn': item_doc.get('ISBN', ''), 'item_cost_raw': item_doc.get('Anschaffungskosten', ''), - 'user': decrypted_user, + 'user': decrypted_user, + 'klasse': user_class, 'status': record.get('Status', ''), 'start': fmt_dt(record.get('Start')), 'end': fmt_dt(record.get('End')), diff --git a/Web/templates/library_borrowings_admin.html b/Web/templates/library_borrowings_admin.html index e6840fb..f24b663 100644 --- a/Web/templates/library_borrowings_admin.html +++ b/Web/templates/library_borrowings_admin.html @@ -72,9 +72,10 @@ color: #1f2937; } + /* Angepasst für 4 Filter-Felder statt 3 */ .filter-bar { display: grid; - grid-template-columns: 1fr 220px 220px; + grid-template-columns: 1fr 140px 180px 180px; gap: 10px; margin-bottom: 16px; } @@ -121,6 +122,7 @@ letter-spacing: 0.04em; color: #64748b; background: var(--ui-surface-soft); + user-select: none; /* Verhindert Textmarkierung beim Klicken */ } .library-table tr:hover td { @@ -149,6 +151,7 @@ .badge-open { background: #fee2e2; color: #991b1b; } .badge-paid { background: #dcfce7; color: #166534; } .badge-damaged { background: #fee2e2; color: #991b1b; } + .badge-class { background: #f1f5f9; color: #475569; border: 1px solid #cbd5e1; } /* Neues Badge für Klasse */ .row-actions { display: flex; @@ -222,15 +225,30 @@
- + + + + + @@ -242,18 +260,31 @@ - - - - - - + + + + + + + + + {% for e in loan_entries %} - + + +
StatusElementBenutzerZeitRechnungSchadenStatus ↕Element ↕Benutzer ↕Klasse ↕Zeit ↕Rechnung ↕Schaden ↕ Aktionen
{% if e.status == 'active' %} Aktiv @@ -272,11 +303,19 @@ -
{{ e.user }}
-
{{ e.start }}{% if e.end %} bis {{ e.end }}{% endif %}
+
{{ e.user }}
+
+ {% if e.klasse %} + {{ e.klasse }} + {% else %} + — + {% endif %}
{{ e.period or '—' }}
+
{{ e.start }}{% if e.end %} bis {{ e.end }}{% endif %}
{% if e.notes %}
{{ e.notes }}
{% endif %}
@@ -355,10 +394,11 @@ - - - - + + + + + @@ -489,6 +529,7 @@
ElementCodeSchadenStatusElement ↕Code ↕Schaden ↕Status ↕ Aktion