5 Commits

Author SHA1 Message Date
dependabot[bot]
82fc64bbc2 Bump phpstan/phpstan-doctrine from 2.0.6 to 2.0.10
Bumps [phpstan/phpstan-doctrine](https://github.com/phpstan/phpstan-doctrine) from 2.0.6 to 2.0.10.
- [Release notes](https://github.com/phpstan/phpstan-doctrine/releases)
- [Commits](https://github.com/phpstan/phpstan-doctrine/compare/2.0.6...2.0.10)

---
updated-dependencies:
- dependency-name: phpstan/phpstan-doctrine
  dependency-version: 2.0.10
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-06 23:32:58 +00:00
ca460cca7f - Refactor ORM annotations across entities for consistency.
- Adjusted migrations to align with refactored ORM annotations.
- Added new PHPStan and PHP-CS-Fixer configurations, including stricter rules.
- Introduced `tests/object-manager.php` to improve test environment setup.
2025-10-04 12:40:45 +02:00
3e39550c90 Remove EasyAdmin integration
- Removed EasyAdmin controllers and configurations.
- Uninstalled `easycorp/easyadmin-bundle` and related dependencies.
- Cleaned up all associated routes, bundles, and vendor references.
2025-10-03 22:37:45 +02:00
0319224979 Dependey updates 2025-09-28 21:19:01 +02:00
81e471a760 Change namespace to Tvdt 2025-09-28 18:14:58 +02:00
119 changed files with 1113 additions and 1475 deletions

View File

@@ -1,6 +0,0 @@
{
"image": "mcr.microsoft.com/devcontainers/universal:2",
"features": {"ghcr.io/devcontainers/features/php:1": {
"version": "8.3"
}}
}

View File

@@ -35,6 +35,9 @@ indent_size = 4
trim_trailing_whitespace = false
indent_size = 2
[config/**/*.{yaml,yml}]
indent_size = 4
[.github/workflows/*.yml]
indent_size = 2

View File

@@ -1,4 +1,4 @@
# define your env variables for the test env here
KERNEL_CLASS='App\Kernel'
KERNEL_CLASS='Tvdt\Kernel'
APP_SECRET='$ecretf0rt3st'
SYMFONY_DEPRECATIONS_HELPER=999999

View File

@@ -2,8 +2,8 @@
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="App\" />
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" packagePrefix="App\Tests\" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="Tvdt\" />
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" packagePrefix="Tvdt\Tests\" />
<excludeFolder url="file://$MODULE_DIR$/vendor/clue/ndjson-react" />
<excludeFolder url="file://$MODULE_DIR$/vendor/composer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/collections" />
@@ -116,15 +116,12 @@
<excludeFolder url="file://$MODULE_DIR$/vendor/thecodingmachine/phpstan-safe-rule" />
<excludeFolder url="file://$MODULE_DIR$/vendor/thecodingmachine/safe" />
<excludeFolder url="file://$MODULE_DIR$/vendor/twig/twig" />
<excludeFolder url="file://$MODULE_DIR$/vendor/easycorp/easyadmin-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/intl" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/mime" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-idn" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/translation" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/ux-twig-component" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/validator" />
<excludeFolder url="file://$MODULE_DIR$/vendor/twig/extra-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/twig/html-extra" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/data-fixtures" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/doctrine-fixtures-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/vincentlanglet/twig-cs-fixer" />
@@ -166,6 +163,7 @@
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/stimulus-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/ux-turbo" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-uuid" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/brevo-mailer" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />

8
.idea/php.xml generated
View File

@@ -68,7 +68,6 @@
<path value="$PROJECT_DIR$/vendor/symfony/form" />
<path value="$PROJECT_DIR$/vendor/runtime/frankenphp-symfony" />
<path value="$PROJECT_DIR$/vendor/symfony/framework-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/validator" />
<path value="$PROJECT_DIR$/vendor/symfony/cache" />
<path value="$PROJECT_DIR$/vendor/symfony/serializer" />
<path value="$PROJECT_DIR$/vendor/symfony/dotenv" />
@@ -78,7 +77,6 @@
<path value="$PROJECT_DIR$/vendor/symfony/browser-kit" />
<path value="$PROJECT_DIR$/vendor/symfony/config" />
<path value="$PROJECT_DIR$/vendor/symfony/security-http" />
<path value="$PROJECT_DIR$/vendor/symfony/translation" />
<path value="$PROJECT_DIR$/vendor/symfony/translation-contracts" />
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher" />
<path value="$PROJECT_DIR$/vendor/symfony/runtime" />
@@ -124,7 +122,6 @@
<path value="$PROJECT_DIR$/vendor/symfony/error-handler" />
<path value="$PROJECT_DIR$/vendor/symfony/cache-contracts" />
<path value="$PROJECT_DIR$/vendor/symfony/console" />
<path value="$PROJECT_DIR$/vendor/symfony/ux-twig-component" />
<path value="$PROJECT_DIR$/vendor/symfony/password-hasher" />
<path value="$PROJECT_DIR$/vendor/symfony/process" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-grapheme" />
@@ -142,7 +139,6 @@
<path value="$PROJECT_DIR$/vendor/doctrine/sql-formatter" />
<path value="$PROJECT_DIR$/vendor/doctrine/orm" />
<path value="$PROJECT_DIR$/vendor/doctrine/event-manager" />
<path value="$PROJECT_DIR$/vendor/easycorp/easyadmin-bundle" />
<path value="$PROJECT_DIR$/vendor/evenement/evenement" />
<path value="$PROJECT_DIR$/vendor/doctrine/deprecations" />
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-bundle" />
@@ -191,12 +187,14 @@
<path value="$PROJECT_DIR$/vendor/clue/ndjson-react" />
<path value="$PROJECT_DIR$/vendor/fidry/cpu-core-counter" />
<path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
<path value="$PROJECT_DIR$/vendor/twig/html-extra" />
<path value="$PROJECT_DIR$/vendor/twig/twig" />
<path value="$PROJECT_DIR$/vendor/symfony/ux-turbo" />
<path value="$PROJECT_DIR$/vendor/symfony/stimulus-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-uuid" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php84" />
<path value="$PROJECT_DIR$/vendor/symfony/brevo-mailer" />
<path value="$PROJECT_DIR$/vendor/symfony/translation" />
<path value="$PROJECT_DIR$/vendor/symfony/validator" />
</include_path>
</component>
<component name="PhpInterpreters">

View File

@@ -5,13 +5,13 @@ use PhpCsFixer\Config;
use PhpCsFixer\Finder;
use PhpCsFixer\Runner\Parallel\ParallelConfigFactory;
$finder = (new Finder())
$finder = new Finder()
->in(__DIR__)
->exclude('var')
->exclude('bin')
;
return (new Config())
return new Config()
->setParallelConfig(ParallelConfigFactory::detect())
->setRules([
'@Symfony' => true,
@@ -30,8 +30,9 @@ return (new Config())
'single_line_empty_body' => true,
'strict_comparison' => true,
'strict_param' => true,
'ordered_attributes' => true,
'heredoc_indentation' => ['indentation' => 'start_plus_one'],
'trailing_comma_in_multiline' => ['after_heredoc' => true, 'elements' => ['arguments', 'array_destructuring', 'arrays', 'match', 'parameters']],
])
->setRiskyAllowed(true)
->setFinder($finder)

View File

@@ -1,8 +1,8 @@
up:
docker compose up -d
up *args:
docker compose up -d {{ args }}
down *args:
docker compose down {{ args }} --remove-orphans
docker compose down --remove-orphans {{ args }}
stop:
docker compose stop

View File

@@ -3,7 +3,7 @@
declare(strict_types=1);
use App\Kernel;
use Tvdt\Kernel;
use Symfony\Bundle\FrameworkBundle\Console\Application;
if (!is_dir(dirname(__DIR__).'/vendor')) {

View File

@@ -15,7 +15,6 @@ services:
# See https://xdebug.org/docs/all_settings#mode
XDEBUG_MODE: "${XDEBUG_MODE:-off}"
MAILER_DSN: "smtp://mailer:1025"
PHP_CS_FIXER_IGNORE_ENV: 1
extra_hosts:
# Ensure that host.docker.internal is correctly defined on Linux
- host.docker.internal:host-gateway

View File

@@ -10,17 +10,17 @@
"ext-ctype": "*",
"ext-iconv": "*",
"doctrine/dbal": "^4.3.3",
"doctrine/doctrine-bundle": "^2.16.1",
"doctrine/doctrine-bundle": "^2.16.2",
"doctrine/doctrine-migrations-bundle": "^3.4.2",
"doctrine/orm": "^3.5.2",
"easycorp/easyadmin-bundle": "^4.25.0",
"phpdocumentor/reflection-docblock": "^5.6.3",
"phpoffice/phpspreadsheet": "^5.1",
"phpstan/phpdoc-parser": "^2.3",
"runtime/frankenphp-symfony": "^0.2.0",
"sentry/sentry-symfony": "^5.4",
"sentry/sentry-symfony": "^5.6",
"symfony/asset": "7.3.*",
"symfony/asset-mapper": "7.3.*",
"symfony/brevo-mailer": "7.3.*",
"symfony/console": "7.3.*",
"symfony/dotenv": "7.3.*",
"symfony/flex": "^2.8.2",
@@ -33,9 +33,11 @@
"symfony/security-bundle": "7.3.*",
"symfony/security-csrf": "7.3.*",
"symfony/serializer": "7.3.*",
"symfony/translation": "7.3.*",
"symfony/twig-bundle": "7.3.*",
"symfony/uid": "7.3.*",
"symfony/ux-turbo": "^2.30.0",
"symfony/validator": "7.3.*",
"symfony/yaml": "7.3.*",
"symfonycasts/sass-bundle": "^0.8.3",
"symfonycasts/verify-email-bundle": "^1.17.4",
@@ -46,14 +48,14 @@
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^4.1",
"friendsofphp/php-cs-fixer": "^3.87.1",
"friendsofphp/php-cs-fixer": "^3.88.2",
"phpstan/extension-installer": "^1.4.3",
"phpstan/phpstan": "^2.1.22",
"phpstan/phpstan-doctrine": "^2.0.5",
"phpstan/phpstan": "^2.1.30",
"phpstan/phpstan-doctrine": "^2.0.6",
"phpstan/phpstan-phpunit": "^2.0.7",
"phpstan/phpstan-symfony": "^2.0.8",
"phpunit/phpunit": "^12.3.8",
"rector/rector": "^2.1.6",
"phpunit/phpunit": "^12.4.0",
"rector/rector": "^2.1.7",
"roave/security-advisories": "dev-latest",
"symfony/browser-kit": "7.3.*",
"symfony/css-selector": "7.3.*",
@@ -62,7 +64,7 @@
"symfony/stopwatch": "7.3.*",
"symfony/web-profiler-bundle": "7.3.*",
"thecodingmachine/phpstan-safe-rule": "^1.4.1",
"vincentlanglet/twig-cs-fixer": "^3.9.0"
"vincentlanglet/twig-cs-fixer": "^3.10.0"
},
"config": {
"allow-plugins": {
@@ -76,12 +78,12 @@
},
"autoload": {
"psr-4": {
"App\\": "src/"
"Tvdt\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"App\\Tests\\": "tests/"
"Tvdt\\Tests\\": "tests/"
}
},
"replace": {

985
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,6 @@ declare(strict_types=1);
use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
use Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle;
use Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle;
use EasyCorp\Bundle\EasyAdminBundle\EasyAdminBundle;
use Sentry\SentryBundle\SentryBundle;
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
use Symfony\Bundle\MakerBundle\MakerBundle;
@@ -14,7 +13,6 @@ use Symfony\Bundle\TwigBundle\TwigBundle;
use Symfony\Bundle\WebProfilerBundle\WebProfilerBundle;
use Symfony\UX\StimulusBundle\StimulusBundle;
use Symfony\UX\Turbo\TurboBundle;
use Symfony\UX\TwigComponent\TwigComponentBundle;
use SymfonyCasts\Bundle\VerifyEmail\SymfonyCastsVerifyEmailBundle;
use Symfonycasts\SassBundle\SymfonycastsSassBundle;
use Twig\Extra\TwigExtraBundle\TwigExtraBundle;
@@ -28,8 +26,6 @@ return [
SecurityBundle::class => ['all' => true],
WebProfilerBundle::class => ['dev' => true, 'test' => true],
TwigExtraBundle::class => ['all' => true],
TwigComponentBundle::class => ['all' => true],
EasyAdminBundle::class => ['all' => true],
DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
SymfonyCastsVerifyEmailBundle::class => ['all' => true],
SentryBundle::class => ['prod' => true],

View File

@@ -18,12 +18,12 @@ doctrine:
Doctrine\DBAL\Platforms\PostgreSQLPlatform: identity
auto_mapping: true
mappings:
App:
Tvdt:
type: attribute
is_bundle: false
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: App
prefix: 'Tvdt\Entity'
alias: Tvdt
controller_resolver:
auto_mapping: false

View File

@@ -1,6 +1,6 @@
doctrine_migrations:
migrations_paths:
# namespace is arbitrary but should be different from App\Migrations
# namespace is arbitrary but should be different from Tvdt\Migrations
# as migrations classes should NOT be autoloaded
'DoctrineMigrations': '%kernel.project_dir%/migrations'
enable_profiler: false

View File

@@ -5,9 +5,9 @@ security:
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
tvdt_user_provider:
entity:
class: App\Entity\User
class: Tvdt\Entity\User
property: email
# used to reload user from session & other features (e.g. switch_user)
firewalls:
@@ -16,16 +16,16 @@ security:
security: false
main:
lazy: true
provider: app_user_provider
provider: tvdt_user_provider
form_login:
login_path: app_login_login
check_path: app_login_login
login_path: tvdt_login_login
check_path: tvdt_login_login
enable_csrf: true
default_target_path: app_backoffice_index
default_target_path: tvdt_backoffice_index
logout:
path: app_login_logout
path: tvdt_login_logout
# where to redirect after logout
# target: app_any_route
# target: tvdt_any_route
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#the-firewall

View File

@@ -1,5 +0,0 @@
twig_component:
anonymous_template_directory: 'components/'
defaults:
# Namespace & directory for components
App\Twig\Components\: 'components/'

View File

@@ -3,7 +3,7 @@ framework:
# Enables validator auto-mapping support.
# For instance, basic validation constraints will be inferred from Doctrine's metadata.
#auto_mapping:
# App\Entity\: []
# Tvdt\Entity\: []
when@test:
framework:

View File

@@ -1,5 +1,5 @@
controllers:
resource:
path: ../src/Controller/
namespace: App\Controller
namespace: Tvdt\Controller
type: attribute

View File

@@ -1,9 +1,9 @@
controllers:
resource:
path: ../../src/Controller/
namespace: App\Controller
namespace: Tvdt\Controller
type: attribute
kernel:
resource: App\Kernel
resource: Tvdt\Kernel
type: attribute

View File

@@ -1,3 +0,0 @@
easyadmin:
resource: .
type: easyadmin.routes

View File

@@ -13,7 +13,7 @@ services:
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
Tvdt\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'

View File

@@ -8,3 +8,7 @@ parameters:
- src/
- tests/
treatPhpDocTypesAsCertain: false
symfony:
containerXmlPath: var/cache/dev/Tvdt_KernelDevDebugContainer.xml
doctrine:
objectManagerLoader: tests/object-manager.php

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
use App\Kernel;
use Tvdt\Kernel;
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';

View File

@@ -2,19 +2,19 @@
declare(strict_types=1);
namespace App\Command;
namespace Tvdt\Command;
use App\Entity\SeasonSettings;
use App\Repository\SeasonRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Tvdt\Entity\SeasonSettings;
use Tvdt\Repository\SeasonRepository;
#[AsCommand(
name: 'app:add-settings',
name: 'tvdt:add-settings',
description: 'Add a short description for your command',
)]
readonly class AddSettingsCommand

View File

@@ -2,10 +2,8 @@
declare(strict_types=1);
namespace App\Command;
namespace Tvdt\Command;
use App\Repository\SeasonRepository;
use App\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Attribute\Argument;
use Symfony\Component\Console\Attribute\AsCommand;
@@ -13,9 +11,11 @@ use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Tvdt\Repository\SeasonRepository;
use Tvdt\Repository\UserRepository;
#[AsCommand(
name: 'app:claim-season',
name: 'tvdt:claim-season',
description: 'Give a user owner rights on a season',
)]
readonly class ClaimSeasonCommand

View File

@@ -2,18 +2,18 @@
declare(strict_types=1);
namespace App\Command;
namespace Tvdt\Command;
use App\Repository\UserRepository;
use Symfony\Component\Console\Attribute\Argument;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Tvdt\Repository\UserRepository;
#[AsCommand(
name: 'app:make-admin',
name: 'tvdt:make-admin',
description: 'Give a user the role admin',
)]
readonly class MakeAdminCommand

View File

@@ -2,10 +2,10 @@
declare(strict_types=1);
namespace App\Controller;
namespace Tvdt\Controller;
use App\Enum\FlashType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController as AbstractBaseController;
use Tvdt\Enum\FlashType;
abstract class AbstractController extends AbstractBaseController
{

View File

@@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin;
use App\Entity\Answer;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
/** @extends AbstractCrudController<Answer> */
class AnswerCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return Answer::class;
}
}

View File

@@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin;
use App\Entity\Candidate;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
/** @extends AbstractCrudController<Candidate> */
class CandidateCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return Candidate::class;
}
}

