Compare commits

..

4 Commits

Author SHA1 Message Date
Marijn d3bb8d7c57 Fix question order (#99) 2026-05-16 13:33:44 +02:00
Marijn b799dfd5e5 Remove symlink 2026-05-10 10:43:33 +02:00
Marijn 86e7d07078 Actual hotfix 2026-05-09 17:21:04 +02:00
Marijn c68e865a78 Check for excel and ignore empty cells 2026-05-09 17:11:25 +02:00
7 changed files with 46 additions and 11 deletions
+13
View File
@@ -68,6 +68,19 @@ Icon
# Thumbnails # Thumbnails
._* ._*
# IDEs
/.idea/
/.vscode/
# Junie
!/.junie/
/.junie/memory/
/.junie/plans/
# Windows
Thumbs.db
Desktop.ini
# Files that might appear in the root of a volume # Files that might appear in the root of a volume
.DocumentRevisions-V100 .DocumentRevisions-V100
.fseventsd .fseventsd
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="SqlDialectMappings">
<file url="PROJECT" dialect="PostgreSQL" />
</component>
</project>
+13
View File
@@ -61,6 +61,19 @@ The project uses `just` as the primary task runner. Always prefer `just` command
- CSS/Sass is in `assets/styles/`. - CSS/Sass is in `assets/styles/`.
- Assets are compiled on-the-fly or mapped; do not look for a `node_modules` folder. - Assets are compiled on-the-fly or mapped; do not look for a `node_modules` folder.
## Key Components
### Controllers
- **Backoffice**: Located in `src/Controller/Backoffice`, handles season and quiz management.
- **Quiz**: `src/Controller/QuizController` handles the candidate-facing side of quizzes.
- **Elimination**: `src/Controller/EliminationController` handles elimination screens.
### Services
- **QuizSpreadsheetService**: Handles importing quizzes from XLSX files.
### Base Classes & Enums
- **AbstractController**: Base class for all controllers, containing common regexes and flash helpers.
- **FlashType Enum**: Used for consistent flash messaging (`FlashType::Success`, `FlashType::Danger`, etc.).
## Key Files ## Key Files
- `composer.json`: Dependency management. - `composer.json`: Dependency management.
- `importmap.php`: JavaScript module mapping. - `importmap.php`: JavaScript module mapping.
+5
View File
@@ -8,6 +8,7 @@ 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\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils; use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
use Symfony\Contracts\Translation\TranslatorInterface; use Symfony\Contracts\Translation\TranslatorInterface;
use Tvdt\Enum\FlashType; use Tvdt\Enum\FlashType;
@@ -20,6 +21,10 @@ final class LoginController extends AbstractController
#[Route(path: '/login', name: 'tvdt_login_login')] #[Route(path: '/login', name: 'tvdt_login_login')]
public function login(): Response public function login(): Response
{ {
if ($this->getUser() instanceof UserInterface) {
return $this->redirectToRoute('tvdt_backoffice_index');
}
// get the login error if there is one // get the login error if there is one
$error = $this->authenticationUtils->getLastAuthenticationError(); $error = $this->authenticationUtils->getLastAuthenticationError();
// last username entered by the user // last username entered by the user
@@ -15,6 +15,7 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Mailer\Exception\TransportExceptionInterface; use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Contracts\Translation\TranslatorInterface; use Symfony\Contracts\Translation\TranslatorInterface;
use SymfonyCasts\Bundle\VerifyEmail\Exception\VerifyEmailExceptionInterface; use SymfonyCasts\Bundle\VerifyEmail\Exception\VerifyEmailExceptionInterface;
use Tvdt\Entity\User; use Tvdt\Entity\User;
@@ -30,6 +31,10 @@ final class RegistrationController extends AbstractController
public function register( public function register(
Request $request, Request $request,
): Response { ): Response {
if ($this->getUser() instanceof UserInterface) {
return $this->redirectToRoute('tvdt_backoffice_index');
}
$user = new User(); $user = new User();
$form = $this->createForm(RegistrationFormType::class, $user); $form = $this->createForm(RegistrationFormType::class, $user);
$form->handleRequest($request); $form->handleRequest($request);
+1
View File
@@ -30,6 +30,7 @@ class QuestionRepository extends ServiceEntityRepository
and q1.quiz = :quiz and q1.quiz = :quiz
) )
and qz = :quiz and qz = :quiz
order by q.ordering
DQL) DQL)
->setMaxResults(1) ->setMaxResults(1)
->setParameter('candidate', $candidate) ->setParameter('candidate', $candidate)
+5 -1
View File
@@ -95,6 +95,7 @@ class QuizSpreadsheetService
$arrCounter = 1; $arrCounter = 1;
while (true) { while (true) {
try {
if (null === $questionArr[$arrCounter]) { if (null === $questionArr[$arrCounter]) {
if (1 === $answerCounter) { if (1 === $answerCounter) {
$errors[] = \sprintf('Question %d has no answers', $answerCounter); $errors[] = \sprintf('Question %d has no answers', $answerCounter);
@@ -102,6 +103,9 @@ class QuizSpreadsheetService
break; break;
} }
} catch (\ErrorException) {
break;
}
$answer = new Answer((string) $questionArr[$arrCounter++], (bool) $questionArr[$arrCounter++]); $answer = new Answer((string) $questionArr[$arrCounter++], (bool) $questionArr[$arrCounter++]);
$answer->ordering = $answerCounter++; $answer->ordering = $answerCounter++;
@@ -130,6 +134,6 @@ class QuizSpreadsheetService
private function isSpreadsheetFile(File $file): bool private function isSpreadsheetFile(File $file): bool
{ {
return 'xlsx' === $file->getExtension(); return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' === $file->getMimeType();
} }
} }