diff --git a/app/flask-postgres/app/app.py b/app/flask-postgres/app/app.py index 5e3b045..6b5d929 100644 --- a/app/flask-postgres/app/app.py +++ b/app/flask-postgres/app/app.py @@ -564,7 +564,7 @@ def admin_mandanten(): "level": level, "admin_name": admin_name, "admin_email": admin_email, - "groups": selected_groups, + "groups": selected_groups } **get_current_user() @@ -1612,3 +1612,315 @@ def impressum(): @app.route("/datenschutz") def datenschutz(): return render_template("datenschutz.html", **get_current_user()) + +@app.route("/admin/questions") +@admin_required +def admin_questions(): + conn = get_connection() + cur = conn.cursor() + + cur.execute(""" + SELECT id, code, title + FROM course + ORDER BY min_level, sort_order, code + """) + courses = fetchall_dict(cur) + + cur.close() + conn.close() + + return render_template( + "admin_questions.html", + page_title="Assessment-Verwaltung", + active_page="admin_questions", + courses=courses, + **get_current_user() + ) +@app.route("/admin/questions/", methods=["GET", "POST"]) +@admin_required +def admin_questions_course(course_id): + conn = get_connection() + cur = conn.cursor() + + cur.execute(""" + SELECT id, code, title + FROM course + WHERE id = %s + """, (course_id,)) + course = fetchone_dict(cur) + + if not course: + cur.close() + conn.close() + abort(404) + + form_error = None + + if request.method == "POST": + action = request.form.get("action") + + if action == "create_question": + title = request.form.get("title", "").strip() + question_text = request.form.get("question_text", "").strip() + sort_order = request.form.get("sort_order", "0").strip() + + answers = [ + request.form.get("answer_1", "").strip(), + request.form.get("answer_2", "").strip(), + request.form.get("answer_3", "").strip(), + ] + correct_index = request.form.get("correct_index", "").strip() + + if not question_text: + form_error = "Fragetext ist Pflicht." + elif not all(answers): + form_error = "Alle drei Antwortmöglichkeiten müssen ausgefüllt sein." + elif correct_index not in ("1", "2", "3"): + form_error = "Bitte die richtige Antwort auswählen." + else: + cur.execute(""" + INSERT INTO question (course_id, title, question_text, sort_order) + VALUES (%s, %s, %s, %s) + RETURNING id + """, ( + course_id, + title or None, + question_text, + int(sort_order or 0) + )) + question_id = cur.fetchone()[0] + + for idx, answer_text in enumerate(answers, start=1): + cur.execute(""" + INSERT INTO answer (question_id, answer_text, is_correct) + VALUES (%s, %s, %s) + """, ( + question_id, + answer_text, + str(idx) == correct_index + )) + + conn.commit() + + elif action == "delete_question": + question_id = int(request.form.get("question_id")) + cur.execute(""" + DELETE FROM question + WHERE id = %s + AND course_id = %s + """, (question_id, course_id)) + conn.commit() + + elif action == "update_question": + question_id = int(request.form.get("question_id")) + title = request.form.get("title", "").strip() + question_text = request.form.get("question_text", "").strip() + sort_order = request.form.get("sort_order", "0").strip() + + answers = [ + request.form.get("answer_1", "").strip(), + request.form.get("answer_2", "").strip(), + request.form.get("answer_3", "").strip(), + ] + correct_index = request.form.get("correct_index", "").strip() + + if not question_text: + form_error = "Fragetext ist Pflicht." + elif not all(answers): + form_error = "Alle drei Antwortmöglichkeiten müssen ausgefüllt sein." + elif correct_index not in ("1", "2", "3"): + form_error = "Bitte die richtige Antwort auswählen." + else: + # Frage aktualisieren + cur.execute(""" + UPDATE question + SET title = %s, + question_text = %s, + sort_order = %s + WHERE id = %s + AND course_id = %s + """, ( + title or None, + question_text, + int(sort_order or 0), + question_id, + course_id + )) + + # Bestehende Antworten in stabiler Reihenfolge laden + cur.execute(""" + SELECT id + FROM answer + WHERE question_id = %s + ORDER BY id + """, (question_id,)) + existing_answers = cur.fetchall() + + if len(existing_answers) == 3: + for idx, row in enumerate(existing_answers, start=1): + answer_id = row[0] + cur.execute(""" + UPDATE answer + SET answer_text = %s, + is_correct = %s + WHERE id = %s + AND question_id = %s + """, ( + answers[idx - 1], + str(idx) == correct_index, + answer_id, + question_id + )) + else: + # Falls inkonsistent, Antworten neu aufbauen + cur.execute(""" + DELETE FROM answer + WHERE question_id = %s + """, (question_id,)) + + for idx, answer_text in enumerate(answers, start=1): + cur.execute(""" + INSERT INTO answer (question_id, answer_text, is_correct) + VALUES (%s, %s, %s) + """, ( + question_id, + answer_text, + str(idx) == correct_index + )) + + conn.commit() + + cur.execute(""" + SELECT id, title, question_text, sort_order + FROM question + WHERE course_id = %s + ORDER BY sort_order, id + """, (course_id,)) + questions = fetchall_dict(cur) + + for q in questions: + cur.execute(""" + SELECT id, answer_text, is_correct + FROM answer + WHERE question_id = %s + ORDER BY id + """, (q["id"],)) + q["answers"] = fetchall_dict(cur) + + cur.close() + conn.close() + + return render_template( + "admin_questions_course.html", + page_title="Fragen verwalten", + active_page="admin_questions", + course=course, + questions=questions, + form_error=form_error, + **get_current_user() + ) + +@app.route("/course//assessment", methods=["GET", "POST"]) +@login_required +def course_assessment(course_id): + mandant_level = session.get("mandant_level", 0) + + conn = get_connection() + cur = conn.cursor() + + cur.execute(""" + SELECT id, code, title + FROM course + WHERE id = %s + """, (course_id,)) + course = fetchone_dict(cur) + + if not course: + cur.close() + conn.close() + abort(404) + + if not is_course_allowed_for_level(course["code"], mandant_level): + cur.close() + conn.close() + abort(403) + + if request.method == "GET": + cur.execute(""" + SELECT id, title, question_text + FROM question + WHERE course_id = %s + ORDER BY RANDOM() + """, (course_id,)) + questions = fetchall_dict(cur) + + for q in questions: + cur.execute(""" + SELECT id, answer_text + FROM answer + WHERE question_id = %s + ORDER BY RANDOM() + """, (q["id"],)) + q["answers"] = fetchall_dict(cur) + + cur.close() + conn.close() + + return render_template( + "course_assessment.html", + page_title="Assessment", + active_page="courses", + course=course, + questions=questions, + **get_current_user() + ) + + # POST = Auswertung + cur.execute(""" + SELECT id + FROM question + WHERE course_id = %s + """, (course_id,)) + questions = fetchall_dict(cur) + + total_questions = len(questions) + correct_answers = 0 + + for q in questions: + selected_answer_id = request.form.get(f"question_{q['id']}") + if not selected_answer_id: + continue + + cur.execute(""" + SELECT is_correct + FROM answer + WHERE id = %s + AND question_id = %s + """, (int(selected_answer_id), q["id"])) + row = cur.fetchone() + + if row and row[0] is True: + correct_answers += 1 + + score = correct_answers + passed = total_questions > 0 and correct_answers == total_questions + + cur.execute(""" + INSERT INTO user_assessment (user_id, course_id, score, passed) + VALUES (%s, %s, %s, %s) + """, (session["user_id"], course_id, score, passed)) + conn.commit() + + cur.close() + conn.close() + + return render_template( + "course_assessment_result.html", + page_title="Assessment Ergebnis", + active_page="courses", + course=course, + score=score, + total_questions=total_questions, + passed=passed, + **get_current_user() + ) \ No newline at end of file