reihenfolge und images
34
app.py
@ -58,11 +58,12 @@ from db import (
|
||||
get_all_empfehlungen,
|
||||
)
|
||||
from permissions import admin_required, login_required
|
||||
from tools import create_assessment_chart, generate_activation_token, send_mail, verify_activation_token, generate_pdf_from_html
|
||||
from tools import create_assessment_chart, generate_activation_token, send_mail, verify_activation_token, generate_pdf_from_html, get_image_files
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from copy import deepcopy
|
||||
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config.from_object(Config)
|
||||
|
||||
@ -428,12 +429,16 @@ def admin_themen():
|
||||
def admin_thema_new():
|
||||
ansprechpartner = get_all_ansprechpartner()
|
||||
branchen = get_all_branchen()
|
||||
image_dir = Path(app.root_path) / "static" / "images"
|
||||
image_files = get_image_files(image_dir)
|
||||
|
||||
if request.method == "POST":
|
||||
kurztitel = request.form.get("kurztitel", "").strip()
|
||||
titel = request.form.get("titel", "").strip()
|
||||
infotext = request.form.get("infotext", "").strip()
|
||||
zusatztext = request.form.get("zusatztext", "").strip()
|
||||
pic = request.form.get("pic", "").strip()
|
||||
reihenfolge = request.form.get("reihenfolge", "").strip()
|
||||
ansprechpartner_ids = [int(x) for x in request.form.getlist("ansprechpartner_ids")]
|
||||
branche_ids = [int(x) for x in request.form.getlist("branche_ids")]
|
||||
|
||||
@ -447,6 +452,7 @@ def admin_thema_new():
|
||||
branchen=branchen,
|
||||
selected_ansprechpartner_ids=ansprechpartner_ids,
|
||||
selected_branche_ids=branche_ids,
|
||||
image_files=image_files,
|
||||
)
|
||||
|
||||
create_thema(
|
||||
@ -454,6 +460,8 @@ def admin_thema_new():
|
||||
titel,
|
||||
infotext,
|
||||
zusatztext,
|
||||
reihenfolge,
|
||||
pic,
|
||||
ansprechpartner_ids,
|
||||
branche_ids,
|
||||
)
|
||||
@ -468,6 +476,7 @@ def admin_thema_new():
|
||||
branchen=branchen,
|
||||
selected_ansprechpartner_ids=[],
|
||||
selected_branche_ids=[],
|
||||
image_files=image_files,
|
||||
)
|
||||
|
||||
@app.route("/admin/themen/<int:thema_id>/edit", methods=["GET", "POST"])
|
||||
@ -480,21 +489,28 @@ def admin_thema_edit(thema_id):
|
||||
|
||||
ansprechpartner = get_all_ansprechpartner()
|
||||
branchen = get_all_branchen()
|
||||
image_dir = Path(app.root_path) / "static" / "images"
|
||||
image_files = get_image_files(image_dir)
|
||||
|
||||
if request.method == "POST":
|
||||
kurztitel = request.form.get("kurztitel", "").strip()
|
||||
titel = request.form.get("titel", "").strip()
|
||||
infotext = request.form.get("infotext", "").strip()
|
||||
zusatztext = request.form.get("zusatztext", "").strip()
|
||||
pic = request.form.get("pic", "").strip()
|
||||
reihenfolge = request.form.get("reihenfolge", "").strip()
|
||||
ansprechpartner_ids = [int(x) for x in request.form.getlist("ansprechpartner_ids")]
|
||||
branche_ids = [int(x) for x in request.form.getlist("branche_ids")]
|
||||
|
||||
|
||||
if not kurztitel or not titel:
|
||||
flash("Kurztitel und Titel sind Pflichtfelder.", "error")
|
||||
thema_form = {
|
||||
"id": thema_id,
|
||||
"kurztitel": kurztitel,
|
||||
"titel": titel,
|
||||
"pic": pic,
|
||||
"reihenfolge": reihenfolge,
|
||||
"infotext": infotext,
|
||||
"zusatztext": zusatztext,
|
||||
}
|
||||
@ -506,6 +522,7 @@ def admin_thema_edit(thema_id):
|
||||
branchen=branchen,
|
||||
selected_ansprechpartner_ids=ansprechpartner_ids,
|
||||
selected_branche_ids=branche_ids,
|
||||
image_files=image_files,
|
||||
)
|
||||
|
||||
update_thema(
|
||||
@ -513,7 +530,9 @@ def admin_thema_edit(thema_id):
|
||||
kurztitel,
|
||||
titel,
|
||||
infotext,
|
||||
reihenfolge,
|
||||
zusatztext,
|
||||
pic,
|
||||
ansprechpartner_ids,
|
||||
branche_ids,
|
||||
)
|
||||
@ -531,6 +550,7 @@ def admin_thema_edit(thema_id):
|
||||
branchen=branchen,
|
||||
selected_ansprechpartner_ids=selected_ansprechpartner_ids,
|
||||
selected_branche_ids=selected_branche_ids,
|
||||
image_files=image_files,
|
||||
)
|
||||
|
||||
@app.route("/admin/themen/<int:thema_id>/delete", methods=["POST"])
|
||||
@ -637,6 +657,7 @@ def admin_question_new():
|
||||
if request.method == "POST":
|
||||
thema_id = request.form.get("thema_id")
|
||||
text = request.form.get("text", "").strip()
|
||||
reihenfolge = request.form.get("reihenfolge", "").strip()
|
||||
|
||||
if not thema_id or not text:
|
||||
flash("Thema und Text sind Pflichtfelder.", "error")
|
||||
@ -647,7 +668,7 @@ def admin_question_new():
|
||||
themen=themen,
|
||||
)
|
||||
|
||||
create_question(thema_id, text)
|
||||
create_question(thema_id, text, reihenfolge)
|
||||
flash("Frage wurde erstellt.", "success")
|
||||
return redirect(url_for("admin_questions"))
|
||||
|
||||
@ -670,6 +691,7 @@ def admin_question_edit(frage_id):
|
||||
|
||||
if request.method == "POST":
|
||||
thema_id = request.form.get("thema_id")
|
||||
reihenfolge = request.form.get("reihenfolge", "").strip()
|
||||
text = request.form.get("text", "").strip()
|
||||
|
||||
if not thema_id or not text:
|
||||
@ -677,6 +699,7 @@ def admin_question_edit(frage_id):
|
||||
"id": frage_id,
|
||||
"thema_id": thema_id,
|
||||
"text": text,
|
||||
"reihenfolge": reihenfolge,
|
||||
}
|
||||
flash("Thema und Text sind Pflichtfelder.", "error")
|
||||
return render_template(
|
||||
@ -686,7 +709,7 @@ def admin_question_edit(frage_id):
|
||||
themen=themen,
|
||||
)
|
||||
|
||||
update_question(frage_id, thema_id, text)
|
||||
update_question(frage_id, thema_id, text, reihenfolge)
|
||||
flash("Frage wurde gespeichert.", "success")
|
||||
return redirect(url_for("admin_questions"))
|
||||
|
||||
@ -915,6 +938,11 @@ def admin_empfehlungen():
|
||||
ansprechpartner=ansprechpartner,
|
||||
)
|
||||
|
||||
|
||||
@app.route("/images/<path:filename>")
|
||||
def images(filename):
|
||||
return send_from_directory(Path(app.root_path) / "/app/static/images", filename)
|
||||
|
||||
@app.errorhandler(401)
|
||||
def unauthorized_error(error):
|
||||
return render_template("401.html"), 401
|
||||
|
||||
55
db.py
@ -165,9 +165,9 @@ def get_user_groups(user_id):
|
||||
def get_all_themen():
|
||||
return fetch_all(
|
||||
"""
|
||||
SELECT id, kurztitel, titel, infotext, zusatztext
|
||||
SELECT id, kurztitel, titel, infotext, zusatztext, reihenfolge, pic
|
||||
FROM thema
|
||||
ORDER BY id
|
||||
ORDER BY reihenfolge,id
|
||||
"""
|
||||
)
|
||||
|
||||
@ -175,7 +175,7 @@ def get_all_themen():
|
||||
def get_thema_by_id(thema_id):
|
||||
return fetch_one(
|
||||
"""
|
||||
SELECT id, kurztitel, titel, infotext, zusatztext
|
||||
SELECT id, kurztitel, titel, infotext, zusatztext, reihenfolge, pic
|
||||
FROM thema
|
||||
WHERE id = %s
|
||||
""",
|
||||
@ -242,17 +242,17 @@ def get_ansprechpartner_ids_for_thema(thema_id):
|
||||
return [row["ansprechpartner_id"] for row in rows]
|
||||
|
||||
|
||||
def create_thema(kurztitel, titel, infotext, zusatztext, ansprechpartner_ids, branche_ids=None):
|
||||
def create_thema(kurztitel, titel, infotext, zusatztext, reihenfolge, pic, ansprechpartner_ids, branche_ids=None):
|
||||
if branche_ids is None:
|
||||
branche_ids = []
|
||||
|
||||
row = execute_returning(
|
||||
"""
|
||||
INSERT INTO thema (kurztitel, titel, infotext, zusatztext)
|
||||
VALUES (%s, %s, %s, %s)
|
||||
INSERT INTO thema (kurztitel, titel, infotext, zusatztext, reihenfolge, pic)
|
||||
VALUES (%s, %s, %s, %s, %s, %s)
|
||||
RETURNING id
|
||||
""",
|
||||
(kurztitel, titel, infotext, zusatztext),
|
||||
(kurztitel, titel, infotext, zusatztext, reihenfolge, pic),
|
||||
)
|
||||
thema_id = row["id"]
|
||||
|
||||
@ -277,7 +277,7 @@ def create_thema(kurztitel, titel, infotext, zusatztext, ansprechpartner_ids, br
|
||||
return thema_id
|
||||
|
||||
|
||||
def update_thema(thema_id, kurztitel, titel, infotext, zusatztext, ansprechpartner_ids, branche_ids=None):
|
||||
def update_thema(thema_id, kurztitel, titel, infotext, reihenfolge, zusatztext, pic, ansprechpartner_ids, branche_ids=None):
|
||||
if branche_ids is None:
|
||||
branche_ids = []
|
||||
|
||||
@ -287,10 +287,12 @@ def update_thema(thema_id, kurztitel, titel, infotext, zusatztext, ansprechpartn
|
||||
SET kurztitel = %s,
|
||||
titel = %s,
|
||||
infotext = %s,
|
||||
zusatztext = %s
|
||||
zusatztext = %s,
|
||||
reihenfolge = %s,
|
||||
pic = %s
|
||||
WHERE id = %s
|
||||
""",
|
||||
(kurztitel, titel, infotext, zusatztext, thema_id),
|
||||
(kurztitel, titel, infotext, zusatztext, reihenfolge, pic, thema_id),
|
||||
)
|
||||
|
||||
execute(
|
||||
@ -343,7 +345,7 @@ def get_thema_questions(thema_id):
|
||||
SELECT id, thema_id, text
|
||||
FROM fragen
|
||||
WHERE thema_id = %s
|
||||
ORDER BY id
|
||||
ORDER BY reihenfolge, id
|
||||
""",
|
||||
(thema_id,),
|
||||
)
|
||||
@ -358,6 +360,7 @@ def get_all_questions_with_thema():
|
||||
f.thema_id,
|
||||
t.id AS thema_sort_id,
|
||||
t.kurztitel,
|
||||
t.reihenfolge,
|
||||
t.titel,
|
||||
COALESCE(STRING_AGG(b.branchenname, ' | '), '') AS branchen
|
||||
FROM fragen f
|
||||
@ -374,7 +377,7 @@ def get_all_questions_with_thema():
|
||||
t.id,
|
||||
t.kurztitel,
|
||||
t.titel
|
||||
ORDER BY t.id, f.id
|
||||
ORDER BY t.reihenfolge, t.id, f.reihenfolge, f.id
|
||||
"""
|
||||
)
|
||||
|
||||
@ -489,7 +492,7 @@ def delete_ansprechpartner(ansprechpartner_id):
|
||||
def get_question_by_id(frage_id):
|
||||
return fetch_one(
|
||||
"""
|
||||
SELECT id, thema_id, text
|
||||
SELECT id, thema_id, text, reihenfolge
|
||||
FROM fragen
|
||||
WHERE id = %s
|
||||
""",
|
||||
@ -497,26 +500,32 @@ def get_question_by_id(frage_id):
|
||||
)
|
||||
|
||||
|
||||
def create_question(thema_id, text):
|
||||
def create_question(thema_id, text, reihenfolge):
|
||||
return execute_returning(
|
||||
"""
|
||||
INSERT INTO fragen (thema_id, text)
|
||||
VALUES (%s, %s)
|
||||
INSERT INTO fragen (thema_id, text, reihenfolge)
|
||||
VALUES (%s, %s, %s)
|
||||
RETURNING id
|
||||
""",
|
||||
(thema_id, text),
|
||||
(thema_id, text, reihenfolge),
|
||||
)
|
||||
|
||||
|
||||
def update_question(frage_id, thema_id, text):
|
||||
def update_question(question_id, thema_id, text, reihenfolge):
|
||||
execute(
|
||||
"""
|
||||
UPDATE fragen
|
||||
SET thema_id = %s,
|
||||
text = %s
|
||||
text = %s,
|
||||
reihenfolge = %s
|
||||
WHERE id = %s
|
||||
""",
|
||||
(thema_id, text, frage_id),
|
||||
(
|
||||
thema_id,
|
||||
text,
|
||||
reihenfolge,
|
||||
question_id,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@ -724,7 +733,7 @@ def get_next_thema_id_for_branche(current_thema_id, branche_id):
|
||||
def get_thema_for_branche(thema_id, branche_id):
|
||||
return fetch_one(
|
||||
"""
|
||||
SELECT t.id, t.kurztitel, t.titel, t.infotext, t.zusatztext
|
||||
SELECT t.id, t.kurztitel, t.titel, t.infotext, t.zusatztext, t.pic
|
||||
FROM thema t
|
||||
JOIN branchenthemen bt ON bt.thema_id = t.id
|
||||
WHERE t.id = %s
|
||||
@ -754,11 +763,13 @@ def get_all_themen_with_question_count():
|
||||
t.titel,
|
||||
t.infotext,
|
||||
t.zusatztext,
|
||||
t.reihenfolge,
|
||||
t.pic,
|
||||
COUNT(f.id) AS fragen_anzahl
|
||||
FROM thema t
|
||||
LEFT JOIN fragen f ON f.thema_id = t.id
|
||||
GROUP BY t.id, t.kurztitel, t.titel, t.infotext, t.zusatztext
|
||||
ORDER BY t.id
|
||||
ORDER BY t.reihenfolge, t.id
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
BIN
static/images/Logo-Erfolgsfaktoren.png
Normal file
|
After Width: | Height: | Size: 601 KiB |
BIN
static/images/Logo-Finanz.png
Normal file
|
After Width: | Height: | Size: 573 KiB |
BIN
static/images/Logo-Finanzen.png
Normal file
|
After Width: | Height: | Size: 567 KiB |
BIN
static/images/Logo-Hexerei.png
Normal file
|
After Width: | Height: | Size: 2.0 MiB |
BIN
static/images/Logo-ITSicherheit.png
Normal file
|
After Width: | Height: | Size: 592 KiB |
BIN
static/images/Logo-Identifikation.png
Normal file
|
After Width: | Height: | Size: 586 KiB |
BIN
static/images/Logo-Identitaet.png
Normal file
|
After Width: | Height: | Size: 617 KiB |
BIN
static/images/Logo-Liebe.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
static/images/Logo-Marketing.png
Normal file
|
After Width: | Height: | Size: 586 KiB |
BIN
static/images/Logo-Personal.png
Normal file
|
After Width: | Height: | Size: 550 KiB |
BIN
static/images/Logo-Personal2.png
Normal file
|
After Width: | Height: | Size: 551 KiB |
BIN
static/images/Logo-Raum.png
Normal file
|
After Width: | Height: | Size: 590 KiB |
BIN
static/images/Logo-Softskills.png
Normal file
|
After Width: | Height: | Size: 588 KiB |
BIN
static/images/Logo-Teambuilding.png
Normal file
|
After Width: | Height: | Size: 574 KiB |
BIN
static/images/Logo-WLB.png
Normal file
|
After Width: | Height: | Size: 579 KiB |
@ -25,6 +25,13 @@
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Reihenfolge</label>
|
||||
<input type="number"
|
||||
name="reihenfolge"
|
||||
value="{{ frage.reihenfolge or 0 }}">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Frage</label>
|
||||
<textarea name="text" rows="5" required>{{ frage.text or '' }}</textarea>
|
||||
|
||||
@ -11,6 +11,13 @@
|
||||
</h1>
|
||||
|
||||
<form method="post" class="admin-form">
|
||||
<div class="form-group">
|
||||
<label>Reihenfolge</label>
|
||||
<input type="number"
|
||||
name="reihenfolge"
|
||||
value="{{ thema.reihenfolge or 0 }}">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="kurztitel">Kurztitel</label>
|
||||
<input type="text" id="kurztitel" name="kurztitel" value="{{ thema.kurztitel or '' }}" required>
|
||||
@ -21,6 +28,24 @@
|
||||
<input type="text" id="titel" name="titel" value="{{ thema.titel or '' }}" required>
|
||||
</div>
|
||||
|
||||
<!--div class="form-group">
|
||||
<label for="kurztitel">Bild</label>
|
||||
<input type="text" id="pic" name="pic" value="{{ thema.pic or '' }}" required>
|
||||
</div-->
|
||||
|
||||
<div class="form-group">
|
||||
<label for="pic">Bild / Logo</label>
|
||||
<select id="pic" name="pic">
|
||||
<option value="">-- kein Bild --</option>
|
||||
{% for image in image_files %}
|
||||
<option value="{{ image }}"
|
||||
{% if thema.pic == image %}selected{% endif %}>
|
||||
{{ image }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="infotext">InfoText</label>
|
||||
<textarea id="infotext" name="infotext" rows="6">{{ thema.infotext or '' }}</textarea>
|
||||
|
||||
@ -11,9 +11,10 @@
|
||||
<table class="admin-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Rfg</th>
|
||||
<th>Kurztitel</th>
|
||||
<th>Titel</th>
|
||||
<th>Bild</th>
|
||||
<th>Fragen</th>
|
||||
<th>Aktionen</th>
|
||||
</tr>
|
||||
@ -21,9 +22,10 @@
|
||||
<tbody>
|
||||
{% for thema in themen %}
|
||||
<tr>
|
||||
<td>{{ thema.id }}</td>
|
||||
<td>{{ thema.reihenfolge }}</td>
|
||||
<td>{{ thema.kurztitel }}</td>
|
||||
<td>{{ thema.titel }}</td>
|
||||
<td>{{ thema.pic }}</td>
|
||||
<td>
|
||||
{{ thema.fragen_anzahl }}
|
||||
{% if thema.fragen_anzahl < 8 %}
|
||||
|
||||
@ -3,6 +3,9 @@
|
||||
{% block content %}
|
||||
<section class="card">
|
||||
<h1>{{ thema.titel }}</h1>
|
||||
{% if thema.pic != "" %}
|
||||
<center><img src="/images/{{ thema.pic }}"></center>
|
||||
{% endif %}
|
||||
<p>{{ thema.infotext }}</p>
|
||||
<p class="muted">{{ thema.zusatztext }}</p>
|
||||
</section>
|
||||
|
||||
27
tools.py
@ -7,6 +7,7 @@ import matplotlib
|
||||
matplotlib.use('Agg')
|
||||
import matplotlib.pyplot as plt
|
||||
from config import Config
|
||||
from flask import current_app
|
||||
|
||||
from pathlib import Path
|
||||
from weasyprint import HTML
|
||||
@ -116,3 +117,29 @@ def create_chart_bytes(labels, yes_counts):
|
||||
plt.close(fig)
|
||||
buffer.seek(0)
|
||||
return buffer
|
||||
|
||||
def get_image_files(image_dir):
|
||||
allowed_extensions = {".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg"}
|
||||
|
||||
#current_app.logger.error(f"IMAGE DIR: {image_dir}")
|
||||
#current_app.logger.error(f"EXISTS: {image_dir.exists()}")
|
||||
|
||||
|
||||
if not image_dir.exists():
|
||||
return []
|
||||
|
||||
files = sorted(
|
||||
|
||||
file.name
|
||||
|
||||
for file in image_dir.iterdir()
|
||||
|
||||
if file.is_file()
|
||||
|
||||
and file.suffix.lower() in allowed_extensions
|
||||
|
||||
)
|
||||
|
||||
#current_app.logger.error(f"FILES: {files}")
|
||||
|
||||
return files
|
||||