View File

@@ -1,67 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin;
use App\Entity\Answer;
use App\Entity\Candidate;
use App\Entity\GivenAnswer;
use App\Entity\Question;
use App\Entity\Quiz;
use App\Entity\QuizCandidate;
use App\Entity\Season;
use App\Entity\User;
use EasyCorp\Bundle\EasyAdminBundle\Attribute\AdminDashboard;
use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard;
use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
use Symfony\Component\HttpFoundation\Response;
#[AdminDashboard(routePath: '/admin', routeName: 'admin')]
class DashboardController extends AbstractDashboardController
{
#[\Override]
public function index(): Response
{
// Option 1. You can make your dashboard redirect to some common page of your backend
//
$adminUrlGenerator = $this->container->get(AdminUrlGenerator::class);
return $this->redirect($adminUrlGenerator->setController(SeasonCrudController::class)->generateUrl());
// Option 2. You can make your dashboard redirect to different pages depending on the user
//
// if ('jane' === $this->getUser()->getUsername()) {
// return $this->redirect('...');
// }
// Option 3. You can render some custom template to display a proper dashboard with widgets, etc.
// (tip: it's easier if your template extends from @EasyAdmin/page/content.html.twig)
//
// return $this->render('some/path/my-dashboard.html.twig');
}
#[\Override]
public function configureDashboard(): Dashboard
{
return Dashboard::new()
->setTitle('TijdVoorDeTest');
}
#[\Override]
public function configureMenuItems(): iterable
{
yield MenuItem::linkToDashboard('Dashboard', 'fa fa-home');
yield MenuItem::linkToCrud('Season', 'fas fa-list', Season::class);
yield MenuItem::linkToCrud('Quiz', 'fas fa-list', Quiz::class);
yield MenuItem::linkToCrud('Question', 'fas fa-list', Question::class);
yield MenuItem::linkToCrud('Candidate', 'fas fa-list', Candidate::class);
yield MenuItem::linkToCrud('Correction', 'fas fa-list', QuizCandidate::class);
yield MenuItem::linkToCrud('User', 'fas fa-list', User::class);
yield MenuItem::linkToCrud('Given Answer', 'fas fa-list', GivenAnswer::class);
yield MenuItem::linkToCrud('Answer', 'fas fa-list', Answer::class);
yield MenuItem::linkToLogout('Logout', 'fas fa-sign-out');
}
}

View File

@@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin;
use App\Entity\GivenAnswer;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
/** @extends AbstractCrudController<GivenAnswer> */
class GivenAnswerCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return GivenAnswer::class;
}
}

View File

