Compare commits

...

6 Commits

+67 -74
View File
@@ -8154,10 +8154,26 @@ def admin_audit_dashboard():
# DEC_START: Decrypt the sensitive fields for display
for row in audit_rows:
if "payload" in row:
# decrypt_document_fields acts in-place
decrypt_document_fields(row["payload"], SENSITIVE_AUDIT_FIELDS)
# DEC_END
payload_raw = row.get("payload")
if payload_raw and isinstance(payload_raw, str):
try:
# Safely evaluate the python-like dict string, providing context for ObjectId
safe_context = {"ObjectId": ObjectId, "None": None, "True": True, "False": False}
payload_dict = eval(payload_raw, {"__builtins__": {}}, safe_context)
if isinstance(payload_dict, dict):
# Decrypt the sensitive keys inside the extracted dictionary
decrypt_document_fields(payload_dict, SENSITIVE_AUDIT_FIELDS)
# Replace the raw string with the clean dictionary for the Jinja template
row["payload"] = payload_dict
except Exception as parse_err:
app.logger.error(f"Failed to parse audit payload string for index {row.get('chain_index')}: {parse_err}")
elif payload_raw and isinstance(payload_raw, dict):
# Fallback in case some newer log rows are already stored as proper dictionaries
decrypt_document_fields(payload_raw, SENSITIVE_AUDIT_FIELDS)
return render_template(
'admin_audit.html',
@@ -8204,11 +8220,26 @@ def admin_audit_export_pdf_official():
audit_rows = list(db['audit_log'].find({}).sort('chain_index', -1).limit(limit))
# DEC_START: Decrypt sensitive fields for the PDF report
for row in audit_rows:
if "payload" in row:
decrypt_document_fields(row["payload"], SENSITIVE_AUDIT_FIELDS)
# DEC_END
payload_raw = row.get("payload")
if payload_raw and isinstance(payload_raw, str):
try:
# Safely evaluate the python-like dict string with custom token support
safe_context = {"ObjectId": ObjectId, "None": None, "True": True, "False": False}
payload_dict = eval(payload_raw, {"__builtins__": {}}, safe_context)
if isinstance(payload_dict, dict):
# Decrypt the dictionary fields in-place
decrypt_document_fields(payload_dict, SENSITIVE_AUDIT_FIELDS)
# Replace string with the clean dictionary so the PDF generator can read it
row["payload"] = payload_dict
except Exception as parse_err:
app.logger.error(f"Failed to parse audit payload string for PDF export at index {row.get('chain_index')}: {parse_err}")
elif payload_raw and isinstance(payload_raw, dict):
# Fallback for standard dict payloads
decrypt_document_fields(payload_raw, SENSITIVE_AUDIT_FIELDS)
# Get school information from settings or use defaults
school_info = _get_school_info_for_export()
@@ -10366,91 +10397,53 @@ def notifications_unread_status():
client.close()
@app.route('/admin/damaged_items')
def admin_damaged_items():
"""Dedicated admin management window for damaged items."""
@app.route('/admin/damaged_items')
def damaged_items():
"""Admin-Übersicht aller aktiven und vergangenen Ausleihen."""
if 'username' not in session:
flash('Administratorrechte erforderlich.', 'error')
return redirect(url_for('login'))
'''
permissions = _get_current_user_permissions()
if not _action_access_allowed(permissions, 'can_manage_settings'):
flash('Sie haben keine Berechtigung, die Schulstammdaten zu ändern.', 'error')
if cfg.MODULES.is_enabled('library'):
return redirect(url_for('library_admin'))
'''
from modules.inventarsystem.data_protection import decrypt_text
from bson.objectid import ObjectId
client = None
try:
client = MongoClient(MONGODB_HOST, MONGODB_PORT)
db = client[MONGODB_DB]
items_col = db['items']
ausleihungen_col = db['ausleihungen']
items_col = db['items']
items = list(items_col.find(
{
'Deleted': {'$ne': True},
'$or': [
{'HasDamage': True},
{'Condition': 'destroyed'},
{'DamageReports.0': {'$exists': True}},
]
},
{
'Name': 1,
'Code_4': 1,
'ItemType': 1,
'Author': 1,
'ISBN': 1,
'Condition': 1,
'DamageReports': 1,
'DamageRepairs': 1,
'Verfuegbar': 1,
'User': 1,
'LastUpdated': 1,
}
).sort('LastUpdated', -1))
ausleihungen = list(ausleihungen_col.find().sort('Start', -1))
damaged_rows = []
for item_doc in items:
item_id = str(item_doc.get('_id'))
active_borrow = ausleihungen_col.find_one(
{'Item': item_id, 'Status': {'$in': ['active', 'planned']}},
{'_id': 1, 'User': 1, 'Status': 1, 'End': 1}
)
reports = item_doc.get('DamageReports', []) or []
latest_report = reports[0] if reports else {}
for record in ausleihungen:
raw_user = record.get('User', '')
if raw_user:
record['User'] = decrypt_text(raw_user)
damaged_rows.append({
'id': item_id,
'name': item_doc.get('Name', ''),
'code': item_doc.get('Code_4', ''),
'item_type': item_doc.get('ItemType', ''),
'author': item_doc.get('Author', ''),
'isbn': item_doc.get('ISBN', ''),
'condition': item_doc.get('Condition', ''),
'available': bool(item_doc.get('Verfuegbar', False)),
'borrow_user': item_doc.get('User', ''),
'damage_count': len(reports),
'damage_reports': reports,
'latest_damage_description': latest_report.get('description', ''),
'latest_damage_by': latest_report.get('reported_by', ''),
'latest_damage_at': latest_report.get('reported_at'),
'active_borrow': active_borrow,
'last_updated': item_doc.get('LastUpdated'),
})
item_id = record.get('Item')
if item_id:
try:
item_doc = items_col.find_one({'_id': ObjectId(item_id)})
if item_doc:
if item_doc.get('User'):
item_doc['User'] = decrypt_text(item_doc['User'])
record['ItemDetails'] = item_doc
except Exception as e:
app.logger.warning(f"Konnte Item {item_id} für Ausleihe {record.get('_id')} nicht laden: {e}")
return render_template(
'admin_damaged_items.html',
damaged_items=damaged_rows,
'admin_damaged_items.html',
ausleihungen=ausleihungen,
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"Error loading damaged-items admin view: {exc}")
flash('Fehler beim Laden der Defekte-Items-Verwaltung.', 'error')
app.logger.error(f"Fehler beim Laden der Ausleihen-Verwaltung: {exc}")
flash('Fehler beim Laden der Ausleihen-Übersicht.', 'error')
return redirect(url_for('home_admin'))
finally:
if client: