Compare commits

..

19 Commits

Author SHA1 Message Date
Aiirondev_dev f7c113b760 changes to the right page permission check 2026-07-25 14:10:43 +02:00
Aiirondev_dev f35f0d6908 changes to make the release process fluent 2026-07-24 20:46:05 +02:00
Aiirondev_dev a577c7bda7 start of the permision completion for test purposes 2026-07-24 20:25:52 +02:00
Aiirondev_dev b37e630cde prune release clearing of unused files 2026-07-24 20:06:57 +02:00
Aiirondev_dev aa0f7c68bd fix of a actions error 2026-07-24 19:34:23 +02:00
Aiirondev_dev 68596b6939 changes to fix the user authentification issues 2026-07-24 18:59:29 +02:00
Aiirondev_dev 8dbdcaff56 Addition of the decryption for the logs beeing shown 2026-07-23 18:57:32 +02:00
Aiirondev_dev 622e257145 change from invario.eu to invario-software.de 2026-07-19 21:31:36 +02:00
Aiirondev_dev 7e66dad7e7 cahnges to the decryption 2026-07-19 21:24:55 +02:00
Aiirondev_dev 69fb566e8a The release will change the valuable decryption 2026-07-19 21:17:02 +02:00
Aiirondev_dev 3e993f65e6 Fix of the endpoint name 2026-07-19 21:07:30 +02:00
Aiirondev_dev 3cffa4f601 slight changes 2026-07-19 21:00:56 +02:00
Aiirondev_dev adc484cc26 slight changes in hopes of debugging 2026-07-19 20:47:06 +02:00
Aiirondev_dev c99e61ac45 debugging fot the damaged view 2026-07-19 20:27:58 +02:00
Aiirondev_dev e1e488f723 changes to incorperate the Encryption frokm the borrower name correctly 2026-07-19 20:20:41 +02:00
Aiirondev_dev 0562aee04b changes to the decryption of the payloads from the audit event report download 2026-07-19 20:02:17 +02:00
Aiirondev_dev b1c104f36c changes to the processing of the decryption process 2026-07-19 19:53:44 +02:00
Aiirondev_dev 5afe05b2d2 changes to the Library Items Types wich caused some Issues with the right displayment 2026-07-18 12:20:20 +02:00
Aiirondev_dev 7207fef0d4 Chnages to the Items being shown to the Library User 2026-07-18 12:18:12 +02:00
7 changed files with 309 additions and 174 deletions
+24 -12
View File
@@ -125,7 +125,7 @@ jobs:
# Prüfen, ob Docker existiert und ob die Version ausreicht
if command -v docker >/dev/null 2>&1; then
# Extrahiere die Major-Version (z. B. "20" aus "20.10.24" oder "26" aus "26.1.0")
# Extrahiere die Major-Version
DOCKER_MAJOR=$(docker --version | grep -oE '[0-9]+' | head -n1)
# API 1.44 erfordert mindestens Docker v25
@@ -135,19 +135,31 @@ jobs:
fi
if [ "$install_docker" = true ]; then
echo "Veraltete oder fehlende Docker-Installation erkannt. Führe Update durch..."
if command -v apt-get >/dev/null 2>&1; then
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y curl
# Nutzt das offizielle Docker-Skript (installiert docker-ce statt das alte docker.io)
curl -fsSL https://get.docker.com | sh
elif command -v apk >/dev/null 2>&1; then
apk update
apk add --no-cache docker-cli
echo "Veraltete oder fehlende Docker-Installation erkannt. Lade statische Docker CLI herunter..."
DOCKER_VERSION="26.1.4"
# Download der statischen Binaries via curl oder wget (umgeht apt-get komplett)
if command -v curl >/dev/null 2>&1; then
curl -fsSLO "https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz"
else
echo "Error: no supported package manager found to install docker"
exit 1
wget -q "https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz"
fi
tar -xzf docker-${DOCKER_VERSION}.tgz
# Installation in lokalen Benutzer-Pfad, um sudo/root-Rechte-Probleme zu vermeiden
mkdir -p "$HOME/.local/bin"
cp docker/docker "$HOME/.local/bin/"
# Pfad für nachfolgende GitHub Actions Schritte verfügbar machen
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
# Pfad für diesen spezifischen Shell-Run exportieren
export PATH="$HOME/.local/bin:$PATH"
rm -rf docker docker-${DOCKER_VERSION}.tgz
echo "Docker CLI wurde erfolgreich aktualisiert."
else
echo "Docker CLI ist bereits auf einem aktuellen Stand."
fi
+96 -82
View File
@@ -289,7 +289,7 @@ SCHEDULER_INTERVAL = cfg.SCHEDULER_INTERVAL_MIN
SSL_CERT = cfg.SSL_CERT
SSL_KEY = cfg.SSL_KEY
LIBRARY_ITEM_TYPES = ('book', 'cd', 'dvd', 'other', 'schoolbook', 'Buch', 'Schulbuch', 'schulbuch')
LIBRARY_ITEM_TYPES = ('book', 'cd', 'dvd', 'schoolbook', 'Buch', 'Schulbuch', 'schulbuch')
INVOICE_CURRENCY = 'EUR'
NOTIFICATION_STATUS_CACHE_TTL = max(3, int(os.getenv('INVENTAR_NOTIFICATION_STATUS_CACHE_TTL', '8')))
@@ -1258,7 +1258,9 @@ def inject_version():
try:
client = MongoClient(MONGODB_HOST, MONGODB_PORT)
db = client[MONGODB_DB]
unread_notification_count = _get_unread_notification_count(db, session['username'], is_admin=is_admin)
# Pass the computed permission instead of the strict is_admin boolean
can_manage = current_permissions.get('actions', {}).get('can_manage_settings', False)
unread_notification_count = _get_unread_notification_count(db, session['username'], is_admin=(is_admin or can_manage))
except Exception:
unread_notification_count = 0
finally:
@@ -3066,15 +3068,22 @@ 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'))
if not us.check_admin(session['username']):
current_permissions = us.get_effective_permissions(session['username'])
if not current_permissions['pages'].get('library_loans_admin', False):
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'))
return redirect(url_for('library_view'))
if not cfg.MODULES.is_enabled('library'):
flash('Bibliotheks-Modul ist deaktiviert.', 'error')
return redirect(url_for('home_admin'))
return redirect(url_for('home'))
_ensure_audit_indexes_once()
# IMPORT HINZUGEFÜGT: Entschlüsselungs-Tool importieren
from modules.inventarsystem.data_protection import decrypt_text
def fmt_dt(dt):
try:
return dt.strftime('%d.%m.%Y %H:%M') if dt else ''
@@ -3121,6 +3130,9 @@ def library_loans_admin():
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 ''
loan_entries.append({
'id': str(record.get('_id')),
'item_id': item_id,
@@ -3128,7 +3140,7 @@ def library_loans_admin():
'item_code': item_doc.get('Code_4', ''),
'item_author': item_doc.get('Author', ''),
'item_isbn': item_doc.get('ISBN', ''),
'user': record.get('User', ''),
'user': decrypted_user,
'status': record.get('Status', ''),
'start': fmt_dt(record.get('Start')),
'end': fmt_dt(record.get('End')),
@@ -3181,7 +3193,6 @@ def library_loans_admin():
if client:
client.close()
@app.route('/api/library_items')
def api_library_items():
"""
@@ -3212,7 +3223,7 @@ def api_library_items():
ausleihungen_db = db['ausleihungen']
query = {
'ItemType': {'$in': ['book', 'cd', 'dvd', 'other', 'schoolbook', 'schulbuch', 'Buch', 'Schulbuch']},
'ItemType': {'$in': ['book', 'cd', 'dvd', 'schoolbook', 'schulbuch', 'Buch', 'Schulbuch']},
'IsGroupedSubItem': {'$ne': True},
'Deleted': {'$ne': True}
}
@@ -3338,7 +3349,7 @@ def api_library_items():
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
db = client[cfg.MONGODB_DB]
student_cards = db['student_cards']
card = student_cards.find_one({'_id': ObjectId(borrow_id)})
card = student_cards.find_one({'_id': ObjectId(borrower)}) if borrower else None
card = _decrypt_student_card_doc(card)
client.close()
borrower = card['SchülerName']
@@ -8048,6 +8059,8 @@ def admin_borrowings():
_ensure_audit_indexes_once()
from modules.inventarsystem.data_protection import decrypt_text
client = MongoClient(MONGODB_HOST, MONGODB_PORT)
db = client[MONGODB_DB]
ausleihungen = db['ausleihungen']
@@ -8081,6 +8094,10 @@ def admin_borrowings():
item_name = None
item_cost = None
has_damage = False
raw_user = r.get('User', '')
decrypted_user = decrypt_text(raw_user) if raw_user else ''
entries.append({
'id': str(r.get('_id')),
'item_id': str(item_doc.get('_id')) if item_doc and item_doc.get('_id') else str(it_id or ''),
@@ -8088,7 +8105,7 @@ def admin_borrowings():
'item_name': str(item_name or ''),
'item_cost': fmt_money(item_cost),
'item_cost_raw': item_cost if item_cost is not None else '',
'user': r.get('User', ''),
'user': decrypted_user,
'status': r.get('Status', ''),
'start': fmt_dt(r.get('Start')),
'end': fmt_dt(r.get('End')),
@@ -8154,10 +8171,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 +8237,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()
@@ -9239,6 +9287,10 @@ def logs():
logs_collection = db['system_logs']
extra_logs = list(logs_collection.find({'type': {'$in': ['damage_report', 'damage_repair']}}))
from modules.inventarsystem.data_protection import decrypt_text
from bson.objectid import ObjectId
for log_item in extra_logs:
log_type = log_item.get('type', '')
item_id = log_item.get('item_id')
@@ -9258,7 +9310,7 @@ def logs():
note = log_item.get('note', '')
formatted_items.append({
'Item': item_name,
'User': log_item.get('user', 'Unknown User'),
'User': decrypt_text(log_item.get('user', 'Unknown User')),
'Start': ts_display,
'End': '-',
'Duration': '-',
@@ -9272,7 +9324,7 @@ def logs():
resolved_count = log_item.get('resolved_count', 0)
formatted_items.append({
'Item': item_name,
'User': log_item.get('user', 'Unknown User'),
'User': decrypt_text(log_item.get('user', 'Unknown User')),
'Start': ts_display,
'End': '-',
'Duration': '-',
@@ -10368,89 +10420,51 @@ def notifications_unread_status():
@app.route('/admin/damaged_items')
def admin_damaged_items():
"""Dedicated admin management window for 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,
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:
+8 -2
View File
@@ -323,7 +323,8 @@ def get_effective_permissions(username):
if bool(user.get('Admin', False)):
return build_default_permission_payload('full_access')
preset_key = user.get('PermissionPreset') or 'standard_user'
preset_key = user.get('PermissionPreset')
print(preset_key)
payload = build_default_permission_payload(preset_key)
payload['actions'] = _normalize_bool_map(user.get('ActionPermissions', {}), payload['actions'])
payload['pages'] = _normalize_bool_map(user.get('PagePermissions', {}), payload['pages'])
@@ -552,10 +553,15 @@ def add_user(
for key, value in page_permissions.items():
permission_defaults['pages'][str(key)] = bool(value)
if permission_preset == "full_access":
can_admin_preset_based = True
else:
can_admin_preset_based = False
user_doc = {
'Username': username,
'Password': hashing(password),
'Admin': False,
'Admin': can_admin_preset_based,
'active_ausleihung': None,
'name': name.strip() if name else '',
'last_name': last_name.strip() if last_name else '',
+173 -70
View File
@@ -1130,7 +1130,7 @@
<li class="nav-item" data-nav-fixed="true">
<a class="nav-link {% if current_path == url_for('terminplan') %}nav-active{% endif %}" href="{{ url_for('terminplan') }}" data-tutorial-tip="Hier sehen Sie den Kalender mit den bestehenden Terminen.">Kalender</a>
</li>
{% if current_permissions.pages.get('terminplan', True) and current_permissions.actions.get('can_insert', True) %}
{% if current_permissions.pages.get('terminplan', False) and current_permissions.actions.get('can_insert', False) %}
<li class="nav-item">
<a class="nav-link quick-link-pill {% if current_path == url_for('terminplaner.configure') %}nav-active{% endif %}" href="{{ url_for('terminplaner.configure') }}" data-tutorial-tip="Neuen Terminplan erstellen und an Ihr Team versenden.">Neue Planung</a>
</li>
@@ -1145,20 +1145,22 @@
<a class="nav-link dropdown-toggle" href="#" id="termMoreDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false" title="Weitere Optionen">Mehr Optionen</a>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="termMoreDropdown">
{% if 'username' in session %}
{% if current_permissions.pages.get('tutorial_page', True) %}
{% if current_permissions.pages.get('tutorial_page', False) %}
<li><a class="dropdown-item" href="{{ url_for('tutorial_page') }}">Tutorial</a></li>
{% endif %}
{% if current_permissions.pages.get('admin_school_settings', False) %}
<li><a class="dropdown-item" href="{{ url_for('admin_school_settings') }}">Schulstammdaten</a></li>
{% if current_permissions.actions.get('can_view_logs', True) and current_permissions.pages.get('admin_audit_dashboard', True) %}
{% endif %}
{% if current_permissions.actions.get('can_view_logs', False) or current_permissions.pages.get('admin_audit_dashboard', False) %}
<li><a class="dropdown-item" href="{{ url_for('admin_audit_dashboard') }}">Audit Dashboard</a></li>
{% endif %}
<li><hr class="dropdown-divider"></li>
{% endif %}
{% if current_permissions.pages.get('home', True) %}
{% if current_permissions.pages.get('home', False) %}
<li><a class="dropdown-item" href="{{ url_for('home') }}">Inventarsystem</a></li>
{% endif %}
{% if current_permissions.pages.get('library_view', True) and library_module_enabled %}
{% if current_permissions.pages.get('library_view', False) and library_module_enabled %}
<li><a class="dropdown-item" href="{{ url_for('library_view') }}">Bibliothek</a></li>
{% endif %}
<li><hr class="dropdown-divider"></li>
@@ -1191,7 +1193,7 @@
<span class="user-notification-dot {% if unread_notification_count and unread_notification_count > 0 %}visible{% endif %}" aria-hidden="true"></span>
</button>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="invUserMenuDropdown">
{% if current_permissions.pages.get('notifications_view', True) %}
{% if current_permissions.pages.get('notifications_view', False) %}
<li><a class="dropdown-item" href="{{ url_for('notifications_view') }}">Benachrichtigungen</a></li>
{% endif %}
<li><hr class="dropdown-divider"></li>
@@ -1214,13 +1216,13 @@
</button>
<div class="collapse navbar-collapse" id="inventoryNavContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0" id="inventoryNavList">
{% if current_permissions.pages.get('home', True) %}
{% if current_permissions.pages.get('home', False) %}
<li class="nav-item" data-nav-fixed="true">
<a class="nav-link {% if current_path == url_for('home') %}nav-active{% endif %}" href="{{ url_for('home') }}" data-tutorial-tip="Starten Sie hier mit dem Materialbestand und suchen Sie nach Artikeln.">Artikel</a>
</li>
{% endif %}
{% if 'username' in session %}
{% if current_permissions.pages.get('my_borrowed_items', True) %}
{% if current_permissions.pages.get('my_borrowed_items', False) %}
<li class="nav-item">
<a class="nav-link quick-link-pill {% if current_path == url_for('my_borrowed_items') %}nav-active{% endif %}" href="{{ url_for('my_borrowed_items') }}" data-tutorial-tip="Ihre aktuellen Ausleihen und Rückgaben finden Sie hier.">Meine Ausleihen</a>
</li>
@@ -1239,42 +1241,44 @@
</a>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="invMoreDropdown">
{% if 'username' in session %}
{% if current_permissions.pages.get('tutorial_page', True) %}
{% if current_permissions.pages.get('tutorial_page', False) %}
<li><a class="dropdown-item" href="{{ url_for('tutorial_page') }}">Tutorial</a></li>
{% endif %}
{% if current_permissions.pages.get('upload_admin', True) and current_permissions.actions.get('can_insert', True) %}
{% if current_permissions.pages.get('upload_admin', False) and current_permissions.actions.get('can_insert', False) %}
<li><a class="dropdown-item" href="{{ url_for('upload_admin') }}"> Hochladen</a></li>
{% endif %}
<li><hr class="dropdown-divider"></li>
{% endif %}
{% if 'username' in session and (session.get('admin', False) or is_admin) and current_permissions.actions.get('can_manage_settings', True) %}
{% if 'username' in session and current_permissions.actions.get('can_manage_settings', False) %}
<li><h6 class="dropdown-header">Verwaltung</h6></li>
{% if current_permissions.pages.get('manage_filters', True) %}
{% if current_permissions.pages.get('manage_filters', False) %}
<li><a class="dropdown-item" href="{{ url_for('manage_filters') }}">Filter verwalten</a></li>
{% endif %}
{% if current_permissions.pages.get('manage_locations', True) %}
{% if current_permissions.pages.get('manage_locations', False) %}
<li><a class="dropdown-item" href="{{ url_for('manage_locations') }}">Orte verwalten</a></li>
{% endif %}
{% if current_permissions.pages.get('admin_school_settings', False) %}
<li><a class="dropdown-item" href="{{ url_for('admin_school_settings') }}">Schulstammdaten</a></li>
{% if current_permissions.pages.get('admin_borrowings', True) %}
{% endif %}
{% if current_permissions.pages.get('admin_borrowings', False) %}
<li><a class="dropdown-item" href="{{ url_for('admin_borrowings') }}">Ausleihen</a></li>
{% endif %}
{% if current_permissions.pages.get('admin_damaged_items', True) %}
{% if current_permissions.pages.get('admin_damaged_items', False) %}
<li><a class="dropdown-item" href="{{ url_for('admin_damaged_items') }}">Defekte Items</a></li>
{% endif %}
{% if current_permissions.actions.get('can_view_logs', True) and current_permissions.pages.get('admin_audit_dashboard', True) %}
{% if current_permissions.actions.get('can_view_logs', False) and current_permissions.pages.get('admin_audit_dashboard', False) %}
<li><a class="dropdown-item" href="{{ url_for('admin_audit_dashboard') }}">Audit Dashboard</a></li>
{% endif %}
{% if current_permissions.actions.get('can_view_logs', True) and current_permissions.pages.get('logs', True) %}
{% if current_permissions.actions.get('can_view_logs', False) and current_permissions.pages.get('logs', False) %}
<li><a class="dropdown-item" href="{{ url_for('logs') }}">Logs</a></li>
{% endif %}
<li><hr class="dropdown-divider"></li>
{% if current_permissions.actions.get('can_manage_users', True) %}
{% if current_permissions.actions.get('can_manage_users', False) %}
<li><h6 class="dropdown-header">System</h6></li>
{% if current_permissions.pages.get('user_del', True) %}
{% if current_permissions.pages.get('user_del', False) %}
<li><a class="dropdown-item" href="{{ url_for('user_del') }}">Benutzer verwalten</a></li>
{% endif %}
{% if current_permissions.pages.get('register', True) %}
{% if current_permissions.pages.get('register', False) %}
<li><a class="dropdown-item" href="{{ url_for('register') }}">Neuer Benutzer</a></li>
{% endif %}
<li><hr class="dropdown-divider"></li>
@@ -1311,7 +1315,7 @@
<span class="user-notification-dot {% if unread_notification_count and unread_notification_count > 0 %}visible{% endif %}" aria-hidden="true"></span>
</button>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="invUserMenuDropdown">
{% if current_permissions.pages.get('notifications_view', True) %}
{% if current_permissions.pages.get('notifications_view', False) %}
<li><a class="dropdown-item" href="{{ url_for('notifications_view') }}">Benachrichtigungen</a></li>
{% endif %}
<li><hr class="dropdown-divider"></li>
@@ -1336,19 +1340,19 @@
</button>
<div class="collapse navbar-collapse" id="libraryNavContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0" id="libraryNavList">
{% if current_permissions.pages.get('library_view', True) %}
{% if current_permissions.pages.get('library_view', False) %}
<li class="nav-item" data-nav-fixed="true">
<a class="nav-link {% if current_path == url_for('library_view') %}nav-active{% endif %}" href="{{ url_for('library_view') }}" data-tutorial-tip="Die Bibliothek zeigt Ihnen alle Medien und verfügbaren Bücher.">Medien</a>
</li>
{% endif %}
{% if 'username' in session %}
{% if current_permissions.pages.get('tutorial_page', True) %}
{% if current_permissions.pages.get('tutorial_page', False) %}
<li class="nav-item">
<a class="nav-link quick-link-pill {% if current_path == url_for('tutorial_page') %}nav-active{% endif %}" href="{{ url_for('tutorial_page') }}" data-tutorial-tip="Nutzen Sie das Tutorial, um die Bibliotheksfunktionen kennenzulernen.">Tutorial</a>
</li>
{% endif %}
{% endif %}
{% if 'username' in session and current_permissions.actions.get('can_insert', True) and current_permissions.pages.get('library_admin', True) %}
{% if 'username' in session and current_permissions.actions.get('can_insert', False) and current_permissions.pages.get('library_admin', False) %}
<li class="nav-item">
<a class="nav-link nav-priority-link {% if current_path == url_for('library_admin') %}nav-active{% endif %}" href="{{ url_for('library_admin') }}" data-tutorial-tip="Neue Bibliotheksmedien können hier aufgenommen werden.">📖 Hochladen</a>
</li>
@@ -1365,22 +1369,24 @@
Mehr Optionen
</a>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="libMoreDropdown">
{% if 'username' in session and (session.get('admin', False) or is_admin) and current_permissions.actions.get('can_manage_settings', True) %}
{% if 'username' in session and current_permissions.actions.get('can_manage_settings', False) %}
<li><h6 class="dropdown-header">Bibliotheks-Verwaltung</h6></li>
{% if current_permissions.pages.get('library_loans_admin', True) %}
{% if current_permissions.pages.get('library_loans_admin', False) %}
<li><a class="dropdown-item" href="{{ url_for('library_loans_admin') }}">Ausleihen / Defekte Items</a></li>
{% endif %}
{% if student_cards_module_enabled %}
<li><a class="dropdown-item" href="{{ url_for('student_cards_admin') }}">Bibliotheksausweis</a></li>
{% endif %}
{% if current_permissions.pages.get('admin_school_settings', False) %}
<li><a class="dropdown-item" href="{{ url_for('admin_school_settings') }}">Schulstammdaten</a></li>
{% endif %}
<li><hr class="dropdown-divider"></li>
{% if current_permissions.actions.get('can_manage_users', True) %}
{% if current_permissions.actions.get('can_manage_users', False) %}
<li><h6 class="dropdown-header">System</h6></li>
{% if current_permissions.pages.get('user_del', True) %}
{% if current_permissions.pages.get('user_del', False) %}
<li><a class="dropdown-item" href="{{ url_for('user_del') }}">Benutzer verwalten</a></li>
{% endif %}
{% if current_permissions.pages.get('register', True) %}
{% if current_permissions.pages.get('register', False) %}
<li><a class="dropdown-item" href="{{ url_for('register') }}">Neuer Benutzer</a></li>
{% endif %}
<li><hr class="dropdown-divider"></li>
@@ -1414,7 +1420,7 @@
<span class="user-notification-dot {% if unread_notification_count and unread_notification_count > 0 %}visible{% endif %}" aria-hidden="true"></span>
</button>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="libUserMenuDropdown">
{% if current_permissions.pages.get('notifications_view', True) %}
{% if current_permissions.pages.get('notifications_view', False) %}
<li><a class="dropdown-item" href="{{ url_for('notifications_view') }}">Benachrichtigungen</a></li>
{% endif %}
<li><hr class="dropdown-divider"></li>
@@ -1642,30 +1648,79 @@
</div>
<datalist id="function-search-options">
{% if current_permissions.pages.get('home', False) %}
<option value="Artikel"></option>
<option value="Meine Ausleihen"></option>
<option value="Benachrichtigungen"></option>
<option value="Tutorial"></option>
{% endif %}
{% if 'username' in session %}
{% if current_permissions.pages.get('my_borrowed_items', False) %}
<option value="Meine Ausleihen"></option>
{% endif %}
{% if current_permissions.pages.get('notifications_view', False) %}
<option value="Benachrichtigungen"></option>
{% endif %}
{% if current_permissions.pages.get('tutorial_page', False) %}
<option value="Tutorial"></option>
{% endif %}
{% endif %}
<option value="Impressum"></option>
<option value="Lizenz"></option>
{% if library_module_enabled %}
<option value="Bibliothek"></option>
<option value="Meine Medien"></option>
{% endif %}
{% if 'username' in session and (session.get('admin', False) or is_admin) %}
<option value="Hochladen"></option>
<option value="Ausleihen Verwaltung"></option>
<option value="Defekte Items"></option>
<option value="Filter verwalten"></option>
<option value="Orte verwalten"></option>
<option value="Schulstammdaten"></option>
<option value="Audit Dashboard"></option>
<option value="Logs"></option>
<option value="Benutzer verwalten"></option>
<option value="Neuer Benutzer"></option>
{% if student_cards_module_enabled %}
<option value="Bibliotheksausweis"></option>
{% if current_permissions.pages.get('library_view', False) %}
<option value="Bibliothek"></option>
{% endif %}
{% if 'username' in session and current_permissions.pages.get('my_borrowed_items', False) %}
<option value="Meine Medien"></option>
{% endif %}
{% endif %}
{% if 'username' in session %}
{% if current_permissions.pages.get('upload_admin', False) and current_permissions.actions.get('can_insert', False) %}
<option value="Hochladen"></option>
{% endif %}
{% if current_permissions.pages.get('admin_borrowings', False) or current_permissions.pages.get('library_loans_admin', False) %}
<option value="Ausleihen Verwaltung"></option>
{% endif %}
{% if current_permissions.pages.get('admin_damaged_items', False) or current_permissions.pages.get('library_loans_admin', False) %}
<option value="Defekte Items"></option>
{% endif %}
{% if current_permissions.pages.get('manage_filters', False) %}
<option value="Filter verwalten"></option>
{% endif %}
{% if current_permissions.pages.get('manage_locations', False) %}
<option value="Orte verwalten"></option>
{% endif %}
{% if current_permissions.pages.get('admin_school_settings', False) %}
<option value="Schulstammdaten"></option>
{% endif %}
{% if current_permissions.actions.get('can_view_logs', False) and current_permissions.pages.get('admin_audit_dashboard', False) %}
<option value="Audit Dashboard"></option>
{% endif %}
{% if current_permissions.actions.get('can_view_logs', False) and current_permissions.pages.get('logs', False) %}
<option value="Logs"></option>
{% endif %}
{% if current_permissions.actions.get('can_manage_users', False) %}
{% if current_permissions.pages.get('user_del', False) %}
<option value="Benutzer verwalten"></option>
{% endif %}
{% if current_permissions.pages.get('register', False) %}
<option value="Neuer Benutzer"></option>
{% endif %}
{% endif %}
{% if student_cards_module_enabled and current_permissions.pages.get('student_cards_admin', False) %}
<option value="Bibliotheksausweis"></option>
{% endif %}
{% endif %}
</datalist>
@@ -1713,32 +1768,80 @@
const loginHintKey = username ? ('inventarsystem_notification_login_hint_v1_' + username) : null;
const functionSearchEntries = [
{% if current_permissions.pages.get('home', False) %}
{ label: 'Artikel', keywords: ['artikel', 'inventar', 'home'], url: {{ url_for('home')|tojson }} },
{ label: 'Meine Ausleihen', keywords: ['meine ausleihen', 'ausleihen', 'borrowed'], url: {{ url_for('my_borrowed_items')|tojson }} },
{ label: 'Benachrichtigungen', keywords: ['benachrichtigungen', 'nachrichten', 'notifications'], url: {{ url_for('notifications_view')|tojson }} },
{ label: 'Tutorial', keywords: ['tutorial', 'hilfe', 'anleitung'], url: {{ url_for('tutorial_page')|tojson }} },
{% endif %}
{% if 'username' in session %}
{% if current_permissions.pages.get('my_borrowed_items', False) %}
{ label: 'Meine Ausleihen', keywords: ['meine ausleihen', 'ausleihen', 'borrowed'], url: {{ url_for('my_borrowed_items')|tojson }} },
{% endif %}
{% if current_permissions.pages.get('notifications_view', False) %}
{ label: 'Benachrichtigungen', keywords: ['benachrichtigungen', 'nachrichten', 'notifications'], url: {{ url_for('notifications_view')|tojson }} },
{% endif %}
{% if current_permissions.pages.get('tutorial_page', False) %}
{ label: 'Tutorial', keywords: ['tutorial', 'hilfe', 'anleitung'], url: {{ url_for('tutorial_page')|tojson }} },
{% endif %}
{% endif %}
{ label: 'Impressum', keywords: ['impressum'], url: {{ url_for('impressum')|tojson }} },
{ label: 'Lizenz', keywords: ['lizenz', 'license'], url: {{ url_for('license')|tojson }} },
{% if library_module_enabled %}
{ label: 'Bibliothek', keywords: ['bibliothek', 'medien'], url: {{ url_for('library_view')|tojson }} },
{% endif %}
{% if 'username' in session and (session.get('admin', False) or is_admin) %}
{ label: 'Hochladen', keywords: ['hochladen', 'upload'], url: {{ url_for('upload_admin')|tojson }} },
{ label: 'Ausleihen Verwaltung', keywords: ['ausleihen verwaltung', 'admin borrowings'], url: {{ url_for('admin_borrowings')|tojson }} },
{ label: 'Defekte Items', keywords: ['defekte items', 'defekt', 'schaden'], url: {{ url_for('admin_damaged_items')|tojson }} },
{ label: 'Filter verwalten', keywords: ['filter verwalten', 'filter'], url: {{ url_for('manage_filters')|tojson }} },
{ label: 'Orte verwalten', keywords: ['orte verwalten', 'orte', 'location'], url: {{ url_for('manage_locations')|tojson }} },
{ label: 'Schulstammdaten', keywords: ['schule', 'settings', 'stammdaten', 'school settings'], url: {{ url_for('admin_school_settings')|tojson }} },
{ label: 'Audit Dashboard', keywords: ['audit', 'audit dashboard'], url: {{ url_for('admin_audit_dashboard')|tojson }} },
{ label: 'Logs', keywords: ['logs', 'protokoll'], url: {{ url_for('logs')|tojson }} },
{ label: 'Benutzer verwalten', keywords: ['benutzer verwalten', 'user'], url: {{ url_for('user_del')|tojson }} },
{ label: 'Neuer Benutzer', keywords: ['neuer benutzer', 'register'], url: {{ url_for('register')|tojson }} },
{% if library_module_enabled %}
{ label: 'Bibliotheks-Ausleihen', keywords: ['bibliotheks ausleihen', 'library loans'], url: {{ url_for('library_loans_admin')|tojson }} },
{% endif %}
{% if student_cards_module_enabled %}
{ label: 'Bibliotheksausweis', keywords: ['bibliotheksausweis', 'student card'], url: {{ url_for('student_cards_admin')|tojson }} },
{% if current_permissions.pages.get('library_view', False) %}
{ label: 'Bibliothek', keywords: ['bibliothek', 'medien'], url: {{ url_for('library_view')|tojson }} },
{% endif %}
{% endif %}
{% if 'username' in session %}
{% if current_permissions.pages.get('upload_admin', False) and current_permissions.actions.get('can_insert', False) %}
{ label: 'Hochladen', keywords: ['hochladen', 'upload'], url: {{ url_for('upload_admin')|tojson }} },
{% endif %}
{% if current_permissions.pages.get('admin_borrowings', False) %}
{ label: 'Ausleihen Verwaltung', keywords: ['ausleihen verwaltung', 'admin borrowings'], url: {{ url_for('admin_borrowings')|tojson }} },
{% endif %}
{% if current_permissions.pages.get('admin_damaged_items', False) %}
{ label: 'Defekte Items', keywords: ['defekte items', 'defekt', 'schaden'], url: {{ url_for('admin_damaged_items')|tojson }} },
{% endif %}
{% if current_permissions.pages.get('manage_filters', False) %}
{ label: 'Filter verwalten', keywords: ['filter verwalten', 'filter'], url: {{ url_for('manage_filters')|tojson }} },
{% endif %}
{% if current_permissions.pages.get('manage_locations', False) %}
{ label: 'Orte verwalten', keywords: ['orte verwalten', 'orte', 'location'], url: {{ url_for('manage_locations')|tojson }} },
{% endif %}
{% if current_permissions.pages.get('admin_school_settings', False) %}
{ label: 'Schulstammdaten', keywords: ['schule', 'settings', 'stammdaten', 'school settings'], url: {{ url_for('admin_school_settings')|tojson }} },
{% endif %}
{% if current_permissions.actions.get('can_view_logs', False) and current_permissions.pages.get('admin_audit_dashboard', False) %}
{ label: 'Audit Dashboard', keywords: ['audit', 'audit dashboard'], url: {{ url_for('admin_audit_dashboard')|tojson }} },
{% endif %}
{% if current_permissions.actions.get('can_view_logs', False) and current_permissions.pages.get('logs', False) %}
{ label: 'Logs', keywords: ['logs', 'protokoll'], url: {{ url_for('logs')|tojson }} },
{% endif %}
{% if current_permissions.actions.get('can_manage_users', False) %}
{% if current_permissions.pages.get('user_del', False) %}
{ label: 'Benutzer verwalten', keywords: ['benutzer verwalten', 'user'], url: {{ url_for('user_del')|tojson }} },
{% endif %}
{% if current_permissions.pages.get('register', False) %}
{ label: 'Neuer Benutzer', keywords: ['neuer benutzer', 'register'], url: {{ url_for('register')|tojson }} },
{% endif %}
{% endif %}
{% if library_module_enabled and current_permissions.pages.get('library_loans_admin', False) %}
{ label: 'Bibliotheks-Ausleihen', keywords: ['bibliotheks ausleihen', 'library loans'], url: {{ url_for('library_loans_admin')|tojson }} },
{% endif %}
{% if student_cards_module_enabled and current_permissions.pages.get('student_cards_admin', False) %}
{ label: 'Bibliotheksausweis', keywords: ['bibliotheksausweis', 'student card'], url: {{ url_for('student_cards_admin')|tojson }} },
{% endif %}
{% endif %}
];
+1 -1
View File
@@ -22,7 +22,7 @@
<p><strong>Name:</strong> Invario UG</p>
<p><strong>Adresse:</strong> Am Sportplatz 10<br>83052 Bruckmühl<br>Deutschland</p>
</address>
<p><strong>E-Mail:</strong> <a href="mailto:info@invario.eu">info@invario.eu</a></p>
<p><strong>E-Mail:</strong> <a href="mailto:info@invario-software.de">info@invario-software.de</a></p>
</div>
<div class="impressum-section mb-4">
+1 -1
View File
@@ -469,7 +469,7 @@
}
</style>
<div class="library-table-container" id="libraryTableContainer" data-can-edit="{{ 1 if is_admin else 0 }}">
<div class="library-table-container" id="libraryTableContainer" data-can-edit="{{ 1 if current_permissions.actions.get('can_edit', False) else 0 }}">
<!-- Header -->
<div class="library-header">
<h1>📚 Bibliothek</h1>
+1 -1
View File
@@ -122,7 +122,7 @@
<h3>Meldung von Sicherheitslücken</h3>
<div class="license-exception-notice">
<h3>⚠️ Responsible Disclosure</h3>
<p>Falls Sie eine Sicherheitslücke entdecken, wenden sie sich umgehend an die Email: info@invario.eu .
<p>Falls Sie eine Sicherheitslücke entdecken, wenden sie sich umgehend an die Email: info@invario-software.de .
</div>
</div>
</div><!-- /#pane-security -->