@@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin;
use App\Entity\Question;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
/** @extends AbstractCrudController<Question> */
class QuestionCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return Question::class;
}
}

View File

@@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin;
use App\Entity\QuizCandidate;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
/** @extends AbstractCrudController<QuizCandidate> */
class QuizCorrectionCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return QuizCandidate::class;
}
}

View File

@@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin;
use App\Entity\Quiz;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
/** @extends AbstractCrudController<Quiz> */
class QuizCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return Quiz::class;
}
}

View File

@@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin;
use App\Entity\Season;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
/** @extends AbstractCrudController<Season> */
class SeasonCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return Season::class;
}
}

View File

@@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Controller\Admin;
use App\Entity\User;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
/** @extends AbstractCrudController<User> */
class UserCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return User::class;
}
}

View File

@@ -2,14 +2,8 @@
declare(strict_types=1);
namespace App\Controller\Backoffice;
namespace Tvdt\Controller\Backoffice;
use App\Controller\AbstractController;
use App\Entity\Season;
use App\Entity\User;
use App\Form\CreateSeasonFormType;
use App\Repository\SeasonRepository;
use App\Service\QuizSpreadsheetService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\HttpFoundation\Request;
@@ -18,6 +12,12 @@ use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Tvdt\Controller\AbstractController;
use Tvdt\Entity\Season;
use Tvdt\Entity\User;
use Tvdt\Form\CreateSeasonFormType;
use Tvdt\Repository\SeasonRepository;
use Tvdt\Service\QuizSpreadsheetService;
#[AsController]
#[IsGranted('ROLE_USER')]
@@ -28,7 +28,7 @@ final class BackofficeController extends AbstractController
private readonly Security $security,
) {}
#[Route('/backoffice/', name: 'app_backoffice_index')]
#[Route('/backoffice/', name: 'tvdt_backoffice_index')]
public function index(): Response
{
$user = $this->getUser();
@@ -43,7 +43,7 @@ final class BackofficeController extends AbstractController
]);
}
#[Route('/backoffice/season/add', name: 'app_backoffice_season_add', priority: 10)]
#[Route('/backoffice/season/add', name: 'tvdt_backoffice_season_add', priority: 10)]
public function addSeason(Request $request, EntityManagerInterface $em): Response
{
$season = new Season();
@@ -61,13 +61,13 @@ final class BackofficeController extends AbstractController
$em->persist($season);
$em->flush();
return $this->redirectToRoute('app_backoffice_season', ['seasonCode' => $season->getSeasonCode()]);
return $this->redirectToRoute('tvdt_backoffice_season', ['seasonCode' => $season->getSeasonCode()]);
}
return $this->render('backoffice/season_add.html.twig', ['form' => $form]);
}
#[Route('/backoffice/template', name: 'app_backoffice_template', priority: 10)]
#[Route('/backoffice/template', name: 'tvdt_backoffice_template', priority: 10)]
public function getTemplate(QuizSpreadsheetService $excel): Response
{
$response = new StreamedResponse($excel->generateTemplate());

View File

@@ -2,36 +2,36 @@
declare(strict_types=1);
namespace App\Controller\Backoffice;
namespace Tvdt\Controller\Backoffice;
use App\Controller\AbstractController;
use App\Entity\Elimination;
use App\Entity\Quiz;
use App\Entity\Season;
use App\Factory\EliminationFactory;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Routing\Requirement\Requirement;
use Tvdt\Controller\AbstractController;
use Tvdt\Entity\Elimination;
use Tvdt\Entity\Quiz;
use Tvdt\Entity\Season;
use Tvdt\Factory\EliminationFactory;
final class PrepareEliminationController extends AbstractController
{
#[Route(
'/backoffice/season/{seasonCode:season}/quiz/{quiz}/elimination/prepare',
name: 'app_prepare_elimination',
name: 'tvdt_prepare_elimination',
requirements: ['seasonCode' => self::SEASON_CODE_REGEX, 'quiz' => Requirement::UUID],
)]
public function index(Season $season, Quiz $quiz, EliminationFactory $eliminationFactory): Response
{
$elimination = $eliminationFactory->createEliminationFromQuiz($quiz);
return $this->redirectToRoute('app_prepare_elimination_view', ['elimination' => $elimination->getId()]);
return $this->redirectToRoute('tvdt_prepare_elimination_view', ['elimination' => $elimination->getId()]);
}
#[Route(
'/backoffice/elimination/{elimination}',
name: 'app_prepare_elimination_view',
name: 'tvdt_prepare_elimination_view',
requirements: ['elimination' => Requirement::UUID],
)]
public function viewElimination(Elimination $elimination, Request $request, EntityManagerInterface $em): Response
@@ -41,7 +41,7 @@ final class PrepareEliminationController extends AbstractController
$em->flush();
if ($request->request->getBoolean('start')) {
return $this->redirectToRoute('app_elimination', ['elimination' => $elimination->getId()]);
return $this->redirectToRoute('tvdt_elimination', ['elimination' => $elimination->getId()]);
}
$this->addFlash('success', 'Elimination updated');

View File

@@ -2,17 +2,8 @@
declare(strict_types=1);
namespace App\Controller\Backoffice;
namespace Tvdt\Controller\Backoffice;
use App\Controller\AbstractController;
use App\Entity\Candidate;
use App\Entity\Quiz;
use App\Entity\Season;
use App\Exception\ErrorClearingQuizException;
use App\Repository\CandidateRepository;
use App\Repository\QuizCandidateRepository;
use App\Repository\QuizRepository;
use App\Security\Voter\SeasonVoter;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
@@ -23,6 +14,15 @@ use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Routing\Requirement\Requirement;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Contracts\Translation\TranslatorInterface;
use Tvdt\Controller\AbstractController;
use Tvdt\Entity\Candidate;
use Tvdt\Entity\Quiz;
use Tvdt\Entity\Season;
use Tvdt\Exception\ErrorClearingQuizException;
use Tvdt\Repository\CandidateRepository;
use Tvdt\Repository\QuizCandidateRepository;
use Tvdt\Repository\QuizRepository;
use Tvdt\Security\Voter\SeasonVoter;
#[AsController]
#[IsGranted('ROLE_USER')]
@@ -33,12 +33,12 @@ class QuizController extends AbstractController
private readonly TranslatorInterface $translator,
) {}
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
#[Route(
'/backoffice/season/{seasonCode:season}/quiz/{quiz}',
name: 'app_backoffice_quiz',
name: 'tvdt_backoffice_quiz',
requirements: ['seasonCode' => self::SEASON_CODE_REGEX, 'quiz' => Requirement::UUID],
)]
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
public function index(Season $season, Quiz $quiz): Response
{
return $this->render('backoffice/quiz.html.twig', [
@@ -48,30 +48,30 @@ class QuizController extends AbstractController
]);
}
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
#[Route(
'/backoffice/season/{seasonCode:season}/quiz/{quiz}/enable',
name: 'app_backoffice_enable',
name: 'tvdt_backoffice_enable',
requirements: ['seasonCode' => self::SEASON_CODE_REGEX, 'quiz' => Requirement::UUID.'|null'],
)]
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
public function enableQuiz(Season $season, ?Quiz $quiz, EntityManagerInterface $em): RedirectResponse
{
$season->setActiveQuiz($quiz);
$em->flush();
if ($quiz instanceof Quiz) {
return $this->redirectToRoute('app_backoffice_quiz', ['seasonCode' => $season->getSeasonCode(), 'quiz' => $quiz->getId()]);
return $this->redirectToRoute('tvdt_backoffice_quiz', ['seasonCode' => $season->getSeasonCode(), 'quiz' => $quiz->getId()]);
}
return $this->redirectToRoute('app_backoffice_season', ['seasonCode' => $season->getSeasonCode()]);
return $this->redirectToRoute('tvdt_backoffice_season', ['seasonCode' => $season->getSeasonCode()]);
}
#[IsGranted(SeasonVoter::EDIT, subject: 'quiz')]
#[Route(
'/backoffice/quiz/{quiz}/clear',
name: 'app_backoffice_quiz_clear',
name: 'tvdt_backoffice_quiz_clear',
requirements: ['quiz' => Requirement::UUID],
)]
#[IsGranted(SeasonVoter::EDIT, subject: 'quiz')]
public function clearQuiz(Quiz $quiz, QuizRepository $quizRepository): RedirectResponse
{
try {
@@ -81,30 +81,30 @@ class QuizController extends AbstractController
$this->addFlash('error', $this->translator->trans('Error clearing quiz'));
}
return $this->redirectToRoute('app_backoffice_quiz', ['seasonCode' => $quiz->getSeason()->getSeasonCode(), 'quiz' => $quiz->getId()]);
return $this->redirectToRoute('tvdt_backoffice_quiz', ['seasonCode' => $quiz->getSeason()->getSeasonCode(), 'quiz' => $quiz->getId()]);
}
#[IsGranted(SeasonVoter::DELETE, subject: 'quiz')]
#[Route(
'/backoffice/quiz/{quiz}/delete',
name: 'app_backoffice_quiz_delete',
name: 'tvdt_backoffice_quiz_delete',
requirements: ['quiz' => Requirement::UUID],
)]
#[IsGranted(SeasonVoter::DELETE, subject: 'quiz')]
public function deleteQuiz(Quiz $quiz, QuizRepository $quizRepository): RedirectResponse
{
$quizRepository->deleteQuiz($quiz);
$this->addFlash('success', $this->translator->trans('Quiz deleted'));
return $this->redirectToRoute('app_backoffice_season', ['seasonCode' => $quiz->getSeason()->getSeasonCode()]);
return $this->redirectToRoute('tvdt_backoffice_season', ['seasonCode' => $quiz->getSeason()->getSeasonCode()]);
}
#[IsGranted(SeasonVoter::EDIT, subject: 'quiz')]
#[Route(
'/backoffice/quiz/{quiz}/candidate/{candidate}/modify_correction',
name: 'app_backoffice_modify_correction',
name: 'tvdt_backoffice_modify_correction',
requirements: ['quiz' => Requirement::UUID, 'candidate' => Requirement::UUID],
)]
#[IsGranted(SeasonVoter::EDIT, subject: 'quiz')]
public function modifyCorrection(Quiz $quiz, Candidate $candidate, QuizCandidateRepository $quizCandidateRepository, Request $request): RedirectResponse
{
if (!$request->isMethod('POST')) {
@@ -115,6 +115,6 @@ class QuizController extends AbstractController
$quizCandidateRepository->setCorrectionsForCandidate($quiz, $candidate, $corrections);
return $this->redirectToRoute('app_backoffice_quiz', ['seasonCode' => $quiz->getSeason()->getSeasonCode(), 'quiz' => $quiz->getId()]);
return $this->redirectToRoute('tvdt_backoffice_quiz', ['seasonCode' => $quiz->getSeason()->getSeasonCode(), 'quiz' => $quiz->getId()]);
}
}

