mirror of
https://github.com/MarijnDoeve/TijdVoorDeTest.git
synced 2026-07-10 09:30:14 +02:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 352e34a428 | |||
| b1a959fdc6 | |||
| 27d3d64154 | |||
| e7586c2d6b | |||
| a49d32e8ff | |||
| 4547a43199 |
Generated
+19
-19
@@ -1475,16 +1475,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "guzzlehttp/psr7",
|
"name": "guzzlehttp/psr7",
|
||||||
"version": "2.12.3",
|
"version": "2.12.4",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/guzzle/psr7.git",
|
"url": "https://github.com/guzzle/psr7.git",
|
||||||
"reference": "7ec62dc3f44aa218487dbed81a9bf9bc647be55d"
|
"reference": "51e27f9e2b332ab3e72f4520d5ff4f3c68c3577c"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/guzzle/psr7/zipball/7ec62dc3f44aa218487dbed81a9bf9bc647be55d",
|
"url": "https://api.github.com/repos/guzzle/psr7/zipball/51e27f9e2b332ab3e72f4520d5ff4f3c68c3577c",
|
||||||
"reference": "7ec62dc3f44aa218487dbed81a9bf9bc647be55d",
|
"reference": "51e27f9e2b332ab3e72f4520d5ff4f3c68c3577c",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -1574,7 +1574,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/guzzle/psr7/issues",
|
"issues": "https://github.com/guzzle/psr7/issues",
|
||||||
"source": "https://github.com/guzzle/psr7/tree/2.12.3"
|
"source": "https://github.com/guzzle/psr7/tree/2.12.4"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -1590,7 +1590,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2026-06-23T15:21:08+00:00"
|
"time": "2026-07-08T15:56:20+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "jean85/pretty-package-versions",
|
"name": "jean85/pretty-package-versions",
|
||||||
@@ -2253,16 +2253,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpstan/phpdoc-parser",
|
"name": "phpstan/phpdoc-parser",
|
||||||
"version": "2.3.2",
|
"version": "2.3.3",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/phpstan/phpdoc-parser.git",
|
"url": "https://github.com/phpstan/phpdoc-parser.git",
|
||||||
"reference": "a004701b11273a26cd7955a61d67a7f1e525a45a"
|
"reference": "fb19eedd2bb67ff8cf7a5502ad329e701d6398a3"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/a004701b11273a26cd7955a61d67a7f1e525a45a",
|
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/fb19eedd2bb67ff8cf7a5502ad329e701d6398a3",
|
||||||
"reference": "a004701b11273a26cd7955a61d67a7f1e525a45a",
|
"reference": "fb19eedd2bb67ff8cf7a5502ad329e701d6398a3",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -2294,9 +2294,9 @@
|
|||||||
"description": "PHPDoc parser with support for nullable, intersection and generic types",
|
"description": "PHPDoc parser with support for nullable, intersection and generic types",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
|
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
|
||||||
"source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.2"
|
"source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.3"
|
||||||
},
|
},
|
||||||
"time": "2026-01-25T14:56:51+00:00"
|
"time": "2026-07-08T07:01:06+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "psr/cache",
|
"name": "psr/cache",
|
||||||
@@ -10452,16 +10452,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/phpunit",
|
"name": "phpunit/phpunit",
|
||||||
"version": "13.2.3",
|
"version": "13.2.4",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||||
"reference": "d76d0e24225e587d6a5f0c6f6d9fef0d90712b54"
|
"reference": "8f5180f4627fc1978be2f61d8d9979dbe37e0c10"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d76d0e24225e587d6a5f0c6f6d9fef0d90712b54",
|
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/8f5180f4627fc1978be2f61d8d9979dbe37e0c10",
|
||||||
"reference": "d76d0e24225e587d6a5f0c6f6d9fef0d90712b54",
|
"reference": "8f5180f4627fc1978be2f61d8d9979dbe37e0c10",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -10475,7 +10475,7 @@
|
|||||||
"phar-io/manifest": "^2.0.4",
|
"phar-io/manifest": "^2.0.4",
|
||||||
"phar-io/version": "^3.2.1",
|
"phar-io/version": "^3.2.1",
|
||||||
"php": ">=8.4.1",
|
"php": ">=8.4.1",
|
||||||
"phpunit/php-code-coverage": "^14.2.2",
|
"phpunit/php-code-coverage": "^14.2.3",
|
||||||
"phpunit/php-file-iterator": "^7.0.0",
|
"phpunit/php-file-iterator": "^7.0.0",
|
||||||
"phpunit/php-invoker": "^7.0.0",
|
"phpunit/php-invoker": "^7.0.0",
|
||||||
"phpunit/php-text-template": "^6.0.0",
|
"phpunit/php-text-template": "^6.0.0",
|
||||||
@@ -10532,7 +10532,7 @@
|
|||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/13.2.3"
|
"source": "https://github.com/sebastianbergmann/phpunit/tree/13.2.4"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -10540,7 +10540,7 @@
|
|||||||
"type": "other"
|
"type": "other"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2026-07-06T14:55:56+00:00"
|
"time": "2026-07-08T08:36:51+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "react/cache",
|
"name": "react/cache",
|
||||||
|
|||||||
@@ -10,10 +10,13 @@ use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
|||||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
use Symfony\Component\Form\FormError;
|
use Symfony\Component\Form\FormError;
|
||||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||||
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\HttpKernel\Attribute\AsController;
|
use Symfony\Component\HttpKernel\Attribute\AsController;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
use Symfony\Component\Routing\Requirement\Requirement;
|
||||||
|
use Symfony\Component\Security\Http\Attribute\IsCsrfTokenValid;
|
||||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||||
use Symfony\Component\Validator\Constraints\Length;
|
use Symfony\Component\Validator\Constraints\Length;
|
||||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||||
@@ -26,6 +29,7 @@ use Tvdt\Enum\FlashType;
|
|||||||
use Tvdt\Form\AddCandidatesFormType;
|
use Tvdt\Form\AddCandidatesFormType;
|
||||||
use Tvdt\Form\SettingsForm;
|
use Tvdt\Form\SettingsForm;
|
||||||
use Tvdt\Form\UploadQuizFormType;
|
use Tvdt\Form\UploadQuizFormType;
|
||||||
|
use Tvdt\Repository\CandidateRepository;
|
||||||
use Tvdt\Security\Voter\SeasonVoter;
|
use Tvdt\Security\Voter\SeasonVoter;
|
||||||
use Tvdt\Service\QuizSpreadsheetService;
|
use Tvdt\Service\QuizSpreadsheetService;
|
||||||
|
|
||||||
@@ -37,6 +41,7 @@ class SeasonController extends AbstractController
|
|||||||
private readonly TranslatorInterface $translator,
|
private readonly TranslatorInterface $translator,
|
||||||
private readonly EntityManagerInterface $em,
|
private readonly EntityManagerInterface $em,
|
||||||
private readonly QuizSpreadsheetService $quizSpreadsheet,
|
private readonly QuizSpreadsheetService $quizSpreadsheet,
|
||||||
|
private readonly CandidateRepository $candidateRepository,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
|
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
|
||||||
@@ -97,6 +102,24 @@ class SeasonController extends AbstractController
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[IsCsrfTokenValid('regenerate_season_code')]
|
||||||
|
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
|
||||||
|
#[Route(
|
||||||
|
'/backoffice/season/{seasonCode:season}/settings/regenerate-code',
|
||||||
|
name: 'tvdt_backoffice_season_regenerate_code',
|
||||||
|
requirements: ['seasonCode' => self::SEASON_CODE_REGEX],
|
||||||
|
methods: ['POST'],
|
||||||
|
)]
|
||||||
|
public function regenerateSeasonCode(Season $season): RedirectResponse
|
||||||
|
{
|
||||||
|
$season->generateSeasonCode();
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
|
$this->addFlash(FlashType::Success, $this->translator->trans('Season code regenerated'));
|
||||||
|
|
||||||
|
return $this->redirectToRoute('tvdt_backoffice_season_settings', ['seasonCode' => $season->seasonCode]);
|
||||||
|
}
|
||||||
|
|
||||||
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
|
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
|
||||||
#[Route(
|
#[Route(
|
||||||
'/backoffice/season/{seasonCode:season}/add-candidate',
|
'/backoffice/season/{seasonCode:season}/add-candidate',
|
||||||
@@ -123,6 +146,56 @@ class SeasonController extends AbstractController
|
|||||||
return $this->render('backoffice/season_add_candidates.html.twig', ['form' => $form, 'season' => $season]);
|
return $this->render('backoffice/season_add_candidates.html.twig', ['form' => $form, 'season' => $season]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[IsCsrfTokenValid('rename_candidate')]
|
||||||
|
#[IsGranted(SeasonVoter::EDIT, subject: 'candidate')]
|
||||||
|
#[Route(
|
||||||
|
'/backoffice/season/{seasonCode:season}/candidate/{candidate}/rename',
|
||||||
|
name: 'tvdt_backoffice_candidate_rename',
|
||||||
|
requirements: ['seasonCode' => self::SEASON_CODE_REGEX, 'candidate' => Requirement::UUID],
|
||||||
|
methods: ['POST'],
|
||||||
|
)]
|
||||||
|
public function renameCandidate(Season $season, Candidate $candidate, Request $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$name = mb_trim($request->request->getString('name'));
|
||||||
|
|
||||||
|
if ('' === $name || mb_strlen($name) > 16) {
|
||||||
|
$this->addFlash(FlashType::Danger, $this->translator->trans('The candidate name must be between 1 and 16 characters'));
|
||||||
|
|
||||||
|
return $this->redirectToRoute('tvdt_backoffice_season_candidates', ['seasonCode' => $season->seasonCode]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$candidate->name = $name;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->em->flush();
|
||||||
|
} catch (UniqueConstraintViolationException) {
|
||||||
|
$this->addFlash(FlashType::Danger, $this->translator->trans('A candidate with this name already exists in this season'));
|
||||||
|
|
||||||
|
return $this->redirectToRoute('tvdt_backoffice_season_candidates', ['seasonCode' => $season->seasonCode]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addFlash(FlashType::Success, $this->translator->trans('Candidate renamed'));
|
||||||
|
|
||||||
|
return $this->redirectToRoute('tvdt_backoffice_season_candidates', ['seasonCode' => $season->seasonCode]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[IsCsrfTokenValid('delete_candidate')]
|
||||||
|
#[IsGranted(SeasonVoter::DELETE, subject: 'candidate')]
|
||||||
|
#[Route(
|
||||||
|
'/backoffice/season/{seasonCode:season}/candidate/{candidate}/delete',
|
||||||
|
name: 'tvdt_backoffice_candidate_delete',
|
||||||
|
requirements: ['seasonCode' => self::SEASON_CODE_REGEX, 'candidate' => Requirement::UUID],
|
||||||
|
methods: ['POST'],
|
||||||
|
)]
|
||||||
|
public function deleteCandidate(Season $season, Candidate $candidate): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->candidateRepository->deleteCandidate($candidate);
|
||||||
|
|
||||||
|
$this->addFlash(FlashType::Success, $this->translator->trans('Candidate deleted'));
|
||||||
|
|
||||||
|
return $this->redirectToRoute('tvdt_backoffice_season_candidates', ['seasonCode' => $season->seasonCode]);
|
||||||
|
}
|
||||||
|
|
||||||
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
|
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
|
||||||
#[Route(
|
#[Route(
|
||||||
'/backoffice/season/{seasonCode:season}/add-quiz',
|
'/backoffice/season/{seasonCode:season}/add-quiz',
|
||||||
|
|||||||
@@ -19,6 +19,12 @@ class CandidateRepository extends ServiceEntityRepository
|
|||||||
parent::__construct($registry, Candidate::class);
|
parent::__construct($registry, Candidate::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function deleteCandidate(Candidate $candidate): void
|
||||||
|
{
|
||||||
|
$this->getEntityManager()->remove($candidate);
|
||||||
|
$this->getEntityManager()->flush();
|
||||||
|
}
|
||||||
|
|
||||||
public function getCandidateByHash(Season $season, string $hash): ?Candidate
|
public function getCandidateByHash(Season $season, string $hash): ?Candidate
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
<h6>Kandidaten</h6>
|
<h6>Kandidaten</h6>
|
||||||
<p>Dit zijn de spelers van dit seizoen. Voeg alle deelnemers toe voordat je de eerste test start, kandidaten worden automatisch aan nieuwe testen gekoppeld.</p>
|
<p>Dit zijn de spelers van dit seizoen. Voeg alle deelnemers toe voordat je de eerste test start, kandidaten worden automatisch aan nieuwe testen gekoppeld.</p>
|
||||||
<p>Namen zijn vrij in te voeren, gebruik dezelfde schrijfwijze die je in het spel gebruikt.</p>
|
<p>Namen zijn vrij in te voeren, gebruik dezelfde schrijfwijze die je in het spel gebruikt.</p>
|
||||||
|
<p>Gebruik het potlood-icoon om een kandidaat te hernoemen en het prullenbak-icoon om er een te verwijderen. Verwijderen gooit ook alle gegeven antwoorden van die kandidaat weg.</p>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
<h6>Seizoensinstellingen</h6>
|
<h6>Seizoensinstellingen</h6>
|
||||||
<p>Pas hier de weergave-instellingen van dit seizoen aan.</p>
|
<p>Pas hier de weergave-instellingen van dit seizoen aan.</p>
|
||||||
<p><strong>Nummers tonen:</strong> toont vraagnummers tijdens de test. <strong>Antwoord bevestigen:</strong> vraagt kandidaten om hun antwoord te bevestigen voordat ze doorgaan.</p>
|
<p><strong>Nummers tonen:</strong> toont vraagnummers tijdens de test. <strong>Antwoord bevestigen:</strong> vraagt kandidaten om hun antwoord te bevestigen voordat ze doorgaan.</p>
|
||||||
|
<p><strong>Seizoenscode:</strong> de code waarmee kandidaten dit seizoen kunnen vinden. Genereer een nieuwe code als de huidige per ongeluk gedeeld is, de oude code werkt daarna niet meer.</p>
|
||||||
|
|||||||
@@ -4,9 +4,67 @@
|
|||||||
<a class="btn btn-sm btn-outline-primary"
|
<a class="btn btn-sm btn-outline-primary"
|
||||||
href="{{ path('tvdt_backoffice_add_candidates', {seasonCode: season.seasonCode}) }}">{{ 'Add Candidate'|trans }}</a>
|
href="{{ path('tvdt_backoffice_add_candidates', {seasonCode: season.seasonCode}) }}">{{ 'Add Candidate'|trans }}</a>
|
||||||
</div>
|
</div>
|
||||||
<ul class="mb-3">
|
<ul class="list-group mb-3">
|
||||||
{% for candidate in season.candidates %}
|
{% for candidate in season.candidates %}
|
||||||
<li>{{ candidate.name }}</li>
|
<li class="list-group-item d-flex align-items-center justify-content-between gap-2">
|
||||||
|
{{ candidate.name }}
|
||||||
|
<div class="btn-group btn-group-sm" role="group">
|
||||||
|
<button type="button" class="btn btn-outline-secondary" data-bs-toggle="modal"
|
||||||
|
data-bs-target="#renameCandidate-{{ candidate.id }}"
|
||||||
|
title="{{ 'Rename'|trans }}"><i class="bi bi-pencil"></i></button>
|
||||||
|
<button type="button" class="btn btn-outline-danger" data-bs-toggle="modal"
|
||||||
|
data-bs-target="#deleteCandidate-{{ candidate.id }}"
|
||||||
|
title="{{ 'Delete'|trans }}"><i class="bi bi-trash"></i></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" id="renameCandidate-{{ candidate.id }}" data-bs-backdrop="static"
|
||||||
|
tabindex="-1" aria-labelledby="renameCandidate-{{ candidate.id }}Label" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<form action="{{ path('tvdt_backoffice_candidate_rename', {seasonCode: season.seasonCode, candidate: candidate.id}) }}"
|
||||||
|
method="POST">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h1 class="modal-title fs-5" id="renameCandidate-{{ candidate.id }}Label">{{ 'Rename candidate'|trans }}</h1>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body text-start">
|
||||||
|
<input type="hidden" name="_token" value="{{ csrf_token('rename_candidate') }}">
|
||||||
|
<label class="form-label" for="renameCandidateName-{{ candidate.id }}">{{ 'Name'|trans }}</label>
|
||||||
|
<input type="text" class="form-control" id="renameCandidateName-{{ candidate.id }}"
|
||||||
|
name="name" value="{{ candidate.name }}" maxlength="16" required autofocus>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ 'Cancel'|trans }}</button>
|
||||||
|
<button type="submit" class="btn btn-primary">{{ 'Rename'|trans }}</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" id="deleteCandidate-{{ candidate.id }}" data-bs-backdrop="static"
|
||||||
|
tabindex="-1" aria-labelledby="deleteCandidate-{{ candidate.id }}Label" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h1 class="modal-title fs-5" id="deleteCandidate-{{ candidate.id }}Label">{{ 'Please Confirm'|trans }}</h1>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body text-start">
|
||||||
|
{{ 'Are you sure you want to delete this candidate? All their answers will be lost.'|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_candidate_delete', {seasonCode: season.seasonCode, candidate: candidate.id}) }}"
|
||||||
|
method="POST">
|
||||||
|
<input type="hidden" name="_token" value="{{ csrf_token('delete_candidate') }}">
|
||||||
|
<button type="submit" class="btn btn-danger">{{ 'Yes'|trans }}</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ 'No candidates'|trans }}
|
{{ 'No candidates'|trans }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@@ -1,8 +1,40 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6 col-12">
|
<div class="col-md-6 col-12">
|
||||||
{{ form(form) }}
|
{{ form(form) }}
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h4 class="text-danger">{{ 'Season code'|trans }}</h4>
|
||||||
|
<p>{{ 'The season code is used by candidates to join this season. Regenerating it invalidates the current code, so make sure to share the new one.'|trans }}</p>
|
||||||
|
<p><strong>{{ 'Current code:'|trans }}</strong> {{ season.seasonCode }}</p>
|
||||||
|
<button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#regenerateSeasonCodeModal">
|
||||||
|
{{ 'Regenerate season code...'|trans }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 col-12">
|
<div class="col-md-6 col-12">
|
||||||
{{ include('backoffice/help/season_settings.html.twig') }}
|
{{ include('backoffice/help/season_settings.html.twig') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" id="regenerateSeasonCodeModal" data-bs-backdrop="static"
|
||||||
|
tabindex="-1"
|
||||||
|
aria-labelledby="regenerateSeasonCodeModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<form action="{{ path('tvdt_backoffice_season_regenerate_code', {seasonCode: season.seasonCode}) }}" method="POST">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h1 class="modal-title fs-5" id="regenerateSeasonCodeModalLabel">{{ 'Regenerate season code'|trans }}</h1>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p>{{ 'This invalidates the current season code. Anyone using the old code will no longer be able to join this season.'|trans }}</p>
|
||||||
|
<input type="hidden" name="_token" value="{{ csrf_token('regenerate_season_code') }}">
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ 'Cancel'|trans }}</button>
|
||||||
|
<button type="submit" class="btn btn-danger">{{ 'Regenerate season code'|trans }}</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -8,11 +8,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="list-group mb-3">
|
<div class="list-group mb-3">
|
||||||
{% for quiz in season.quizzes %}
|
{% for quiz in season.quizzes %}
|
||||||
<a class="list-group-item list-group-item-action{% if season.activeQuiz == quiz %} active{% endif %}"
|
<a class="list-group-item list-group-item-action d-flex align-items-center gap-2{% if season.activeQuiz == quiz %} active{% endif %}"
|
||||||
href="{{ path('tvdt_backoffice_quiz', {seasonCode: season.seasonCode, quiz: quiz.id}) }}">
|
href="{{ path('tvdt_backoffice_quiz', {seasonCode: season.seasonCode, quiz: quiz.id}) }}">
|
||||||
{{ quiz.name }}
|
{{ quiz.name }}
|
||||||
{% if quiz.isFinalized %}
|
{% if season.activeQuiz == quiz %}
|
||||||
<span class="badge text-bg-success">{{ 'Finalized'|trans }}</span>
|
<span class="badge text-bg-light ms-auto">{{ 'Active'|trans }}</span>
|
||||||
|
{% elseif quiz.isFinalized %}
|
||||||
|
<span class="badge text-bg-success ms-auto">{{ 'Ready'|trans }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|||||||
@@ -0,0 +1,159 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tvdt\Tests\Controller\Backoffice;
|
||||||
|
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use PHPUnit\Framework\Attributes\CoversClass;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Tvdt\Controller\Backoffice\SeasonController;
|
||||||
|
use Tvdt\Entity\Candidate;
|
||||||
|
use Tvdt\Entity\Season;
|
||||||
|
use Tvdt\Entity\User;
|
||||||
|
|
||||||
|
#[CoversClass(SeasonController::class)]
|
||||||
|
final class SeasonControllerTest extends WebTestCase
|
||||||
|
{
|
||||||
|
private KernelBrowser $client;
|
||||||
|
|
||||||
|
private EntityManagerInterface $entityManager;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
$this->client = self::createClient();
|
||||||
|
$this->entityManager = self::getContainer()->get(EntityManagerInterface::class);
|
||||||
|
|
||||||
|
$user = $this->entityManager->getRepository(User::class)->findOneBy(['email' => 'krtek-admin@example.org']);
|
||||||
|
$this->assertInstanceOf(User::class, $user);
|
||||||
|
$this->client->loginUser($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRegenerateSeasonCodeChangesTheCode(): void
|
||||||
|
{
|
||||||
|
$oldCode = 'krtek';
|
||||||
|
$crawler = $this->client->request(Request::METHOD_GET, \sprintf('/backoffice/season/%s/settings', $oldCode));
|
||||||
|
self::assertResponseIsSuccessful();
|
||||||
|
|
||||||
|
$token = (string) $crawler->filter('form[action*="/regenerate-code"] input[name="_token"]')->first()->attr('value');
|
||||||
|
|
||||||
|
$this->client->request(Request::METHOD_POST, \sprintf('/backoffice/season/%s/settings/regenerate-code', $oldCode), [
|
||||||
|
'_token' => $token,
|
||||||
|
]);
|
||||||
|
|
||||||
|
self::assertResponseRedirects();
|
||||||
|
$this->entityManager->clear();
|
||||||
|
|
||||||
|
$this->assertNotInstanceOf(Season::class, $this->entityManager->getRepository(Season::class)->findOneBy(['seasonCode' => $oldCode]));
|
||||||
|
|
||||||
|
$location = (string) $this->client->getResponse()->headers->get('Location');
|
||||||
|
$this->assertMatchesRegularExpression('#^/backoffice/season/[a-z]{5}/settings$#', $location);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRegenerateSeasonCodeIsDeniedForNonOwner(): void
|
||||||
|
{
|
||||||
|
$crawler = $this->client->request(Request::METHOD_GET, '/backoffice/season/krtek/settings');
|
||||||
|
self::assertResponseIsSuccessful();
|
||||||
|
$token = (string) $crawler->filter('form[action*="/regenerate-code"] input[name="_token"]')->first()->attr('value');
|
||||||
|
|
||||||
|
$user = $this->entityManager->getRepository(User::class)->findOneBy(['email' => 'test@example.org']);
|
||||||
|
$this->assertInstanceOf(User::class, $user);
|
||||||
|
$this->client->loginUser($user);
|
||||||
|
|
||||||
|
$this->client->request(Request::METHOD_POST, '/backoffice/season/krtek/settings/regenerate-code', [
|
||||||
|
'_token' => $token,
|
||||||
|
]);
|
||||||
|
|
||||||
|
self::assertResponseStatusCodeSame(403);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getCandidate(string $name): Candidate
|
||||||
|
{
|
||||||
|
$candidate = $this->entityManager->getRepository(Candidate::class)->findOneBy(['name' => $name]);
|
||||||
|
$this->assertInstanceOf(Candidate::class, $candidate);
|
||||||
|
|
||||||
|
return $candidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getCsrfTokenFromCandidatesTab(string $formActionContains): string
|
||||||
|
{
|
||||||
|
$crawler = $this->client->request(Request::METHOD_GET, '/backoffice/season/krtek/candidates');
|
||||||
|
self::assertResponseIsSuccessful();
|
||||||
|
|
||||||
|
$input = $crawler->filter(\sprintf('form[action*="%s"] input[name="_token"]', $formActionContains));
|
||||||
|
$this->assertGreaterThan(0, $input->count(), \sprintf('No form found with action containing "%s"', $formActionContains));
|
||||||
|
|
||||||
|
return (string) $input->first()->attr('value');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRenameCandidate(): void
|
||||||
|
{
|
||||||
|
$candidate = $this->getCandidate('Tom');
|
||||||
|
$token = $this->getCsrfTokenFromCandidatesTab(\sprintf('/candidate/%s/rename', $candidate->id));
|
||||||
|
|
||||||
|
$this->client->request(Request::METHOD_POST, \sprintf('/backoffice/season/krtek/candidate/%s/rename', $candidate->id), [
|
||||||
|
'_token' => $token,
|
||||||
|
'name' => 'Tommy',
|
||||||
|
]);
|
||||||
|
|
||||||
|
self::assertResponseRedirects('/backoffice/season/krtek/candidates');
|
||||||
|
$this->entityManager->clear();
|
||||||
|
|
||||||
|
$renamed = $this->entityManager->getRepository(Candidate::class)->find($candidate->id);
|
||||||
|
$this->assertInstanceOf(Candidate::class, $renamed);
|
||||||
|
$this->assertSame('Tommy', $renamed->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRenameCandidateToExistingNameShowsError(): void
|
||||||
|
{
|
||||||
|
$candidate = $this->getCandidate('Tom');
|
||||||
|
$token = $this->getCsrfTokenFromCandidatesTab(\sprintf('/candidate/%s/rename', $candidate->id));
|
||||||
|
|
||||||
|
$this->client->request(Request::METHOD_POST, \sprintf('/backoffice/season/krtek/candidate/%s/rename', $candidate->id), [
|
||||||
|
'_token' => $token,
|
||||||
|
'name' => 'Claudia',
|
||||||
|
]);
|
||||||
|
|
||||||
|
self::assertResponseRedirects('/backoffice/season/krtek/candidates');
|
||||||
|
$this->entityManager->clear();
|
||||||
|
|
||||||
|
$unchanged = $this->entityManager->getRepository(Candidate::class)->find($candidate->id);
|
||||||
|
$this->assertInstanceOf(Candidate::class, $unchanged);
|
||||||
|
$this->assertSame('Tom', $unchanged->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDeleteCandidate(): void
|
||||||
|
{
|
||||||
|
$candidate = $this->getCandidate('Tom');
|
||||||
|
$candidateId = $candidate->id;
|
||||||
|
$token = $this->getCsrfTokenFromCandidatesTab(\sprintf('/candidate/%s/delete', $candidate->id));
|
||||||
|
|
||||||
|
$this->client->request(Request::METHOD_POST, \sprintf('/backoffice/season/krtek/candidate/%s/delete', $candidate->id), [
|
||||||
|
'_token' => $token,
|
||||||
|
]);
|
||||||
|
|
||||||
|
self::assertResponseRedirects('/backoffice/season/krtek/candidates');
|
||||||
|
$this->entityManager->clear();
|
||||||
|
|
||||||
|
$this->assertNotInstanceOf(Candidate::class, $this->entityManager->getRepository(Candidate::class)->find($candidateId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRenameCandidateIsDeniedForNonOwner(): void
|
||||||
|
{
|
||||||
|
$candidate = $this->getCandidate('Tom');
|
||||||
|
$token = $this->getCsrfTokenFromCandidatesTab(\sprintf('/candidate/%s/rename', $candidate->id));
|
||||||
|
|
||||||
|
$user = $this->entityManager->getRepository(User::class)->findOneBy(['email' => 'test@example.org']);
|
||||||
|
$this->assertInstanceOf(User::class, $user);
|
||||||
|
$this->client->loginUser($user);
|
||||||
|
|
||||||
|
$this->client->request(Request::METHOD_POST, \sprintf('/backoffice/season/krtek/candidate/%s/rename', $candidate->id), [
|
||||||
|
'_token' => $token,
|
||||||
|
'name' => 'Tommy',
|
||||||
|
]);
|
||||||
|
|
||||||
|
self::assertResponseStatusCodeSame(403);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,10 @@
|
|||||||
<tool tool-id="symfony" tool-name="Symfony"/>
|
<tool tool-id="symfony" tool-name="Symfony"/>
|
||||||
</header>
|
</header>
|
||||||
<body>
|
<body>
|
||||||
|
<trans-unit id="QcFeGZy" resname="A candidate with this name already exists in this season">
|
||||||
|
<source>A candidate with this name already exists in this season</source>
|
||||||
|
<target>Er bestaat al een kandidaat met deze naam in dit seizoen</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="VNxXghX" resname="A label with a similar name already exists">
|
<trans-unit id="VNxXghX" resname="A label with a similar name already exists">
|
||||||
<source>A label with a similar name already exists</source>
|
<source>A label with a similar name already exists</source>
|
||||||
<target>Er bestaat al een label met deze naam</target>
|
<target>Er bestaat al een label met deze naam</target>
|
||||||
@@ -101,6 +105,10 @@
|
|||||||
<source>Are you sure you want to clear all the results? This will also delete all the eliminations.</source>
|
<source>Are you sure you want to clear all the results? This will also delete all the eliminations.</source>
|
||||||
<target>Weet je zeker dat je de resultaten wilt leegmaken? Dit gooit ook alle eliminaties weg.</target>
|
<target>Weet je zeker dat je de resultaten wilt leegmaken? Dit gooit ook alle eliminaties weg.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="zisWo9d" resname="Are you sure you want to delete this candidate? All their answers will be lost.">
|
||||||
|
<source>Are you sure you want to delete this candidate? All their answers will be lost.</source>
|
||||||
|
<target>Weet je zeker dat je deze kandidaat wilt verwijderen? Alle gegeven antwoorden gaan dan verloren.</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="8HZ5s3T" resname="Are you sure you want to delete this question from the question bank?">
|
<trans-unit id="8HZ5s3T" resname="Are you sure you want to delete this question from the question bank?">
|
||||||
<source>Are you sure you want to delete this question from the question bank?</source>
|
<source>Are you sure you want to delete this question from the question bank?</source>
|
||||||
<target>Weet je zeker dat je deze vraag uit de vragenbank wilt verwijderen?</target>
|
<target>Weet je zeker dat je deze vraag uit de vragenbank wilt verwijderen?</target>
|
||||||
@@ -145,10 +153,18 @@
|
|||||||
<source>Candidate answers saved</source>
|
<source>Candidate answers saved</source>
|
||||||
<target>Kandidaatantwoorden opgeslagen</target>
|
<target>Kandidaatantwoorden opgeslagen</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="tggdgJl" resname="Candidate deleted">
|
||||||
|
<source>Candidate deleted</source>
|
||||||
|
<target>Kandidaat verwijderd</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="TiTLBGW" resname="Candidate not found">
|
<trans-unit id="TiTLBGW" resname="Candidate not found">
|
||||||
<source>Candidate not found</source>
|
<source>Candidate not found</source>
|
||||||
<target>Kandidaat niet gevonden</target>
|
<target>Kandidaat niet gevonden</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="QH4e_Ho" resname="Candidate renamed">
|
||||||
|
<source>Candidate renamed</source>
|
||||||
|
<target>Kandidaat hernoemd</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="6QiGbuz" resname="Candidate status updated">
|
<trans-unit id="6QiGbuz" resname="Candidate status updated">
|
||||||
<source>Candidate status updated</source>
|
<source>Candidate status updated</source>
|
||||||
<target>Kandidaatstatus bijgewerkt</target>
|
<target>Kandidaatstatus bijgewerkt</target>
|
||||||
@@ -221,6 +237,10 @@
|
|||||||
<source>Create an empty quiz and add questions from the question bank.</source>
|
<source>Create an empty quiz and add questions from the question bank.</source>
|
||||||
<target>Maak een lege quiz aan en voeg vragen toe vanuit de vragenbank.</target>
|
<target>Maak een lege quiz aan en voeg vragen toe vanuit de vragenbank.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="jrXhJOR" resname="Current code:">
|
||||||
|
<source>Current code:</source>
|
||||||
|
<target>Huidige code:</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="3leUyoA" resname="Current email address:">
|
<trans-unit id="3leUyoA" resname="Current email address:">
|
||||||
<source>Current email address:</source>
|
<source>Current email address:</source>
|
||||||
<target>Huidig e-mailadres:</target>
|
<target>Huidig e-mailadres:</target>
|
||||||
@@ -661,6 +681,10 @@
|
|||||||
<source>Re-opens the quiz for editing. Candidates will no longer be able to take the quiz until it is finalized again.</source>
|
<source>Re-opens the quiz for editing. Candidates will no longer be able to take the quiz until it is finalized again.</source>
|
||||||
<target>Heropent de test voor bewerking. Deelnemers kunnen de test niet meer afnemen totdat deze opnieuw is afgerond.</target>
|
<target>Heropent de test voor bewerking. Deelnemers kunnen de test niet meer afnemen totdat deze opnieuw is afgerond.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="MuwD4xO" resname="Ready">
|
||||||
|
<source>Ready</source>
|
||||||
|
<target>Voorbereid</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="P1HcfAu" resname="Red">
|
<trans-unit id="P1HcfAu" resname="Red">
|
||||||
<source>Red</source>
|
<source>Red</source>
|
||||||
<target>Rood</target>
|
<target>Rood</target>
|
||||||
@@ -669,6 +693,14 @@
|
|||||||
<source>Refresh the page to try again.</source>
|
<source>Refresh the page to try again.</source>
|
||||||
<target>Ververs de pagina om het opnieuw te proberen.</target>
|
<target>Ververs de pagina om het opnieuw te proberen.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="EGW_4W_" resname="Regenerate season code">
|
||||||
|
<source>Regenerate season code</source>
|
||||||
|
<target>Seizoenscode opnieuw genereren</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="EWuNNNu" resname="Regenerate season code...">
|
||||||
|
<source>Regenerate season code...</source>
|
||||||
|
<target>Seizoenscode opnieuw genereren...</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="fGfBzt6" resname="Register">
|
<trans-unit id="fGfBzt6" resname="Register">
|
||||||
<source>Register</source>
|
<source>Register</source>
|
||||||
<target>Registreren</target>
|
<target>Registreren</target>
|
||||||
@@ -681,6 +713,14 @@
|
|||||||
<source>Remove label</source>
|
<source>Remove label</source>
|
||||||
<target>Label verwijderen</target>
|
<target>Label verwijderen</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="WHywg0z" resname="Rename">
|
||||||
|
<source>Rename</source>
|
||||||
|
<target>Hernoemen</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="K2RP6H8" resname="Rename candidate">
|
||||||
|
<source>Rename candidate</source>
|
||||||
|
<target>Kandidaat hernoemen</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="Z9CSKpk" resname="Repeat Password">
|
<trans-unit id="Z9CSKpk" resname="Repeat Password">
|
||||||
<source>Repeat Password</source>
|
<source>Repeat Password</source>
|
||||||
<target>Herhaal wachtwoord</target>
|
<target>Herhaal wachtwoord</target>
|
||||||
@@ -729,6 +769,14 @@
|
|||||||
<source>Season Name</source>
|
<source>Season Name</source>
|
||||||
<target>Seizoennaam</target>
|
<target>Seizoennaam</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="IxKDF4a" resname="Season code">
|
||||||
|
<source>Season code</source>
|
||||||
|
<target>Seizoenscode</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="iigT2eM" resname="Season code regenerated">
|
||||||
|
<source>Season code regenerated</source>
|
||||||
|
<target>Seizoenscode opnieuw gegenereerd</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="kc_J96C" resname="Seasons">
|
<trans-unit id="kc_J96C" resname="Seasons">
|
||||||
<source>Seasons</source>
|
<source>Seasons</source>
|
||||||
<target>Seizoenen</target>
|
<target>Seizoenen</target>
|
||||||
@@ -769,6 +817,18 @@
|
|||||||
<source>Sync latest changes to this quiz</source>
|
<source>Sync latest changes to this quiz</source>
|
||||||
<target>Laatste wijzigingen synchroniseren naar deze quiz</target>
|
<target>Laatste wijzigingen synchroniseren naar deze quiz</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="cug5d45" resname="The candidate name must be between 1 and 16 characters">
|
||||||
|
<source>The candidate name must be between 1 and 16 characters</source>
|
||||||
|
<target>De naam van de kandidaat moet tussen de 1 en 16 tekens zijn</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="XwQ1Fav" resname="The confirmation email could not be sent. Please try again later.">
|
||||||
|
<source>The confirmation email could not be sent. Please try again later.</source>
|
||||||
|
<target>De bevestigingsmail kon niet worden verzonden. Probeer het later opnieuw.</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="mMDwcxj" resname="The confirmation email could not be sent. Please use the resend button to try again.">
|
||||||
|
<source>The confirmation email could not be sent. Please use the resend button to try again.</source>
|
||||||
|
<target>De bevestigingsmail kon niet worden verzonden. Gebruik de knop om het opnieuw te proberen.</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="_z4el3Z" resname="The password fields must match.">
|
<trans-unit id="_z4el3Z" resname="The password fields must match.">
|
||||||
<source>The password fields must match.</source>
|
<source>The password fields must match.</source>
|
||||||
<target>De wachtwoorden moeten overeen komen.</target>
|
<target>De wachtwoorden moeten overeen komen.</target>
|
||||||
@@ -793,6 +853,10 @@
|
|||||||
<source>The quiz must be finalized before it can be activated</source>
|
<source>The quiz must be finalized before it can be activated</source>
|
||||||
<target>De test moet afgerond zijn voordat deze geactiveerd kan worden</target>
|
<target>De test moet afgerond zijn voordat deze geactiveerd kan worden</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="IKPt_Pf" resname="The season code is used by candidates to join this season. Regenerating it invalidates the current code, so make sure to share the new one.">
|
||||||
|
<source>The season code is used by candidates to join this season. Regenerating it invalidates the current code, so make sure to share the new one.</source>
|
||||||
|
<target>De seizoenscode wordt door kandidaten gebruikt om dit seizoen te vinden. Als je een nieuwe code genereert, werkt de oude niet meer, dus deel de nieuwe code opnieuw.</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="HuzRgeN" resname="There are no answers for this question">
|
<trans-unit id="HuzRgeN" resname="There are no answers for this question">
|
||||||
<source>There are no answers for this question</source>
|
<source>There are no answers for this question</source>
|
||||||
<target>Er zijn geen antwoorden voor deze vraag</target>
|
<target>Er zijn geen antwoorden voor deze vraag</target>
|
||||||
@@ -809,6 +873,10 @@
|
|||||||
<source>This deletes your account and every season you are the only owner of. Enter your password to confirm.</source>
|
<source>This deletes your account and every season you are the only owner of. Enter your password to confirm.</source>
|
||||||
<target>Dit verwijdert je account en alle seizoenen waarvan jij de enige eigenaar bent. Vul je wachtwoord in om te bevestigen.</target>
|
<target>Dit verwijdert je account en alle seizoenen waarvan jij de enige eigenaar bent. Vul je wachtwoord in om te bevestigen.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="EBWUWJu" resname="This invalidates the current season code. Anyone using the old code will no longer be able to join this season.">
|
||||||
|
<source>This invalidates the current season code. Anyone using the old code will no longer be able to join this season.</source>
|
||||||
|
<target>Hiermee wordt de huidige seizoenscode ongeldig. Iedereen die de oude code gebruikt, kan dit seizoen niet meer vinden.</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="YueaA2f" resname="This link will expire in %count%.">
|
<trans-unit id="YueaA2f" resname="This link will expire in %count%.">
|
||||||
<source>This link will expire in %count%.</source>
|
<source>This link will expire in %count%.</source>
|
||||||
<target>Deze link verloopt over %count%.</target>
|
<target>Deze link verloopt over %count%.</target>
|
||||||
@@ -901,18 +969,14 @@
|
|||||||
<source>Your data</source>
|
<source>Your data</source>
|
||||||
<target>Je gegevens</target>
|
<target>Je gegevens</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="sAb9l8I" resname="Your email address has been changed.">
|
||||||
|
<source>Your email address has been changed.</source>
|
||||||
|
<target>Je e-mailadres is gewijzigd.</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="OqDtnJw" resname="Your email address has been changed. Please check your inbox to confirm it.">
|
<trans-unit id="OqDtnJw" resname="Your email address has been changed. Please check your inbox to confirm it.">
|
||||||
<source>Your email address has been changed. Please check your inbox to confirm it.</source>
|
<source>Your email address has been changed. Please check your inbox to confirm it.</source>
|
||||||
<target>Je e-mailadres is gewijzigd. Check je inbox om het te bevestigen.</target>
|
<target>Je e-mailadres is gewijzigd. Check je inbox om het te bevestigen.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="kWpL7Rn" resname="The confirmation email could not be sent. Please use the resend button to try again.">
|
|
||||||
<source>The confirmation email could not be sent. Please use the resend button to try again.</source>
|
|
||||||
<target>De bevestigingsmail kon niet worden verzonden. Gebruik de knop om het opnieuw te proberen.</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="mQxV2Jf" resname="The confirmation email could not be sent. Please try again later.">
|
|
||||||
<source>The confirmation email could not be sent. Please try again later.</source>
|
|
||||||
<target>De bevestigingsmail kon niet worden verzonden. Probeer het later opnieuw.</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="m80cBv0" resname="Your email address has been verified.">
|
<trans-unit id="m80cBv0" resname="Your email address has been verified.">
|
||||||
<source>Your email address has been verified.</source>
|
<source>Your email address has been verified.</source>
|
||||||
<target>Je e-mailadres is geverifieerd.</target>
|
<target>Je e-mailadres is geverifieerd.</target>
|
||||||
|
|||||||
Reference in New Issue
Block a user