mirror of
https://github.com/MarijnDoeve/TijdVoorDeTest.git
synced 2026-07-05 23:20:18 +02:00
281462fab8
* Added Gedmo stuff, fix translations * Add CSRF token validation across backoffice forms - Added CSRF validations to candidate correction, penalty, answer saving, and elimination forms. - Updated corresponding Twig templates to include CSRF token inputs. - Adjusted column count in `tab_result` template to maintain layout consistency. * Add unique index constraint for `quiz_candidate` with soft delete support - Updated migration to include a unique index on `quiz_candidate` table that excludes soft-deleted records. - Adjusted `QuizCandidate` entity to reflect the new unique constraint with `deleted_at` condition. * Add CSRF token validation for quiz-related actions - Added CSRF validation to `enableQuiz`, `clearQuiz`, `deleteQuiz`, `toggleCandidate`, and `prepareElimination` actions. - Updated Twig templates to replace links with POST forms to include CSRF tokens. - Set HTTP method restrictions for related endpoints to `POST`. * Fix unique index condition for `quiz_candidate` with soft deletes - Updated condition in unique index definition of `quiz_candidate` to add parentheses for clarity. - Adjusted related migration to reflect the revised condition. * Remove if for post an use methods in Route instead * Refactor CSRF token validation in backoffice controllers - Applied `#[IsCsrfTokenValid]` attribute for CSRF checks to simplify and standardize validation. - Removed manual `isCsrfTokenValid` calls and associated exception throwing. - Updated method signatures across affected endpoints to remove unnecessary `Request` dependency. - Ensured consistency in route HTTP method restrictions where applicable. * Add rector and phpstan * Add validation for answering incorrect quiz question - Added logic to prevent candidates from answering questions out of sequence in `QuizController`. - Updated Dutch translations to include the new error message. * Things
119 lines
6.0 KiB
Twig
119 lines
6.0 KiB
Twig
<div data-controller="bo--quiz">
|
|
<h4 class="mb-3">{{ 'Quick actions'|trans }}</h4>
|
|
<div class="mb-3 btn-group">
|
|
|
|
{% if quiz is same as (season.activeQuiz) %}
|
|
<form action="{{ path('tvdt_backoffice_enable', {seasonCode: season.seasonCode, quiz: 'null'}) }}" method="POST">
|
|
<input type="hidden" name="_token" value="{{ csrf_token('enable_quiz') }}">
|
|
<button type="submit" class="btn btn-secondary rounded-0 rounded-start">
|
|
{{ 'Deactivate Quiz'|trans }}
|
|
</button>
|
|
</form>
|
|
{% else %}
|
|
<form action="{{ path('tvdt_backoffice_enable', {seasonCode: season.seasonCode, quiz: quiz.id}) }}" method="POST">
|
|
<input type="hidden" name="_token" value="{{ csrf_token('enable_quiz') }}">
|
|
<button type="submit" class="btn btn-primary rounded-0 rounded-start">
|
|
{{ 'Make active'|trans }}
|
|
</button>
|
|
</form>
|
|
{% endif %}
|
|
<button class="btn btn-danger" data-action="click->bo--quiz#clearQuiz">
|
|
{{ 'Clear Quiz...'|trans }}
|
|
</button>
|
|
<button class="btn btn-danger rounded-0 rounded-end" data-action="click->bo--quiz#deleteQuiz">
|
|
{{ 'Delete Quiz...'|trans }}
|
|
</button>
|
|
</div>
|
|
|
|
<h4 class="mb-3">{{ 'Questions'|trans }}</h4>
|
|
<div class="accordion">
|
|
{%~ for question in quiz.questions ~%}
|
|
<div class="accordion-item">
|
|
<h2 class="accordion-header">
|
|
<button class="accordion-button collapsed"
|
|
type="button"
|
|
data-bs-toggle="collapse"
|
|
data-bs-target="#question-{{ loop.index0 }}"
|
|
aria-controls="question-{{ loop.index0 }}">
|
|
{% set questionError = questionErrors[question.id.toString] ?? null %}
|
|
<span
|
|
class="badge rounded-pill me-2{% if questionError %} text-bg-danger{% else %} invisible{% endif %}"{% if questionError %} data-bs-toggle="tooltip" title="{{ questionError }}"{% endif %}>!</span>
|
|
{{~ loop.index -}}. {{ question.question -}}
|
|
</button>
|
|
</h2>
|
|
<div id="question-{{ loop.index0 }}"
|
|
class="accordion-collapse collapse">
|
|
<div class="accordion-body">
|
|
<ul>
|
|
{%~ for answer in question.answers %}
|
|
<li{% if answer.isRightAnswer %} class="text-decoration-underline"{% endif %}>
|
|
{{ answer.text }}
|
|
{% if answer.candidates|length > 0 %}
|
|
<small class="text-muted">
|
|
({{ answer.candidates|map(c => c.name)|join(', ') }})
|
|
</small>
|
|
{% endif %}
|
|
</li>
|
|
{%~ else %}
|
|
{{ 'There are no answers for this question'|trans -}}
|
|
{%~ endfor %}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% else %}
|
|
{{ 'EMPTY'|trans }}
|
|
{% endfor %}
|
|
</div>
|
|
|
|
{# Modal Clear #}
|
|
<div class="modal fade" id="clearQuizModal" data-bs-backdrop="static"
|
|
tabindex="-1"
|
|
data-bo--quiz-target="clearModal"
|
|
aria-labelledby="staticBackdropLabel" aria-hidden="true">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h1 class="modal-title fs-5" id="staticBackdropLabel">{{ 'Please Confirm'|trans }}</h1>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
{{ 'Are you sure you want to clear all the results? This will also delete all the eliminations.'|trans }}
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ 'No'|trans }}</button>
|
|
<form action="{{ path('tvdt_backoffice_quiz_clear', {quiz: quiz.id}) }}" method="POST">
|
|
<input type="hidden" name="_token" value="{{ csrf_token('clear_quiz') }}">
|
|
<button type="submit" class="btn btn-danger">{{ 'Yes'|trans }}</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{# Modal Delete #}
|
|
<div class="modal fade" id="deleteQuizModal" data-bs-backdrop="static"
|
|
tabindex="-1"
|
|
data-bo--quiz-target="deleteModal"
|
|
aria-labelledby="staticBackdropLabel" aria-hidden="true">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h1 class="modal-title fs-5" id="staticBackdropLabel">{{ 'Please Confirm'|trans }}</h1>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
{{ 'Are you sure you want to delete this quiz?'|trans }}
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ 'No'|trans }}</button>
|
|
<form action="{{ path('tvdt_backoffice_quiz_delete', {quiz: quiz.id}) }}" method="POST">
|
|
<input type="hidden" name="_token" value="{{ csrf_token('delete_quiz') }}">
|
|
<button type="submit" class="btn btn-danger">{{ 'Yes'|trans }}</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|