View File

@@ -2,18 +2,8 @@
declare(strict_types=1);
namespace App\Controller\Backoffice;
namespace Tvdt\Controller\Backoffice;
use App\Controller\AbstractController;
use App\Entity\Candidate;
use App\Entity\Quiz;
use App\Entity\Season;
use App\Enum\FlashType;
use App\Form\AddCandidatesFormType;
use App\Form\SettingsForm;
use App\Form\UploadQuizFormType;
use App\Security\Voter\SeasonVoter;
use App\Service\QuizSpreadsheetService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request;
@@ -22,6 +12,16 @@ use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Contracts\Translation\TranslatorInterface;
use Tvdt\Controller\AbstractController;
use Tvdt\Entity\Candidate;
use Tvdt\Entity\Quiz;
use Tvdt\Entity\Season;
use Tvdt\Enum\FlashType;
use Tvdt\Form\AddCandidatesFormType;
use Tvdt\Form\SettingsForm;
use Tvdt\Form\UploadQuizFormType;
use Tvdt\Security\Voter\SeasonVoter;
use Tvdt\Service\QuizSpreadsheetService;
#[AsController]
#[IsGranted('ROLE_USER')]
@@ -32,12 +32,12 @@ class SeasonController extends AbstractController
private readonly EntityManagerInterface $em,
) {}
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
#[Route(
'/backoffice/season/{seasonCode:season}',
name: 'app_backoffice_season',
name: 'tvdt_backoffice_season',
requirements: ['seasonCode' => self::SEASON_CODE_REGEX],
)]
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
public function index(Season $season, Request $request): Response
{
$form = $this->createForm(SettingsForm::class, $season->getSettings());
@@ -54,13 +54,13 @@ class SeasonController extends AbstractController
]);
}
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
#[Route(
'/backoffice/season/{seasonCode:season}/add-candidate',
name: 'app_backoffice_add_candidates',
name: 'tvdt_backoffice_add_candidates',
requirements: ['seasonCode' => self::SEASON_CODE_REGEX],
priority: 10,
)]
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
public function addCandidates(Season $season, Request $request): Response
{
$form = $this->createForm(AddCandidatesFormType::class);
@@ -74,19 +74,19 @@ class SeasonController extends AbstractController
$this->em->flush();
return $this->redirectToRoute('app_backoffice_season', ['seasonCode' => $season->getSeasonCode()]);
return $this->redirectToRoute('tvdt_backoffice_season', ['seasonCode' => $season->getSeasonCode()]);
}
return $this->render('backoffice/season_add_candidates.html.twig', ['form' => $form]);
}
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
#[Route(
'/backoffice/season/{seasonCode:season}/add-quiz',
name: 'app_backoffice_quiz_add',
name: 'tvdt_backoffice_quiz_add',
requirements: ['seasonCode' => self::SEASON_CODE_REGEX],
priority: 10,
)]
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
public function addQuiz(Request $request, Season $season, QuizSpreadsheetService $quizSpreadsheet): Response
{
$quiz = new Quiz();
@@ -106,7 +106,7 @@ class SeasonController extends AbstractController
$this->addFlash(FlashType::Success, $this->translator->trans('Quiz Added!'));
return $this->redirectToRoute('app_backoffice_season', ['seasonCode' => $season->getSeasonCode()]);
return $this->redirectToRoute('tvdt_backoffice_season', ['seasonCode' => $season->getSeasonCode()]);
}
return $this->render('/backoffice/quiz_add.html.twig', ['form' => $form, 'season' => $season]);

View File

