Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| af9826547c | |||
| 87027cf3c9 |
+70
-40
@@ -10586,76 +10586,106 @@ def notifications_unread_status():
|
||||
|
||||
@app.route('/admin/damaged_items')
|
||||
def admin_damaged_items():
|
||||
"""Admin-Übersicht aller Ausleihen von beschädigten Objekten."""
|
||||
"""Admin-Übersicht aller defekten, reparierten oder zerstörten Items."""
|
||||
if 'username' not in session:
|
||||
flash('Anmeldung erforderlich.', 'error')
|
||||
return redirect(url_for('login'))
|
||||
|
||||
# SICHERHEIT: Berechtigungsprüfung (wie in admin_borrowings)
|
||||
# Entferne die Kommentare, falls du `us` in dieser Datei importiert hast
|
||||
"""
|
||||
current_permissions = us.get_effective_permissions(session['username'])
|
||||
if not current_permissions['pages'].get('admin_damaged_items', False):
|
||||
flash('Ihnen fehlen die nötigen Berechtigungen, um diese Aktion auszuführen.', 'error')
|
||||
return redirect(url_for('home_admin'))
|
||||
"""
|
||||
|
||||
# Import sicherstellen
|
||||
from modules.inventarsystem.data_protection import decrypt_text
|
||||
|
||||
client = None
|
||||
try:
|
||||
client = MongoClient(MONGODB_HOST, MONGODB_PORT)
|
||||
db = client[MONGODB_DB]
|
||||
ausleihungen_col = db['ausleihungen']
|
||||
items_col = db['items']
|
||||
ausleihungen_col = db['ausleihungen']
|
||||
|
||||
alle_ausleihungen = list(ausleihungen_col.find().sort('Start', -1))
|
||||
# 1. Alle Items suchen, die einen Schaden haben, repariert oder zerstört sind
|
||||
query = {
|
||||
'$or': [
|
||||
{'HasDamage': True},
|
||||
{'DamageReports': {'$exists': True, '$not': {'$size': 0}}},
|
||||
{'Condition': {'$in': ['destroyed', 'broken', 'damaged', 'repaired', 'fixed']}}
|
||||
]
|
||||
}
|
||||
|
||||
beschädigte_ausleihungen = []
|
||||
raw_items = list(items_col.find(query).sort('LastUpdated', -1))
|
||||
damaged_items = []
|
||||
|
||||
for record in alle_ausleihungen:
|
||||
item_id = record.get('Item')
|
||||
if not item_id:
|
||||
continue
|
||||
for item in raw_items:
|
||||
# Dynamischen Status ermitteln (wie zuvor besprochen)
|
||||
condition_value = str(item.get('Condition', '')).strip().lower()
|
||||
has_damage_flag = bool(item.get('HasDamage'))
|
||||
has_reports = bool(item.get('DamageReports'))
|
||||
|
||||
try:
|
||||
if isinstance(item_id, str):
|
||||
query_id = ObjectId(item_id)
|
||||
else:
|
||||
query_id = item_id
|
||||
if condition_value == 'destroyed':
|
||||
status_text = 'Komplett zerstört'
|
||||
status_color = 'danger' # Rot
|
||||
elif condition_value in ['repaired', 'fixed'] or (has_reports and not has_damage_flag):
|
||||
status_text = 'Bereits repariert'
|
||||
status_color = 'success' # Grün
|
||||
else:
|
||||
status_text = 'Aktuelles Problem'
|
||||
status_color = 'warning' # Gelb
|
||||
|
||||
item_doc = items_col.find_one({'_id': query_id})
|
||||
# Schadensberichte analysieren
|
||||
damage_reports = item.get('DamageReports', [])
|
||||
latest_report = damage_reports[-1] if damage_reports else {}
|
||||
|
||||
if item_doc:
|
||||
condition_value = str(item_doc.get('Condition', '')).strip().lower()
|
||||
has_damage = bool(item_doc.get('HasDamage')) or condition_value == 'destroyed' or bool(
|
||||
item_doc.get('DamageReports'))
|
||||
# Prüfen, ob es eine aktive oder geplante Ausleihe für dieses Item gibt
|
||||
active_borrow = ausleihungen_col.find_one({
|
||||
'Item': item.get('_id'), # Suche mit ObjectId
|
||||
'Status': {'$in': ['active', 'planned']}
|
||||
})
|
||||
|
||||
if has_damage:
|
||||
raw_user = record.get('User', '')
|
||||
if raw_user:
|
||||
record['User'] = decrypt_text(raw_user)
|
||||
# Falls die ID in der Ausleihen-Collection als String hinterlegt ist (Fallback)
|
||||
if not active_borrow:
|
||||
active_borrow = ausleihungen_col.find_one({
|
||||
'Item': str(item.get('_id')),
|
||||
'Status': {'$in': ['active', 'planned']}
|
||||
})
|
||||
|
||||
if item_doc.get('User'):
|
||||
item_doc['User'] = decrypt_text(item_doc['User'])
|
||||
# Benutzernamen der Ausleihe entschlüsseln
|
||||
if active_borrow and active_borrow.get('User'):
|
||||
active_borrow['User'] = decrypt_text(active_borrow['User'])
|
||||
|
||||
record['ItemDetails'] = item_doc
|
||||
beschädigte_ausleihungen.append(record)
|
||||
# Direkt am Item hinterlegten Nutzer entschlüsseln
|
||||
item_user = decrypt_text(item.get('User')) if item.get('User') else ''
|
||||
|
||||
except Exception as e:
|
||||
app.logger.warning(f"Konnte Item {item_id} für Ausleihe {record.get('_id')} nicht laden: {e}")
|
||||
# Datenstruktur exakt für dein Jinja2 Template aufbauen
|
||||
damaged_items.append({
|
||||
'id': str(item['_id']),
|
||||
'name': item.get('Name', ''),
|
||||
'code': item.get('Code_4', ''),
|
||||
'item_type': item.get('ItemType', ''),
|
||||
'author': item.get('Author', item.get('Autor', '')), # Deckt beide Schreibweisen ab
|
||||
'isbn': item.get('ISBN', ''),
|
||||
'borrow_user': item_user,
|
||||
'damage_count': len(damage_reports),
|
||||
'condition': item.get('Condition', '-'),
|
||||
'available': item.get('Verfuegbar', False),
|
||||
|
||||
# Letzte Meldung
|
||||
'latest_damage_description': latest_report.get('description', ''),
|
||||
'latest_damage_by': latest_report.get('reported_by', ''),
|
||||
'latest_damage_at': latest_report.get('reported_at', ''),
|
||||
|
||||
# Status & Ausleihe
|
||||
'status_text': status_text,
|
||||
'status_color': status_color,
|
||||
'active_borrow': active_borrow
|
||||
})
|
||||
|
||||
return render_template(
|
||||
'admin_damaged_items.html',
|
||||
ausleihungen=beschädigte_ausleihungen,
|
||||
damaged_items=damaged_items,
|
||||
library_module_enabled=cfg.MODULES.is_enabled('library'),
|
||||
student_cards_module_enabled=cfg.MODULES.is_enabled('student_cards'),
|
||||
mail_module_enabled=cfg.MODULES.is_enabled('mail')
|
||||
)
|
||||
|
||||
except Exception as exc:
|
||||
app.logger.error(f"Fehler beim Laden der beschädigten Objekte: {exc}")
|
||||
app.logger.error(f"Fehler beim Laden der defekten Items: {exc}")
|
||||
flash('Fehler beim Laden der Übersicht.', 'error')
|
||||
return redirect(url_for('home_admin'))
|
||||
finally:
|
||||
|
||||
@@ -319,15 +319,15 @@ THUMBNAIL_FOLDER = _get(_conf, ['upload', 'thumbnail_folder'], DEFAULTS['upload'
|
||||
PREVIEW_FOLDER = _get(_conf, ['upload', 'preview_folder'], DEFAULTS['upload']['preview_folder'])
|
||||
QR_CODE_FOLDER = _get(_conf, ['upload', 'qrcode_folder'], DEFAULTS['upload']['qrcode_folder'])
|
||||
|
||||
# Normalize to absolute paths to avoid cwd issues
|
||||
# This guarantees exact matching with Docker volume mounts
|
||||
if not os.path.isabs(UPLOAD_FOLDER):
|
||||
UPLOAD_FOLDER = os.path.join(BASE_DIR, os.path.relpath(UPLOAD_FOLDER, BASE_DIR))
|
||||
UPLOAD_FOLDER = os.path.abspath(os.path.join(BASE_DIR, "uploads"))
|
||||
if not os.path.isabs(THUMBNAIL_FOLDER):
|
||||
THUMBNAIL_FOLDER = os.path.join(BASE_DIR, os.path.relpath(THUMBNAIL_FOLDER, BASE_DIR))
|
||||
THUMBNAIL_FOLDER = os.path.abspath(os.path.join(BASE_DIR, "thumbnails"))
|
||||
if not os.path.isabs(PREVIEW_FOLDER):
|
||||
PREVIEW_FOLDER = os.path.join(BASE_DIR, os.path.relpath(PREVIEW_FOLDER, BASE_DIR))
|
||||
PREVIEW_FOLDER = os.path.abspath(os.path.join(BASE_DIR, "previews"))
|
||||
if not os.path.isabs(QR_CODE_FOLDER):
|
||||
QR_CODE_FOLDER = os.path.join(BASE_DIR, os.path.relpath(QR_CODE_FOLDER, BASE_DIR))
|
||||
QR_CODE_FOLDER = os.path.abspath(os.path.join(BASE_DIR, "QRCodes"))
|
||||
MAX_UPLOAD_MB = _get(_conf, ['upload', 'max_size_mb'], DEFAULTS['upload']['max_size_mb'])
|
||||
IMAGE_MAX_UPLOAD_MB = _get(_conf, ['upload', 'image_max_size_mb'], DEFAULTS['upload']['image_max_size_mb'])
|
||||
VIDEO_MAX_UPLOAD_MB = _get(_conf, ['upload', 'video_max_size_mb'], DEFAULTS['upload']['video_max_size_mb'])
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<div style="display:flex; justify-content:space-between; align-items:flex-start; gap:12px; flex-wrap:wrap; margin-bottom:16px;">
|
||||
<div>
|
||||
<h1 style="margin:0;">Defekte Items</h1>
|
||||
<p style="margin:6px 0 0; color:#64748b;">Eigenes Verwaltungsfenster fuer gemeldete Defekte mit schneller Reparatur-Funktion.</p>
|
||||
<p style="margin:6px 0 0; color:#64748b;">Eigenes Verwaltungsfenster für gemeldete Defekte mit schneller Reparatur-Funktion.</p>
|
||||
</div>
|
||||
<div style="display:flex; gap:8px; flex-wrap:wrap;">
|
||||
<a class="btn btn-outline-secondary" href="{{ url_for('admin_borrowings') }}">Ausleihen</a>
|
||||
@@ -42,7 +42,13 @@
|
||||
{% if item.isbn %}<div style="font-size:0.82rem; color:#64748b;">ISBN: {{ item.isbn }}</div>{% endif %}
|
||||
</td>
|
||||
<td style="padding:11px; border-bottom:1px solid #eef2f7; vertical-align:top;">
|
||||
<div style="display:inline-block; padding:3px 9px; border-radius:999px; background:#fee2e2; color:#991b1b; font-size:0.75rem; font-weight:700;">Defekt</div>
|
||||
|
||||
<!-- HIER IST DIE ÄNDERUNG: Dynamischer Status-Badge -->
|
||||
<div class="badge bg-{{ item.status_color }} rounded-pill" style="font-size:0.75rem; font-weight:700; padding:4px 10px;">
|
||||
{{ item.status_text }}
|
||||
</div>
|
||||
<!-- ENDE DER ÄNDERUNG -->
|
||||
|
||||
<div style="font-size:0.84rem; color:#475569; margin-top:6px;">Meldungen: {{ item.damage_count }}</div>
|
||||
<div style="font-size:0.84rem; color:#475569;">Condition: {{ item.condition or '-' }}</div>
|
||||
<div style="font-size:0.84rem; color:#475569;">Verfuegbar: {{ 'Ja' if item.available else 'Nein' }}</div>
|
||||
@@ -66,7 +72,12 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
<td style="padding:11px; border-bottom:1px solid #eef2f7; vertical-align:top;">
|
||||
<!-- Button wird ausgeblendet, falls das Item bereits repariert ist -->
|
||||
{% if item.condition not in ['repaired', 'fixed'] %}
|
||||
<button class="btn btn-success btn-sm" onclick="repairDamage('{{ item.id }}', this)">Als repariert markieren</button>
|
||||
{% else %}
|
||||
<span class="text-success" style="font-size: 0.85rem;"><i class="bi bi-check-circle"></i> Repariert</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
@@ -118,4 +129,4 @@ function repairDamage(itemId, button) {
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user