Kursverwaltung
This commit is contained in:
parent
452a3219ea
commit
aa0767f790
@ -1488,3 +1488,118 @@ def admin_checklist():
|
|||||||
form_values=form_values,
|
form_values=form_values,
|
||||||
**get_current_user()
|
**get_current_user()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@app.route("/admin/courses", methods=["GET", "POST"])
|
||||||
|
@admin_required
|
||||||
|
def admin_courses():
|
||||||
|
conn = get_connection()
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
form_error = None
|
||||||
|
form_values = None
|
||||||
|
|
||||||
|
video_dir = os.path.join("/app/images/videos")
|
||||||
|
video_files = []
|
||||||
|
if os.path.isdir(video_dir):
|
||||||
|
video_files = sorted([
|
||||||
|
f for f in os.listdir(video_dir)
|
||||||
|
if f.lower().endswith(".mp4")
|
||||||
|
])
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
action = request.form.get("action")
|
||||||
|
|
||||||
|
code = request.form.get("code", "").strip().upper()
|
||||||
|
title = request.form.get("title", "").strip()
|
||||||
|
description = request.form.get("description", "").strip()
|
||||||
|
min_level = request.form.get("min_level", "").strip()
|
||||||
|
video_file = request.form.get("video_file", "").strip()
|
||||||
|
sort_order = request.form.get("sort_order", "0").strip()
|
||||||
|
|
||||||
|
form_values = {
|
||||||
|
"code": code,
|
||||||
|
"title": title,
|
||||||
|
"description": description,
|
||||||
|
"min_level": min_level,
|
||||||
|
"video_file": video_file,
|
||||||
|
"sort_order": sort_order
|
||||||
|
}
|
||||||
|
|
||||||
|
if action == "create":
|
||||||
|
if not code:
|
||||||
|
form_error = "Code ist Pflicht."
|
||||||
|
elif not title:
|
||||||
|
form_error = "Titel ist Pflicht."
|
||||||
|
elif not min_level:
|
||||||
|
form_error = "Level ist Pflicht."
|
||||||
|
elif not video_file:
|
||||||
|
form_error = "Video-Datei ist Pflicht."
|
||||||
|
else:
|
||||||
|
cur.execute("""
|
||||||
|
INSERT INTO course (code, title, description, min_level, video_file, sort_order)
|
||||||
|
VALUES (%s, %s, %s, %s, %s, %s)
|
||||||
|
""", (
|
||||||
|
code,
|
||||||
|
title,
|
||||||
|
description or None,
|
||||||
|
int(min_level),
|
||||||
|
video_file,
|
||||||
|
int(sort_order or 0)
|
||||||
|
))
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
elif action == "update":
|
||||||
|
course_id = request.form.get("id")
|
||||||
|
|
||||||
|
if not code:
|
||||||
|
form_error = "Code ist Pflicht."
|
||||||
|
elif not title:
|
||||||
|
form_error = "Titel ist Pflicht."
|
||||||
|
elif not min_level:
|
||||||
|
form_error = "Level ist Pflicht."
|
||||||
|
elif not video_file:
|
||||||
|
form_error = "Video-Datei ist Pflicht."
|
||||||
|
else:
|
||||||
|
cur.execute("""
|
||||||
|
UPDATE course
|
||||||
|
SET code=%s,
|
||||||
|
title=%s,
|
||||||
|
description=%s,
|
||||||
|
min_level=%s,
|
||||||
|
video_file=%s,
|
||||||
|
sort_order=%s
|
||||||
|
WHERE id=%s
|
||||||
|
""", (
|
||||||
|
code,
|
||||||
|
title,
|
||||||
|
description or None,
|
||||||
|
int(min_level),
|
||||||
|
video_file,
|
||||||
|
int(sort_order or 0),
|
||||||
|
int(course_id)
|
||||||
|
))
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
elif action == "delete":
|
||||||
|
course_id = request.form.get("id")
|
||||||
|
cur.execute("DELETE FROM course WHERE id=%s", (int(course_id),))
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
cur.execute("""
|
||||||
|
SELECT id, code, title, description, min_level, video_file, sort_order
|
||||||
|
FROM course
|
||||||
|
ORDER BY min_level, sort_order, id
|
||||||
|
""")
|
||||||
|
courses = fetchall_dict(cur)
|
||||||
|
|
||||||
|
cur.close()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return render_template(
|
||||||
|
"admin_courses.html",
|
||||||
|
courses=courses,
|
||||||
|
video_files=video_files,
|
||||||
|
form_error=form_error,
|
||||||
|
form_values=form_values,
|
||||||
|
**get_current_user()
|
||||||
|
)
|
||||||
131
app/flask-postgres/app/templates/admin_courses.html
Normal file
131
app/flask-postgres/app/templates/admin_courses.html
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h1>Kursverwaltung</h1>
|
||||||
|
|
||||||
|
{% if form_error %}
|
||||||
|
<div class="error-box">{{ form_error }}</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="admin-panel">
|
||||||
|
<h2>Neuen Kurs anlegen</h2>
|
||||||
|
|
||||||
|
<form method="post" class="admin-grid-form">
|
||||||
|
<input type="hidden" name="action" value="create">
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<label>Code</label>
|
||||||
|
<input type="text" name="code" value="{{ form_values.code if form_values else '' }}" placeholder="z.B. A1" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<label>Titel</label>
|
||||||
|
<input type="text" name="title" value="{{ form_values.title if form_values else '' }}" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<label>Level</label>
|
||||||
|
<select name="min_level" required>
|
||||||
|
<option value="1" {% if form_values and form_values.min_level == '1' %}selected{% endif %}>1 - Gold</option>
|
||||||
|
<option value="2" {% if form_values and form_values.min_level == '2' %}selected{% endif %}>2 - Silber</option>
|
||||||
|
<option value="3" {% if form_values and form_values.min_level == '3' %}selected{% endif %}>3 - Bronze</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<label>Video-Datei</label>
|
||||||
|
<select name="video_file" required>
|
||||||
|
<option value="">Bitte wählen</option>
|
||||||
|
{% for v in video_files %}
|
||||||
|
<option value="{{ v }}" {% if form_values and form_values.video_file == v %}selected{% endif %}>
|
||||||
|
{{ v }}
|
||||||
|
</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<label>Sortierung</label>
|
||||||
|
<input type="number" name="sort_order" value="{{ form_values.sort_order if form_values else '0' }}">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row form-row-full">
|
||||||
|
<label>Beschreibung</label>
|
||||||
|
<textarea name="description">{{ form_values.description if form_values else '' }}</textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row form-row-full">
|
||||||
|
<button class="btn-primary">Kurs anlegen</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="admin-panel">
|
||||||
|
<h2>Bestehende Kurse</h2>
|
||||||
|
|
||||||
|
<table class="mandanten-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Code</th>
|
||||||
|
<th>Titel</th>
|
||||||
|
<th>Level</th>
|
||||||
|
<th>Video</th>
|
||||||
|
<th>Sort</th>
|
||||||
|
<th>Aktionen</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
{% for c in courses %}
|
||||||
|
<tr>
|
||||||
|
<form method="post">
|
||||||
|
<input type="hidden" name="id" value="{{ c.id }}">
|
||||||
|
|
||||||
|
<td>{{ c.id }}</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<input type="text" name="code" value="{{ c.code }}">
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<input type="text" name="title" value="{{ c.title }}">
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<select name="min_level">
|
||||||
|
<option value="1" {% if c.min_level == 1 %}selected{% endif %}>1 - Gold</option>
|
||||||
|
<option value="2" {% if c.min_level == 2 %}selected{% endif %}>2 - Silber</option>
|
||||||
|
<option value="3" {% if c.min_level == 3 %}selected{% endif %}>3 - Bronze</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<select name="video_file">
|
||||||
|
{% for v in video_files %}
|
||||||
|
<option value="{{ v }}" {% if c.video_file == v %}selected{% endif %}>
|
||||||
|
{{ v }}
|
||||||
|
</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<input type="number" name="sort_order" value="{{ c.sort_order }}">
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<input type="hidden" name="description" value="{{ c.description or '' }}">
|
||||||
|
<button name="action" value="update" class="btn-primary btn-small">Speichern</button>
|
||||||
|
<button name="action" value="delete" class="btn-danger btn-small">Löschen</button>
|
||||||
|
</td>
|
||||||
|
</form>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@ -37,6 +37,7 @@
|
|||||||
{% if is_admin %}
|
{% if is_admin %}
|
||||||
<a href="/admin/mandanten">Mandanten</a>
|
<a href="/admin/mandanten">Mandanten</a>
|
||||||
<a href="/admin/checklist">Checklist</a>
|
<a href="/admin/checklist">Checklist</a>
|
||||||
|
<a href="/admin/courses">Kurse</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if is_user_admin %}
|
{% if is_user_admin %}
|
||||||
<a href="/useradmin/mandant">Useradministration</a>
|
<a href="/useradmin/mandant">Useradministration</a>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user