@@ -2,15 +2,8 @@
declare(strict_types=1);
namespace App\Controller;
namespace Tvdt\Controller;
use App\Entity\Candidate;
use App\Entity\Elimination;
use App\Enum\FlashType;
use App\Form\EliminationEnterNameType;
use App\Helpers\Base64;
use App\Repository\CandidateRepository;
use App\Security\Voter\SeasonVoter;
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
@@ -19,6 +12,13 @@ use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Routing\Requirement\Requirement;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Contracts\Translation\TranslatorInterface;
use Tvdt\Entity\Candidate;
use Tvdt\Entity\Elimination;
use Tvdt\Enum\FlashType;
use Tvdt\Form\EliminationEnterNameType;
use Tvdt\Helpers\Base64;
use Tvdt\Repository\CandidateRepository;
use Tvdt\Security\Voter\SeasonVoter;
use function Symfony\Component\Translation\t;
@@ -28,8 +28,8 @@ final class EliminationController extends AbstractController
{
public function __construct(private readonly TranslatorInterface $translator) {}
#[Route('/elimination/{elimination}', name: 'app_elimination', requirements: ['elimination' => Requirement::UUID])]
#[IsGranted(SeasonVoter::ELIMINATION, 'elimination')]
#[Route('/elimination/{elimination}', name: 'tvdt_elimination', requirements: ['elimination' => Requirement::UUID])]
public function index(#[MapEntity] Elimination $elimination, Request $request): Response
{
$form = $this->createForm(EliminationEnterNameType::class);
@@ -39,7 +39,7 @@ final class EliminationController extends AbstractController
if ($form->isSubmitted() && $form->isValid()) {
$name = $form->get('name')->getData();
return $this->redirectToRoute('app_elimination_candidate', ['elimination' => $elimination->getId(), 'candidateHash' => Base64::base64UrlEncode($name)]);
return $this->redirectToRoute('tvdt_elimination_candidate', ['elimination' => $elimination->getId(), 'candidateHash' => Base64::base64UrlEncode($name)]);
}
return $this->render('quiz/elimination/index.html.twig', [
@@ -48,8 +48,8 @@ final class EliminationController extends AbstractController
]);
}
#[Route('/elimination/{elimination}/{candidateHash}', name: 'app_elimination_candidate', requirements: ['elimination' => Requirement::UUID, 'candidateHash' => self::CANDIDATE_HASH_REGEX])]
#[IsGranted(SeasonVoter::ELIMINATION, 'elimination')]
#[Route('/elimination/{elimination}/{candidateHash}', name: 'tvdt_elimination_candidate', requirements: ['elimination' => Requirement::UUID, 'candidateHash' => self::CANDIDATE_HASH_REGEX])]
public function candidateScreen(Elimination $elimination, string $candidateHash, CandidateRepository $candidateRepository): Response
{
$candidate = $candidateRepository->getCandidateByHash($elimination->getQuiz()->getSeason(), $candidateHash);
@@ -58,7 +58,7 @@ final class EliminationController extends AbstractController
t('Cound not find candidate with name %name%', ['%name%' => Base64::base64UrlDecode($candidateHash)])->trans($this->translator),
);
return $this->redirectToRoute('app_elimination', ['elimination' => $elimination->getId()]);
return $this->redirectToRoute('tvdt_elimination', ['elimination' => $elimination->getId()]);
}
$screenColour = $elimination->getScreenColour($candidate->getName());
@@ -66,7 +66,7 @@ final class EliminationController extends AbstractController
if (null === $screenColour) {
$this->addFlash(FlashType::Warning, $this->translator->trans('Cound not find candidate with name %name% in elimination.', ['%name%' => $candidate->getName()]));
return $this->redirectToRoute('app_elimination', ['elimination' => $elimination->getId()]);
return $this->redirectToRoute('tvdt_elimination', ['elimination' => $elimination->getId()]);
}
return $this->render('quiz/elimination/candidate.html.twig', [

View File

@@ -2,20 +2,20 @@
declare(strict_types=1);
namespace App\Controller;
namespace Tvdt\Controller;
use App\Enum\FlashType;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
use Symfony\Contracts\Translation\TranslatorInterface;
use Tvdt\Enum\FlashType;
#[AsController]
final class LoginController extends AbstractController
{
#[Route(path: '/login', name: 'app_login_login')]
#[Route(path: '/login', name: 'tvdt_login_login')]
public function login(AuthenticationUtils $authenticationUtils, TranslatorInterface $translator): Response
{
// get the login error if there is one
@@ -34,7 +34,7 @@ final class LoginController extends AbstractController
]);
}
#[Route(path: '/logout', name: 'app_login_logout')]
#[Route(path: '/logout', name: 'tvdt_login_logout')]
public function logout(): never
{
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');

View File

@@ -2,37 +2,37 @@
declare(strict_types=1);
namespace App\Controller;
namespace Tvdt\Controller;
use App\Entity\Answer;
use App\Entity\Candidate;
use App\Entity\GivenAnswer;
use App\Entity\Question;
use App\Entity\Quiz;
use App\Entity\Season;
use App\Enum\FlashType;
use App\Form\EnterNameType;
use App\Form\SelectSeasonType;
use App\Helpers\Base64;
use App\Repository\AnswerRepository;
use App\Repository\CandidateRepository;
use App\Repository\GivenAnswerRepository;
use App\Repository\QuestionRepository;
use App\Repository\QuizCandidateRepository;
use App\Repository\SeasonRepository;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Contracts\Translation\TranslatorInterface;
use Tvdt\Entity\Answer;
use Tvdt\Entity\Candidate;
use Tvdt\Entity\GivenAnswer;
use Tvdt\Entity\Question;
use Tvdt\Entity\Quiz;
use Tvdt\Entity\Season;
use Tvdt\Enum\FlashType;
use Tvdt\Form\EnterNameType;
use Tvdt\Form\SelectSeasonType;
use Tvdt\Helpers\Base64;
use Tvdt\Repository\AnswerRepository;
use Tvdt\Repository\CandidateRepository;
use Tvdt\Repository\GivenAnswerRepository;
use Tvdt\Repository\QuestionRepository;
use Tvdt\Repository\QuizCandidateRepository;
use Tvdt\Repository\SeasonRepository;
#[AsController]
final class QuizController extends AbstractController
{
public function __construct(private readonly TranslatorInterface $translator) {}
#[Route(path: '/', name: 'app_quiz_select_season', methods: ['GET', 'POST'])]
#[Route(path: '/', name: 'tvdt_quiz_select_season', methods: ['GET', 'POST'])]
public function selectSeason(Request $request, SeasonRepository $seasonRepository): Response
{
$form = $this->createForm(SelectSeasonType::class);
@@ -44,16 +44,16 @@ final class QuizController extends AbstractController
if ([] === $seasonRepository->findBy(['seasonCode' => $seasonCode])) {
$this->addFlash(FlashType::Warning, $this->translator->trans('Invalid season code'));
return $this->redirectToRoute('app_quiz_select_season');
return $this->redirectToRoute('tvdt_quiz_select_season');
}
return $this->redirectToRoute('app_quiz_enter_name', ['seasonCode' => $seasonCode]);
return $this->redirectToRoute('tvdt_quiz_enter_name', ['seasonCode' => $seasonCode]);
}
return $this->render('quiz/select_season.html.twig', ['form' => $form]);
}
#[Route(path: '/{seasonCode:season}', name: 'app_quiz_enter_name', requirements: ['seasonCode' => self::SEASON_CODE_REGEX])]
#[Route(path: '/{seasonCode:season}', name: 'tvdt_quiz_enter_name', requirements: ['seasonCode' => self::SEASON_CODE_REGEX])]
public function enterName(
Request $request,
Season $season,
@@ -65,7 +65,7 @@ final class QuizController extends AbstractController
if ($form->isSubmitted() && $form->isValid()) {
$name = $form->get('name')->getData();
return $this->redirectToRoute('app_quiz_quiz_page', ['seasonCode' => $season->getSeasonCode(), 'nameHash' => Base64::base64UrlEncode($name)]);
return $this->redirectToRoute('tvdt_quiz_quiz_page', ['seasonCode' => $season->getSeasonCode(), 'nameHash' => Base64::base64UrlEncode($name)]);
}
return $this->render('quiz/enter_name.twig', ['season' => $season, 'form' => $form]);
@@ -73,7 +73,7 @@ final class QuizController extends AbstractController
#[Route(
path: '/{seasonCode:season}/{nameHash}',
name: 'app_quiz_quiz_page',
name: 'tvdt_quiz_quiz_page',
requirements: ['seasonCode' => self::SEASON_CODE_REGEX, 'nameHash' => self::CANDIDATE_HASH_REGEX],
)]
public function quizPage(
@@ -91,7 +91,7 @@ final class QuizController extends AbstractController
if (!$candidate instanceof Candidate) {
$this->addFlash(FlashType::Danger, $this->translator->trans('Candidate not found'));
return $this->redirectToRoute('app_quiz_enter_name', ['seasonCode' => $season->getSeasonCode()]);
return $this->redirectToRoute('tvdt_quiz_enter_name', ['seasonCode' => $season->getSeasonCode()]);
}
$quiz = $season->getActiveQuiz();
@@ -99,7 +99,7 @@ final class QuizController extends AbstractController
if (!$quiz instanceof Quiz) {
$this->addFlash(FlashType::Warning, $this->translator->trans('There is no active quiz'));
return $this->redirectToRoute('app_quiz_enter_name', ['seasonCode' => $season->getSeasonCode()]);
return $this->redirectToRoute('tvdt_quiz_enter_name', ['seasonCode' => $season->getSeasonCode()]);
}
if ('POST' === $request->getMethod()) {
@@ -112,7 +112,7 @@ final class QuizController extends AbstractController
$givenAnswer = new GivenAnswer($candidate, $answer->getQuestion()->getQuiz(), $answer);
$givenAnswerRepository->save($givenAnswer);
return $this->redirectToRoute('app_quiz_quiz_page', ['seasonCode' => $season->getSeasonCode(), 'nameHash' => $nameHash]);
return $this->redirectToRoute('tvdt_quiz_quiz_page', ['seasonCode' => $season->getSeasonCode(), 'nameHash' => $nameHash]);
}
$question = $questionRepository->findNextQuestionForCandidate($candidate);
@@ -120,7 +120,7 @@ final class QuizController extends AbstractController
if (!$question instanceof Question) {
$this->addFlash(FlashType::Success, $this->translator->trans('Quiz completed'));
return $this->redirectToRoute('app_quiz_enter_name', ['seasonCode' => $season->getSeasonCode()]);
return $this->redirectToRoute('tvdt_quiz_enter_name', ['seasonCode' => $season->getSeasonCode()]);
}
$quizCandidateRepository->createIfNotExist($quiz, $candidate);

View File

@@ -2,12 +2,8 @@
declare(strict_types=1);
namespace App\Controller;
namespace Tvdt\Controller;
use App\Entity\User;
use App\Form\RegistrationFormType;
use App\Repository\UserRepository;
use App\Security\EmailVerifier;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
@@ -20,12 +16,16 @@ use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Contracts\Translation\TranslatorInterface;
use SymfonyCasts\Bundle\VerifyEmail\Exception\VerifyEmailExceptionInterface;
use Tvdt\Entity\User;
use Tvdt\Form\RegistrationFormType;
use Tvdt\Repository\UserRepository;
use Tvdt\Security\EmailVerifier;
final class RegistrationController extends AbstractController
{
public function __construct(private readonly EmailVerifier $emailVerifier, private readonly TranslatorInterface $translator) {}
#[Route('/register', name: 'app_register')]
#[Route('/register', name: 'tvdt_register')]
public function register(
Request $request,
UserPasswordHasherInterface $userPasswordHasher,
@@ -48,7 +48,7 @@ final class RegistrationController extends AbstractController
try {
// generate a signed url and email it to the user
$this->emailVerifier->sendEmailConfirmation('app_verify_email', $user,
$this->emailVerifier->sendEmailConfirmation('tvdt_verify_email', $user,
new TemplatedEmail()
->to((string) $user->getEmail())
->subject($this->translator->trans('Please Confirm your Email'))
@@ -69,19 +69,19 @@ final class RegistrationController extends AbstractController
]);
}
#[Route('/verify/email', name: 'app_verify_email')]
#[Route('/verify/email', name: 'tvdt_verify_email')]
public function verifyUserEmail(Request $request, TranslatorInterface $translator, UserRepository $userRepository): Response
{
$id = $request->query->get('id');
if (null === $id) {
return $this->redirectToRoute('app_register');
return $this->redirectToRoute('tvdt_register');
}
$user = $userRepository->find($id);
if (null === $user) {
return $this->redirectToRoute('app_register');
return $this->redirectToRoute('tvdt_register');
}
// validate email confirmation link, sets User::isVerified=true and persists
@@ -90,11 +90,11 @@ final class RegistrationController extends AbstractController
} catch (VerifyEmailExceptionInterface $verifyEmailException) {
$this->addFlash('verify_email_error', $translator->trans($verifyEmailException->getReason(), [], 'VerifyEmailBundle'));
return $this->redirectToRoute('app_register');
return $this->redirectToRoute('tvdt_register');
}
$this->addFlash('success', $this->translator->trans('Your email address has been verified.'));
return $this->redirectToRoute('app_backoffice_index');
return $this->redirectToRoute('tvdt_backoffice_index');
}
}

View File

@@ -2,15 +2,15 @@
declare(strict_types=1);
namespace App\DataFixtures;
namespace Tvdt\DataFixtures;
use App\Entity\Answer;
use App\Entity\Candidate;
use App\Entity\Question;
use App\Entity\Quiz;
use App\Entity\Season;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
use Tvdt\Entity\Answer;
use Tvdt\Entity\Candidate;
use Tvdt\Entity\Question;
use Tvdt\Entity\Quiz;
use Tvdt\Entity\Season;
class KrtekFixtures extends Fixture
{

View File

@@ -2,9 +2,8 @@
declare(strict_types=1);
namespace App\Entity;
namespace Tvdt\Entity;
use App\Repository\AnswerRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
@@ -12,21 +11,22 @@ use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
use Tvdt\Repository\AnswerRepository;
#[ORM\Entity(repositoryClass: AnswerRepository::class)]
class Answer
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\Id]
private Uuid $id;
#[ORM\Column(type: Types::SMALLINT, options: ['default' => 0])]
private int $ordering = 0;
#[ORM\ManyToOne(inversedBy: 'answers')]
#[ORM\JoinColumn(nullable: false)]
#[ORM\ManyToOne(inversedBy: 'answers')]
private Question $question;
/** @var Collection<int, Candidate> */

View File

@@ -2,29 +2,29 @@
declare(strict_types=1);
namespace App\Entity;
namespace Tvdt\Entity;
use App\Helpers\Base64;
use App\Repository\CandidateRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
use Tvdt\Helpers\Base64;
use Tvdt\Repository\CandidateRepository;
#[ORM\Entity(repositoryClass: CandidateRepository::class)]
#[ORM\UniqueConstraint(fields: ['name', 'season'])]
class Candidate
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\Id]
private Uuid $id;
#[ORM\ManyToOne(inversedBy: 'candidates')]
#[ORM\JoinColumn(nullable: false)]
#[ORM\ManyToOne(inversedBy: 'candidates')]
private Season $season;
/** @var Collection<int, Answer> */

View File

@@ -2,9 +2,8 @@
declare(strict_types=1);
namespace App\Entity;
namespace Tvdt\Entity;
use App\Repository\EliminationRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Safe\DateTimeImmutable;
@@ -12,6 +11,7 @@ use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\HttpFoundation\InputBag;
use Symfony\Component\Uid\Uuid;
use Tvdt\Repository\EliminationRepository;
#[ORM\Entity(repositoryClass: EliminationRepository::class)]
#[ORM\HasLifecycleCallbacks]
@@ -21,10 +21,10 @@ class Elimination
public const string SCREEN_RED = 'red';
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\Id]
private Uuid $id;
/** @var array<string, mixed> */
@@ -35,8 +35,8 @@ class Elimination
private \DateTimeImmutable $created;
public function __construct(
#[ORM\ManyToOne(inversedBy: 'eliminations')]
#[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
#[ORM\ManyToOne(inversedBy: 'eliminations')]
private Quiz $quiz,
) {}

View File

@@ -2,40 +2,40 @@
declare(strict_types=1);
namespace App\Entity;
namespace Tvdt\Entity;
use App\Repository\GivenAnswerRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Safe\DateTimeImmutable;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
use Tvdt\Repository\GivenAnswerRepository;
#[ORM\Entity(repositoryClass: GivenAnswerRepository::class)]
#[ORM\HasLifecycleCallbacks]
class GivenAnswer
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\Id]
private Uuid $id;
#[ORM\Column(type: Types::DATETIMETZ_IMMUTABLE, nullable: false)]
private \DateTimeImmutable $created;
public function __construct(
#[ORM\ManyToOne(inversedBy: 'givenAnswers')]
#[ORM\JoinColumn(nullable: false)]
#[ORM\ManyToOne(inversedBy: 'givenAnswers')]
private Candidate $candidate,
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
#[ORM\ManyToOne]
private Quiz $quiz,
#[ORM\ManyToOne(inversedBy: 'givenAnswers')]
#[ORM\JoinColumn(nullable: false)]
#[ORM\ManyToOne(inversedBy: 'givenAnswers')]
private Answer $answer,
) {}

