feat: review received form submissions in the admin ui

This commit is contained in:
fromme committed 2026-09-24 16:35:18 +02:00
1 parent f073a2014d
commit cb2d64f2cd
19 files changed
+999 -7

No files matched your search

@@ -0,0 +1,63 @@
<?php
namespace App\Controller\Admin\ApplicationFormSubmission;
use App\Controller\Traits\ReturnUrlTrait;
use App\Entity\ApplicationFormSubmission;
use App\Form\ApplicationFormSubmissionCallsType;
use App\Model\ApplicationFormSubmissionCallsDto;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
/**
* Saves the two "call held" checkboxes of the detail view. Rendered by DetailController, which
* builds the same form - this one only takes the submission.
*/
class CallsController extends AbstractController
{
use ReturnUrlTrait;
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger,
) {
}
#[Route('/admin/application-form-submission/calls/{uuid}', name: 'app_admin_application_form_submission_calls', methods: ['POST'])]
#[IsGranted('ROLE_TEAM_ADMIN')]
public function index(ApplicationFormSubmission $submission, Request $request): Response
{
$callsDto = new ApplicationFormSubmissionCallsDto($submission);
$form = $this->createForm(ApplicationFormSubmissionCallsType::class, $callsDto);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$callsDto->applyToSubmission();
$this->entityManager->flush();
$this->logger->info('Update application form submission calls', [
'uuid' => $submission->getUuid(),
'firstCallHeldAt' => $submission->getFirstCallHeldAt()?->format('Y-m-d'),
'secondCallHeldAt' => $submission->getSecondCallHeldAt()?->format('Y-m-d'),
]);
$this->addFlash('success', 'Die Calls wurden gespeichert');
}
return $this->redirect($this->detailUrl($submission, $request));
}
private function detailUrl(ApplicationFormSubmission $submission, Request $request): string
{
return $this->generateUrl('app_admin_application_form_submission_detail', [
'uuid' => $submission->getUuid(),
'r' => $request->query->get('r'),
]);
}
}
@@ -0,0 +1,58 @@
<?php
namespace App\Controller\Admin\ApplicationFormSubmission;
use App\Controller\Traits\ReturnUrlTrait;
use App\Entity\ApplicationFormSubmission;
use App\Htmx\HxRedirectResponse;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
/**
* A real DELETE, not setDeleted(): the retention rule for job applications asks for the row to
* be gone, and "details" and "payload" go with it. The audit log keeps the uuid and who deleted
* it, deliberately without the applicant's data.
*/
class DeleteController extends AbstractController
{
use ReturnUrlTrait;
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger,
) {
}
#[Route('/admin/application-form-submission/delete/{uuid}', name: 'app_admin_application_form_submission_delete')]
#[IsGranted('ROLE_TEAM_ADMIN')]
public function index(ApplicationFormSubmission $submission, Request $request): Response
{
if (true === $request->isMethod(Request::METHOD_POST)) {
$uuid = $submission->getUuid();
$this->entityManager->remove($submission);
$this->entityManager->flush();
$this->logger->info('Delete application form submission', [
'uuid' => $uuid,
'form' => $submission->getForm(),
'submittedAt' => $submission->getSubmittedAt()->format(\DateTimeInterface::ATOM),
]);
$this->addFlash('success', 'Das eingegangene Formular wurde gelöscht');
return new HxRedirectResponse(
$this->getReturnUrl($request, 'app_admin_application_form_submission_index')
);
}
return $this->render('admin/application_form_submission/modal_delete.html.twig', [
'submission' => $submission,
]);
}
}
@@ -0,0 +1,40 @@
<?php
namespace App\Controller\Admin\ApplicationFormSubmission;
use App\Controller\Traits\ReturnUrlTrait;
use App\Entity\ApplicationFormSubmission;
use App\Form\ApplicationFormSubmissionCallsType;
use App\Model\ApplicationFormSubmissionCallsDto;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
class DetailController extends AbstractController
{
use ReturnUrlTrait;
#[Route('/admin/application-form-submission/detail/{uuid}', name: 'app_admin_application_form_submission_detail')]
#[IsGranted('ROLE_TEAM_ADMIN')]
public function index(ApplicationFormSubmission $submission, Request $request): Response
{
// Rendered here, taken by CallsController - the form has no validation to fail, so it
// never has to come back to this page with errors.
$callsForm = $this->createForm(
ApplicationFormSubmissionCallsType::class,
new ApplicationFormSubmissionCallsDto($submission),
['action' => $this->generateUrl('app_admin_application_form_submission_calls', [
'uuid' => $submission->getUuid(),
'r' => $request->query->get('r'),
])]
);
return $this->render('admin/application_form_submission/detail.html.twig', [
'submission' => $submission,
'callsForm' => $callsForm->createView(),
'returnUrl' => $this->getReturnUrl($request, 'app_admin_application_form_submission_index'),
]);
}
}
@@ -0,0 +1,49 @@
<?php
namespace App\Controller\Admin\ApplicationFormSubmission;
use App\Repository\ApplicationFormSubmissionRepository;
use App\Service\Common\ApplicationFormSubmissionFilterHandler;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
/**
* The forms the public websites posted here, newest first. Read-only apart from the follow-up
* dates and the deletion the retention rule asks for - nothing in this application creates a
* submission.
*/
class IndexController extends AbstractController
{
public function __construct(
private readonly ApplicationFormSubmissionRepository $submissionRepository,
private readonly PaginatorInterface $paginator,
private readonly ApplicationFormSubmissionFilterHandler $filterHandler,
) {
}
#[Route('/admin/application-form-submission', name: 'app_admin_application_form_submission_index')]
#[IsGranted('ROLE_TEAM_ADMIN')]
public function index(Request $request): Response
{
$filterDto = $this->filterHandler->getFilterSettings();
$pagination = $this->paginator->paginate(
$this->submissionRepository->getListQuery($filterDto),
$request->query->getInt('page', 1),
$request->query->getInt('limit', 50),
[
'defaultSortFieldName' => 'submission.submittedAt',
'defaultSortDirection' => 'desc',
]
);
return $this->render('admin/application_form_submission/index.html.twig', [
'pagination' => $pagination,
'filterDto' => $filterDto,
]);
}
}
@@ -0,0 +1,50 @@
<?php
namespace App\Controller\Common;
use App\Form\ApplicationFormSubmissionFilterType;
use App\Htmx\HxRedirectResponse;
use App\Service\Common\ApplicationFormSubmissionFilterHandler;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
class ApplicationFormSubmissionFilterController extends AbstractController
{
public function __construct(private readonly ApplicationFormSubmissionFilterHandler $filterHandler)
{
}
#[Route('/common/application-form-submission/filter', name: 'app_common_application_form_submission_filter')]
#[IsGranted('ROLE_TEAM_ADMIN')]
public function index(Request $request): Response
{
$formData = $this->filterHandler->getFilterSettings();
$form = $this->createForm(ApplicationFormSubmissionFilterType::class, $formData);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->filterHandler->handleRequest($form);
return new HxRedirectResponse(
$this->generateUrl('app_admin_application_form_submission_index')
);
}
return $this->render('common/modal_application_form_submission_filter.html.twig', [
'filterForm' => $form->createView(),
'filterDto' => $form->getData(),
]);
}
#[Route('/common/application-form-submission/filter/reset', name: 'app_common_application_form_submission_filter_reset')]
#[IsGranted('ROLE_TEAM_ADMIN')]
public function reset(): Response
{
$this->filterHandler->resetFilterSettings();
return $this->redirectToRoute('app_admin_application_form_submission_index');
}
}