Layout angepasst

This commit is contained in:
Bkolb 2026-04-03 17:31:22 +02:00
parent 69ecc2e1f2
commit 87c3af5dc9
6 changed files with 194 additions and 2 deletions

View File

@ -20,7 +20,7 @@ from werkzeug.utils import secure_filename
from config import Config, COUNTRY_VAT_LABELS from config import Config, COUNTRY_VAT_LABELS
from db import get_connection, fetchone_dict, fetchall_dict from db import get_connection, fetchone_dict, fetchall_dict
from auth import login_required from auth import login_required
from permissions import is_video_allowed_for_level, is_course_allowed_for_level from permissions import is_video_allowed_for_level, is_course_allowed_for_level, get_allowed_checklist_levels_for_mandant_level
from security import ( from security import (
admin_required, admin_required,
get_current_user, get_current_user,
@ -1261,4 +1261,10 @@ def dokument_file(item_id):
stored_filename = row[0] stored_filename = row[0]
mandant_dir = os.path.join("/files", str(mandant_id)) mandant_dir = os.path.join("/files", str(mandant_id))
return send_from_directory(mandant_dir, stored_filename) return send_from_directory(mandant_dir, stored_filename)
@app.template_filter("datetime")
def format_datetime(value):
if not value:
return "-"
return value.strftime("%d.%m.%Y %H:%M")

View File

@ -52,3 +52,24 @@ def is_course_allowed_for_level(code: str, mandant_level: int | None) -> bool:
return False return False
def get_allowed_checklist_levels_for_mandant_level(mandant_level: int | None) -> list[int]:
if mandant_level is None:
return []
# 0 = Admin -> alles
if mandant_level == 0:
return [1, 2, 3]
# 1 = Gold -> Bronze + Silber + Gold
if mandant_level == 1:
return [1, 2, 3]
# 2 = Silber -> Bronze + Silber
if mandant_level == 2:
return [1, 2]
# 3 = Bronze -> nur Bronze
if mandant_level == 3:
return [1]
return []

View File

@ -69,6 +69,7 @@ def get_current_user():
"is_logged_in": bool(session.get("user_id")), "is_logged_in": bool(session.get("user_id")),
"is_admin": user_is_admin() if session.get("user_id") else False, "is_admin": user_is_admin() if session.get("user_id") else False,
"is_user_admin": user_is_user_admin() if session.get("user_id") else False, "is_user_admin": user_is_user_admin() if session.get("user_id") else False,
"is_contentmanager": user_is_contentmanager() if session.get("user_id") else False,
"country": country, "country": country,
} }
@ -121,3 +122,40 @@ def user_admin_required(view_func):
return view_func(*args, **kwargs) return view_func(*args, **kwargs)
return wrapper return wrapper
def user_is_contentmanager():
user_id = session.get("user_id")
current_mandant_id = session.get("mandant_id")
if not user_id or not current_mandant_id:
return False
conn = get_connection()
cur = conn.cursor()
cur.execute("""
SELECT 1
FROM user_group ug
JOIN app_group g ON g.id = ug.group_id
WHERE ug.user_id = %s
AND ug.mandant_id = %s
AND g.mandant_id = %s
AND g.group_name = 'Contentmanager'
LIMIT 1
""", (user_id, current_mandant_id, current_mandant_id))
result = cur.fetchone()
cur.close()
conn.close()
return result is not None
def contentmanager_required(view_func):
@wraps(view_func)
def wrapper(*args, **kwargs):
if not session.get("user_id"):
return redirect(url_for("login", next=request.path))
if not user_is_contentmanager():
abort(403)
return view_func(*args, **kwargs)
return wrapper

View File

@ -40,6 +40,9 @@
{% if is_user_admin %} {% if is_user_admin %}
<a href="/useradmin/mandant">Useradministration</a> <a href="/useradmin/mandant">Useradministration</a>
{% endif %} {% endif %}
{% if is_contentmanager %}
<a href="/dokumente">Dokumente</a>
{% endif %}
<a href="/logout">Logout</a> <a href="/logout">Logout</a>
</div> </div>

View File

@ -0,0 +1,103 @@
{% extends "base.html" %}
{% block content %}
<div class="page-header">
<h1>Dokumente</h1>
<p class="intro-text">Checkliste der hochzuladenden Zertifizierungsdokumente.</p>
</div>
<section class="admin-section">
<div class="admin-panel">
<div class="table-wrap">
<table class="mandanten-table">
<thead>
<tr>
<th>ID</th>
<th>Titel</th>
<th>Kurzbeschreibung</th>
<th>Datei</th>
<th>Status</th>
<th>Datum</th>
<th>User</th>
<th>Größe</th>
<th>Aktionen</th>
</tr>
</thead>
<tbody>
{% for item in items %}
<tr>
<td class="col-id">{{ item.id }}</td>
<td>{{ item.title }}</td>
<td>{{ item.short_description or "-" }}</td>
<td>
{% if item.stored_filename %}
<a href="/dokumente/file/{{ item.id }}">
{{ item.original_filename or item.stored_filename }}
</a>
{% else %}
-
{% endif %}
</td>
<td>
{% if item.stored_filename %}
<span class="status-ok">✔ OK</span>
{% else %}
<span class="status-missing">Fehlt</span>
{% endif %}
</td>
<!-- 📅 Datum -->
<td>
{% if item.uploaded_at %}
{{ item.uploaded_at | datetime }}
{% else %}
-
{% endif %}
</td>
<!-- 👤 User -->
<td>
{{ item.uploaded_by_name or "-" }}
</td>
<!-- 📦 Filesize -->
<td>
{% if item.filesize %}
{% if item.filesize < 1024 %}
{{ item.filesize }} B
{% elif item.filesize < 1024*1024 %}
{{ (item.filesize / 1024)|round(1) }} KB
{% else %}
{{ (item.filesize / (1024*1024))|round(2) }} MB
{% endif %}
{% else %}
-
{% endif %}
</td>
<td>
<div class="table-actions">
{% if not item.stored_filename %}
<form method="post" action="/dokumente/upload/{{ item.id }}" enctype="multipart/form-data">
<input type="file" name="file" required>
<button type="submit" class="btn-primary btn-small">Upload</button>
</form>
{% else %}
<form method="post" action="/dokumente/delete/{{ item.id }}">
<button type="submit" class="btn-danger btn-small">Delete</button>
</form>
{% endif %}
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</section>
{% endblock %}

View File

@ -718,4 +718,25 @@ button {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
margin-top: 30px; margin-top: 30px;
}
/* =========================
Dokumente
========================= */
.status-ok {
color: #178b35;
font-weight: 700;
}
.status-missing {
color: #b62323;
font-weight: 700;
}
.col-id {
width: 60px;
}
.mandanten-table td,
.mandanten-table th {
vertical-align: middle;
} }