View File

@@ -2,9 +2,8 @@
declare(strict_types=1);
namespace App\Entity;
namespace Tvdt\Entity;
use App\Repository\QuestionRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
@@ -12,14 +11,15 @@ use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
use Tvdt\Repository\QuestionRepository;
#[ORM\Entity(repositoryClass: QuestionRepository::class)]
class Question
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\Id]
private Uuid $id;
#[ORM\Column(type: Types::SMALLINT, options: ['default' => 0])]
@@ -28,8 +28,8 @@ class Question
#[ORM\Column(type: Types::STRING, length: 255)]
private string $question;
#[ORM\ManyToOne(inversedBy: 'questions')]
#[ORM\JoinColumn(nullable: false)]
#[ORM\ManyToOne(inversedBy: 'questions')]
private Quiz $quiz;
#[ORM\Column]

View File

@@ -2,31 +2,31 @@
declare(strict_types=1);
namespace App\Entity;
namespace Tvdt\Entity;
use App\Repository\QuizRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
use Tvdt\Repository\QuizRepository;
#[ORM\Entity(repositoryClass: QuizRepository::class)]
#[ORM\UniqueConstraint(fields: ['name', 'season'])]
class Quiz
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\Id]
private Uuid $id;
#[ORM\Column(length: 64)]
private string $name;
#[ORM\ManyToOne(inversedBy: 'quizzes')]
#[ORM\JoinColumn(nullable: false)]
#[ORM\ManyToOne(inversedBy: 'quizzes')]
private Season $season;
/** @var Collection<int, Question> */

View File

@@ -2,25 +2,25 @@
declare(strict_types=1);
namespace App\Entity;
namespace Tvdt\Entity;
use App\Repository\QuizCandidateRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Safe\DateTimeImmutable;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
use Tvdt\Repository\QuizCandidateRepository;
#[ORM\Entity(repositoryClass: QuizCandidateRepository::class)]
#[ORM\UniqueConstraint(columns: ['candidate_id', 'quiz_id'])]
#[ORM\HasLifecycleCallbacks]
#[ORM\UniqueConstraint(columns: ['candidate_id', 'quiz_id'])]
class QuizCandidate
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\Id]
private Uuid $id;
#[ORM\Column]
@@ -30,12 +30,12 @@ class QuizCandidate
private \DateTimeImmutable $created;
public function __construct(
#[ORM\ManyToOne(inversedBy: 'candidateData')]
#[ORM\JoinColumn(nullable: false)]
#[ORM\ManyToOne(inversedBy: 'candidateData')]
private Quiz $quiz,
#[ORM\ManyToOne(inversedBy: 'quizData')]
#[ORM\JoinColumn(nullable: false)]
#[ORM\ManyToOne(inversedBy: 'quizData')]
private Candidate $candidate,
) {}

View File

@@ -2,25 +2,25 @@
declare(strict_types=1);
namespace App\Entity;
namespace Tvdt\Entity;
use App\Repository\SeasonRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
use Tvdt\Repository\SeasonRepository;
#[ORM\Entity(repositoryClass: SeasonRepository::class)]
class Season
{
private const string SEASON_CODE_CHARACTERS = 'bcdfghjklmnpqrstvwxz';
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\Id]
private Uuid $id;
#[ORM\Column(length: 64)]
@@ -42,12 +42,12 @@ class Season
#[ORM\ManyToMany(targetEntity: User::class, inversedBy: 'seasons')]
private Collection $owners;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: true, onDelete: 'SET NULL')]
#[ORM\ManyToOne]
private ?Quiz $ActiveQuiz = null;
#[ORM\OneToOne(cascade: ['persist', 'remove'])]
#[ORM\JoinColumn(nullable: true)]
#[ORM\OneToOne(cascade: ['persist', 'remove'])]
private ?SeasonSettings $settings = null;
public function __construct()

View File

@@ -2,22 +2,22 @@
declare(strict_types=1);
namespace App\Entity;
namespace Tvdt\Entity;
use App\Repository\SeasonSettingsRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
use Tvdt\Repository\SeasonSettingsRepository;
#[ORM\Entity(repositoryClass: SeasonSettingsRepository::class)]
class SeasonSettings
{
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\Column(type: UuidType::NAME)]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\Id]
private Uuid $id;
#[ORM\Column(type: Types::BOOLEAN, options: ['default' => false])]

View File

@@ -2,9 +2,8 @@
declare(strict_types=1);
namespace App\Entity;
namespace Tvdt\Entity;
use App\Repository\UserRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
@@ -15,6 +14,7 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Uid\Uuid;
use Tvdt\Repository\UserRepository;
#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\Table(name: '`user`')]
@@ -22,10 +22,10 @@ use Symfony\Component\Uid\Uuid;
#[UniqueEntity(fields: ['email'], message: 'There is already an account with this email')]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\Id]
private Uuid $id;
#[ORM\Column(length: 180)]

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace App\Enum;
namespace Tvdt\Enum;
enum FlashType: string
{

View File

@@ -2,6 +2,6 @@
declare(strict_types=1);
namespace App\Exception;
namespace Tvdt\Exception;
class ErrorClearingQuizException extends \Exception {}

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace App\Exception;
namespace Tvdt\Exception;
class SpreadsheetDataException extends SpreadsheetException
{

View File

@@ -2,6 +2,6 @@
declare(strict_types=1);
namespace App\Exception;
namespace Tvdt\Exception;
class SpreadsheetException extends \Exception {}

View File

@@ -2,12 +2,12 @@
declare(strict_types=1);
namespace App\Factory;
namespace Tvdt\Factory;
use App\Entity\Elimination;
use App\Entity\Quiz;
use App\Repository\CandidateRepository;
use Doctrine\ORM\EntityManagerInterface;
use Tvdt\Entity\Elimination;
use Tvdt\Entity\Quiz;
use Tvdt\Repository\CandidateRepository;
final readonly class EliminationFactory
{

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace App\Form;
namespace Tvdt\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;

View File

@@ -2,14 +2,14 @@
declare(strict_types=1);
namespace App\Form;
namespace Tvdt\Form;
use App\Entity\Season;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Contracts\Translation\TranslatorInterface;
use Tvdt\Entity\Season;
/** @extends AbstractType<Season> */
class CreateSeasonFormType extends AbstractType

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace App\Form;
namespace Tvdt\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace App\Form;
namespace Tvdt\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;

View File

@@ -2,9 +2,8 @@
declare(strict_types=1);
namespace App\Form;
namespace Tvdt\Form;
use App\Entity\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
@@ -14,6 +13,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Contracts\Translation\TranslatorInterface;
use Tvdt\Entity\User;
/**
* @extends AbstractType<User>

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace App\Form;
namespace Tvdt\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;

View File

@@ -2,13 +2,13 @@
declare(strict_types=1);
namespace App\Form;
namespace Tvdt\Form;
use App\Entity\SeasonSettings;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Tvdt\Entity\SeasonSettings;
/** @extends AbstractType<SeasonSettings> */
class SettingsForm extends AbstractType

View File

@@ -2,9 +2,8 @@
declare(strict_types=1);
namespace App\Form;
namespace Tvdt\Form;
use App\Entity\Quiz;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
@@ -12,6 +11,7 @@ use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\File;
use Symfony\Contracts\Translation\TranslatorInterface;
use Tvdt\Entity\Quiz;
/** @extends AbstractType<Quiz> */
class UploadQuizFormType extends AbstractType

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace App\Helpers;
namespace Tvdt\Helpers;
use Safe\Exceptions\UrlException;

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace App;
namespace Tvdt;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;

View File

@@ -2,11 +2,11 @@
declare(strict_types=1);
namespace App\Repository;
namespace Tvdt\Repository;
use App\Entity\Answer;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use Tvdt\Entity\Answer;
/**
* @extends ServiceEntityRepository<Answer>

View File

@@ -2,16 +2,16 @@
declare(strict_types=1);
namespace App\Repository;
namespace Tvdt\Repository;
use App\Entity\Candidate;
use App\Entity\Quiz;
use App\Entity\Season;
use App\Helpers\Base64;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use Safe\Exceptions\UrlException;
use Symfony\Component\Uid\Uuid;
use Tvdt\Entity\Candidate;
use Tvdt\Entity\Quiz;
use Tvdt\Entity\Season;
use Tvdt\Helpers\Base64;
/**
* @extends ServiceEntityRepository<Candidate>
@@ -35,7 +35,7 @@ class CandidateRepository extends ServiceEntityRepository
}
return $this->getEntityManager()->createQuery(<<<DQL
select c from App\Entity\Candidate c
select c from Tvdt\Entity\Candidate c
where c.season = :season
and lower(c.name) = lower(:name)
DQL
@@ -60,11 +60,11 @@ class CandidateRepository extends ServiceEntityRepository
select
c.id,
c.name,
sum(case when a.isRightAnswer = true then 1 else 0 end) as correct,
count(case when a.isRightAnswer = true then 1 else null end) as correct,
qc.corrections,
max(ga.created) - qc.created as time,
(sum(case when a.isRightAnswer = true then 1 else 0 end) + qc.corrections) as score
from App\Entity\Candidate c
(count(case when a.isRightAnswer = true then 1 else null end) + qc.corrections) as score
from Tvdt\Entity\Candidate c
join c.givenAnswers ga
join ga.answer a
join c.quizData qc

View File

@@ -2,11 +2,11 @@
declare(strict_types=1);
namespace App\Repository;
namespace Tvdt\Repository;
use App\Entity\Elimination;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use Tvdt\Entity\Elimination;
/**
* @extends ServiceEntityRepository<Elimination>

View File

@@ -2,11 +2,11 @@
declare(strict_types=1);
namespace App\Repository;
namespace Tvdt\Repository;
use App\Entity\GivenAnswer;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use Tvdt\Entity\GivenAnswer;
/**
* @extends ServiceEntityRepository<GivenAnswer>

View File

@@ -2,12 +2,12 @@
declare(strict_types=1);
namespace App\Repository;
namespace Tvdt\Repository;
use App\Entity\Candidate;
use App\Entity\Question;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use Tvdt\Entity\Candidate;
use Tvdt\Entity\Question;
/**
* @extends ServiceEntityRepository<Question>
@@ -22,10 +22,10 @@ class QuestionRepository extends ServiceEntityRepository
public function findNextQuestionForCandidate(Candidate $candidate): ?Question
{
return $this->getEntityManager()->createQuery(<<<DQL
select q from App\Entity\Question q
select q from Tvdt\Entity\Question q
join q.quiz qz
where q.id not in (
select q1.id from App\Entity\GivenAnswer ga
select q1.id from Tvdt\Entity\GivenAnswer ga
join ga.answer a
join a.question q1
where ga.candidate = :candidate

View File

@@ -2,13 +2,13 @@
declare(strict_types=1);
namespace App\Repository;
namespace Tvdt\Repository;
use App\Entity\Candidate;
use App\Entity\Quiz;
use App\Entity\QuizCandidate;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use Tvdt\Entity\Candidate;
use Tvdt\Entity\Quiz;
use Tvdt\Entity\QuizCandidate;
/**
* @extends ServiceEntityRepository<QuizCandidate>

View File

@@ -2,16 +2,16 @@
declare(strict_types=1);
namespace App\Repository;
namespace Tvdt\Repository;
use App\Entity\Elimination;
use App\Entity\GivenAnswer;
use App\Entity\Quiz;
use App\Entity\QuizCandidate;
use App\Exception\ErrorClearingQuizException;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use Psr\Log\LoggerInterface;
use Tvdt\Entity\Elimination;
use Tvdt\Entity\GivenAnswer;
use Tvdt\Entity\Quiz;
use Tvdt\Entity\QuizCandidate;
use Tvdt\Exception\ErrorClearingQuizException;
/**
* @extends ServiceEntityRepository<Quiz>

View File

@@ -2,12 +2,12 @@
declare(strict_types=1);
namespace App\Repository;
namespace Tvdt\Repository;
use App\Entity\Season;
use App\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use Tvdt\Entity\Season;
use Tvdt\Entity\User;
/**
* @extends ServiceEntityRepository<Season>
@@ -23,7 +23,7 @@ class SeasonRepository extends ServiceEntityRepository
public function getSeasonsForUser(User $user): array
{
return $this->getEntityManager()->createQuery(<<<DQL
select s from App\Entity\Season s where :user member of s.owners order by s.name
select s from Tvdt\Entity\Season s where :user member of s.owners order by s.name
DQL
)->setParameter('user', $user)->getResult();
}

View File

@@ -2,11 +2,11 @@
declare(strict_types=1);
namespace App\Repository;
namespace Tvdt\Repository;
use App\Entity\SeasonSettings;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use Tvdt\Entity\SeasonSettings;
/**
* @extends ServiceEntityRepository<SeasonSettings>

View File

@@ -2,13 +2,13 @@
declare(strict_types=1);
namespace App\Repository;
namespace Tvdt\Repository;
use App\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;
use Tvdt\Entity\User;
/** @extends ServiceEntityRepository<User> */
class UserRepository extends ServiceEntityRepository implements PasswordUpgraderInterface

View File

@@ -2,15 +2,15 @@
declare(strict_types=1);
namespace App\Security;
namespace Tvdt\Security;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
use Symfony\Component\Mailer\MailerInterface;
use SymfonyCasts\Bundle\VerifyEmail\VerifyEmailHelperInterface;
use Tvdt\Entity\User;
readonly class EmailVerifier
{

View File

@@ -2,18 +2,18 @@
declare(strict_types=1);
namespace App\Security\Voter;
namespace Tvdt\Security\Voter;
use App\Entity\Answer;
use App\Entity\Candidate;
use App\Entity\Elimination;
use App\Entity\Question;
use App\Entity\Quiz;
use App\Entity\Season;
use App\Entity\User;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Vote;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Tvdt\Entity\Answer;
use Tvdt\Entity\Candidate;
use Tvdt\Entity\Elimination;
use Tvdt\Entity\Question;
use Tvdt\Entity\Quiz;
use Tvdt\Entity\Season;
use Tvdt\Entity\User;
/** @extends Voter<string, Season> */
final class SeasonVoter extends Voter

View File

@@ -2,9 +2,9 @@
declare(strict_types=1);
namespace App\Service;
namespace Tvdt\Service;
use App\Repository\CandidateRepository;
use Tvdt\Repository\CandidateRepository;
/**
* @phpstan-import-type ResultList from CandidateRepository

View File

@@ -2,16 +2,16 @@
declare(strict_types=1);
namespace App\Service;
namespace Tvdt\Service;
use App\Entity\Answer;
use App\Entity\Question;
use App\Entity\Quiz;
use App\Exception\SpreadsheetDataException;
use PhpOffice\PhpSpreadsheet\Reader;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer;
use Symfony\Component\HttpFoundation\File\File;
use Tvdt\Entity\Answer;
use Tvdt\Entity\Question;
use Tvdt\Entity\Quiz;
use Tvdt\Exception\SpreadsheetDataException;
class QuizSpreadsheetService
{

View File

@@ -47,15 +47,6 @@
"migrations/.gitignore"
]
},
"easycorp/easyadmin-bundle": {
"version": "4.23",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "3.0",
"ref": "b131e6cbfe1b898a508987851963fff485986285"
}
},
"friendsofphp/php-cs-fixer": {
"version": "3.65",
"recipe": {
@@ -121,6 +112,15 @@
"importmap.php"
]
},
"symfony/brevo-mailer": {
"version": "7.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "6.4",
"ref": "7c1038ceb733175f610a913a885a7c8b552b703a"
}
},
"symfony/console": {
"version": "7.2",
"recipe": {
@@ -267,12 +267,12 @@
]
},
"symfony/translation": {
"version": "7.2",
"version": "7.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "6.3",
"ref": "e28e27f53663cc34f0be2837aba18e3a1bef8e7b"
"ref": "620a1b84865ceb2ba304c8f8bf2a185fbf32a843"
},
"files": [
"config/packages/translation.yaml",
@@ -310,20 +310,8 @@
"ref": "c85ff94da66841d7ff087c19cbcd97a2df744ef9"
}
},
"symfony/ux-twig-component": {
"version": "2.22",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "2.13",
"ref": "67814b5f9794798b885cec9d3f48631424449a01"
},
"files": [
"config/packages/twig_component.yaml"
]
},
"symfony/validator": {
"version": "7.2",
"version": "7.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",

View File

@@ -7,7 +7,7 @@
<h2 class="py-2 pe-2">
{{ is_granted('ROLE_ADMIN') ? 'All Seasons'|trans : 'Your Seasons'|trans }}
</h2>
<a class="link" href="{{ path('app_backoffice_season_add') }}">
<a class="link" href="{{ path('tvdt_backoffice_season_add') }}">
{{ 'Add'|trans }}
</a>
</div>
@@ -39,11 +39,11 @@
{% endif %}
</td>
<td>
<a {% if season.activeQuiz %}href="{{ path('app_quiz_enter_name', {seasonCode: season.seasonCode}) }}"
<a {% if season.activeQuiz %}href="{{ path('tvdt_quiz_enter_name', {seasonCode: season.seasonCode}) }}"
{% else %}class="disabled" {% endif %}>{{ season.seasonCode }}</a>
</td>
<td>
<a href="{{ path('app_backoffice_season', {seasonCode: season.seasonCode}) }}">{{ 'Manage'|trans }}</a>
<a href="{{ path('tvdt_backoffice_season', {seasonCode: season.seasonCode}) }}">{{ 'Manage'|trans }}</a>
</td>
</tr>
{% endfor %}

View File

@@ -5,7 +5,7 @@
{% block body %}
{% if app.user %}
<div class="mb-3">
You are logged in as {{ app.user.userIdentifier }}, <a href="{{ path('app_login_logout') }}">Logout</a>
You are logged in as {{ app.user.userIdentifier }}, <a href="{{ path('tvdt_login_logout') }}">Logout</a>
</div>
{% else %}
<form method="post">
@@ -34,7 +34,7 @@
<button class="btn btn-lg btn-primary" type="submit">
{{ 'Sign in'|trans }}
</button>
<a href="{{ path('app_register') }}"
<a href="{{ path('tvdt_register') }}"
class="btn btn-link">{{ 'Create an account'|trans }}</a>
</form>
{% endif %}

View File

@@ -1,6 +1,6 @@
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container-fluid">
<a class="navbar-brand" href="{{ path('app_backoffice_index') }}">Tijd voor de test</a>
<a class="navbar-brand" href="{{ path('tvdt_backoffice_index') }}">Tijd voor de test</a>
<button class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
@@ -14,18 +14,18 @@
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link{% if 'app_backoffice_index' == app.current_route() %} active{% endif %}"
href="{{ path('app_backoffice_index') }}">{{ 'Seasons'|trans }}</a>
<a class="nav-link{% if 'tvdt_backoffice_index' == app.current_route() %} active{% endif %}"
href="{{ path('tvdt_backoffice_index') }}">{{ 'Seasons'|trans }}</a>
</li>
<li class="nav-item">
<a class="nav-link"
href="{{ path('app_backoffice_template') }}">{{ 'Download Template'|trans }}</a>
href="{{ path('tvdt_backoffice_template') }}">{{ 'Download Template'|trans }}</a>
</li>
</ul>
<ul class="navbar-nav mb-auto me-2 me-lg-0">
<li class="nav-item">
<a class="nav-link"
href="{{ path('app_login_logout') }}">{{ 'Logout'|trans }}</a>
href="{{ path('tvdt_login_logout') }}">{{ 'Logout'|trans }}</a>
</li>
</ul>
</div>

View File

@@ -3,12 +3,12 @@
<div class="row">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{{ path('app_backoffice_index') }}">Home</a></li>
<li class="breadcrumb-item"><a href="{{ path('tvdt_backoffice_index') }}">Home</a></li>
<li class="breadcrumb-item"><a
href="{{ path('app_backoffice_season', {seasonCode: elimination.quiz.season.seasonCode}) }}">{{ elimination.quiz.season.name }}</a>
href="{{ path('tvdt_backoffice_season', {seasonCode: elimination.quiz.season.seasonCode}) }}">{{ elimination.quiz.season.name }}</a>
</li>
<li class="breadcrumb-item"><a
href="{{ path('app_backoffice_quiz', {seasonCode: elimination.quiz.season.seasonCode, quiz: elimination.quiz.id}) }}">{{ elimination.quiz.name }}</a>
href="{{ path('tvdt_backoffice_quiz', {seasonCode: elimination.quiz.season.seasonCode, quiz: elimination.quiz.id}) }}">{{ elimination.quiz.name }}</a>
</li>
<li class="breadcrumb-item active" aria-current="page">Prepare Elimination</li>
@@ -36,7 +36,7 @@
<button type="submit" class="btn btn-primary" name="start" value="0">{{ 'Save'|trans }}</button>
<button type="submit" class="btn btn-success" name="start"
value="1">{{ 'Save and start elimination'|trans }}</button>
<a href="{{ path('app_backoffice_quiz', {seasonCode: elimination.quiz.season.seasonCode, quiz: elimination.quiz.id}) }}"
<a href="{{ path('tvdt_backoffice_quiz', {seasonCode: elimination.quiz.season.seasonCode, quiz: elimination.quiz.id}) }}"
class="btn btn-secondary">{{ 'Back'|trans }}</a>
</div>
</form>

View File

@@ -6,10 +6,10 @@
<h2 class="py-2">{{ 'Quiz'|trans }}: {{ quiz.season.name }} - {{ quiz.name }}</h2>
<div class="py-2 btn-group" data-controller="bo--quiz">
<a class="btn btn-primary {% if quiz is same as(season.activeQuiz) %}disabled{% endif %}"
href="{{ path('app_backoffice_enable', {seasonCode: season.seasonCode, quiz: quiz.id}) }}">{{ 'Make active'|trans }}</a>
href="{{ path('tvdt_backoffice_enable', {seasonCode: season.seasonCode, quiz: quiz.id}) }}">{{ 'Make active'|trans }}</a>
{% if quiz is same as (season.activeQuiz) %}
<a class="btn btn-secondary"
href="{{ path('app_backoffice_enable', {seasonCode: season.seasonCode, quiz: 'null'}) }}">{{ 'Deactivate Quiz'|trans }}</a>
href="{{ path('tvdt_backoffice_enable', {seasonCode: season.seasonCode, quiz: 'null'}) }}">{{ 'Deactivate Quiz'|trans }}</a>
{% endif %}
<button class="btn btn-danger" data-action="click->bo--quiz#clearQuiz">
{{ 'Clear quiz...'|trans }}
@@ -62,7 +62,7 @@
<div class="btn-toolbar" role="toolbar">
<div class="btn-group btn-group-lg me-2">
{# <a class="btn btn-primary">{{ 'Start Elimination'|trans }}</a> #}
<a href="{{ path('app_prepare_elimination', {seasonCode: season.seasonCode, quiz: quiz.id}) }}"
<a href="{{ path('tvdt_prepare_elimination', {seasonCode: season.seasonCode, quiz: quiz.id}) }}"
class="btn btn-secondary">{{ 'Prepare Custom Elimination'|trans }}</a>
{%~ if not quiz.eliminations.empty %}
<button class="btn btn-secondary dropdown-toggle"
@@ -70,7 +70,7 @@
<ul class="dropdown-menu">
{%~ for elimination in quiz.eliminations %}
<li><a class="dropdown-item"
href="{{ path('app_prepare_elimination_view', {elimination: elimination.id}) }}">{{ elimination.created|format_datetime() }}</a>
href="{{ path('tvdt_prepare_elimination_view', {elimination: elimination.id}) }}">{{ elimination.created|format_datetime() }}</a>
</li>
{%~ endfor %}
</ul>
@@ -95,7 +95,7 @@
<td>{{ candidate.correct|default('0') }}</td>
<td>
<form method="post"
action="{{ path('app_backoffice_modify_correction', {quiz: quiz.id, candidate: candidate.id}) }}">
action="{{ path('tvdt_backoffice_modify_correction', {quiz: quiz.id, candidate: candidate.id}) }}">
<div class="row">
<div class="col-8">
<input class="form-control form-control-sm" type="number"
@@ -135,7 +135,7 @@
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ 'No'|trans }}</button>
<a href="{{ path('app_backoffice_quiz_clear', {quiz: quiz.id}) }}"
<a href="{{ path('tvdt_backoffice_quiz_clear', {quiz: quiz.id}) }}"
class="btn btn-danger">{{ 'Yes'|trans }}</a>
</div>
</div>
@@ -157,7 +157,7 @@
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ 'No'|trans }}</button>
<a href="{{ path('app_backoffice_quiz_delete', {quiz: quiz.id}) }}"
<a href="{{ path('tvdt_backoffice_quiz_delete', {quiz: quiz.id}) }}"
class="btn btn-danger">{{ 'Yes'|trans }}</a>
</div>
</div>

View File

@@ -11,7 +11,7 @@
{{ form_row(registrationForm.plainPassword) }}
<button type="submit" class="btn btn-primary">Register</button>
<a href="{{ path('app_login_login') }}" class="btn btn-link">{{ 'Already have an account? Log in'|trans }}</a>
<a href="{{ path('tvdt_login_login') }}" class="btn btn-link">{{ 'Already have an account? Log in'|trans }}</a>
{{ form_end(registrationForm) }}
{% endblock %}

View File

@@ -7,12 +7,12 @@
<div class="d-flex flex-row align-items-center">
<h4 class="py-2 pe-2">{{ 'Quizzes'|trans }}</h4>
<a class="link"
href="{{ path('app_backoffice_quiz_add', {seasonCode: season.seasonCode}) }}">{{ 'Add'|trans }}</a>
href="{{ path('tvdt_backoffice_quiz_add', {seasonCode: season.seasonCode}) }}">{{ 'Add'|trans }}</a>
</div>
<div class="list-group">
{% for quiz in season.quizzes %}
<a class="list-group-item list-group-item-action{% if season.activeQuiz == quiz %} active{% endif %}"
href="{{ path('app_backoffice_quiz', {seasonCode: season.seasonCode, quiz: quiz.id}) }}">{{ quiz.name }}</a>
href="{{ path('tvdt_backoffice_quiz', {seasonCode: season.seasonCode, quiz: quiz.id}) }}">{{ quiz.name }}</a>
{% else %}
No quizzes
{% endfor %}
@@ -22,7 +22,7 @@
<div class="d-flex flex-row align-items-center">
<h4 class="py-2 pe-2">{{ 'Candidates'|trans }}</h4>
<a class="link"
href="{{ path('app_backoffice_add_candidates', {seasonCode: season.seasonCode}) }}">{{ 'Add Candidate'|trans }}
href="{{ path('tvdt_backoffice_add_candidates', {seasonCode: season.seasonCode}) }}">{{ 'Add Candidate'|trans }}
</a>
</div>
<ul>

View File

@@ -1,5 +1,5 @@
{% extends 'quiz/base.html.twig' %}
{% block body %}
{{ form(form) }}
<a href="{{ path('app_backoffice_index') }}" class="btn btn-outline-secondary">{{ 'Manage Quiz'|trans }}</a>
<a href="{{ path('tvdt_backoffice_index') }}" class="btn btn-outline-secondary">{{ 'Manage Quiz'|trans }}</a>
{% endblock body %}

View File

@@ -2,21 +2,21 @@
declare(strict_types=1);
namespace App\Tests\Security\Voter;
namespace Tvdt\Tests\Security\Voter;
use App\Entity\Answer;
use App\Entity\Candidate;
use App\Entity\Elimination;
use App\Entity\Question;
use App\Entity\Quiz;
use App\Entity\Season;
use App\Entity\User;
use App\Security\Voter\SeasonVoter;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\MockObject\Stub;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
use Tvdt\Entity\Answer;
use Tvdt\Entity\Candidate;
use Tvdt\Entity\Elimination;
use Tvdt\Entity\Question;
use Tvdt\Entity\Quiz;
use Tvdt\Entity\Season;
use Tvdt\Entity\User;
use Tvdt\Security\Voter\SeasonVoter;
final class SeasonVoterTest extends TestCase
{

15
tests/object-manager.php Normal file
View File

@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
use Symfony\Component\Dotenv\Dotenv;
use Tvdt\Kernel;
require __DIR__.'/../vendor/autoload.php';
new Dotenv()->bootEnv(__DIR__.'/../.env');
$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
$kernel->boot();
return $kernel->getContainer()->get('doctrine')->getManager();