diff --git a/src/Controller/Admin/Application/RejectController.php b/src/Controller/Admin/Application/RejectController.php deleted file mode 100644 index 5062c7f..0000000 --- a/src/Controller/Admin/Application/RejectController.php +++ /dev/null @@ -1,46 +0,0 @@ -eventDispatcher->dispatch(new ApplicationRejectedEvent($applicationCheckDto), ApplicationRejectedEvent::NAME); - - $application->setStatus(Application::STATUS_REJECTED); - - $this->entityManager->flush(); - - $this->addFlash('success', 'Die Bewerbung wurde abgelehnt'); - $this->logger->info('Reject application', [ - 'application' => $application->getUuid(), - ]); - - return $this->redirectToRoute('app_admin_assignment_detail', [ - 'uuid' => $application->getAssignment()->getUuid(), - ]); - } -} \ No newline at end of file diff --git a/src/Controller/Admin/Application/StatusController.php b/src/Controller/Admin/Application/StatusController.php new file mode 100644 index 0000000..d31d3ca --- /dev/null +++ b/src/Controller/Admin/Application/StatusController.php @@ -0,0 +1,62 @@ +generateUrl('app_admin_application_status', ['uuid' => $application->getUuid()]); + $formData = new ApplicationCheckDto($application); + $form = $this->createForm(ApplicationCheckType::class, $formData, ['action' => $formAction, 'ajax_submit' => true]); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $this->eventDispatcher->dispatch(new ApplicationStatusEvent($formData), ApplicationStatusEvent::NAME); + $application->setStatus($formData->getStatus()); + $this->entityManager->flush(); + + $this->addFlash('success', 'Der Status der Bewerbung wurde aktualisiert'); + $this->logger->info('Update application status', [ + 'application' => $application->getUuid(), + 'status_new' => $formData->getStatus(), + ]); + + $response->setCloseAndRedirect($this->generateUrl('app_admin_assignment_detail', [ + 'uuid' => $application->getAssignment()->getUuid(), + ])); + } else { + $response->setContent($this->renderView('admin/application/status.html.twig', [ + 'form' => $form, + ])); + } + + return $this->json($response); + } +} \ No newline at end of file diff --git a/src/Controller/Admin/Assignment/DetailController.php b/src/Controller/Admin/Assignment/DetailController.php index a070847..6ac8384 100644 --- a/src/Controller/Admin/Assignment/DetailController.php +++ b/src/Controller/Admin/Assignment/DetailController.php @@ -26,13 +26,15 @@ class DetailController extends AbstractController #[IsGranted('ROLE_ADMINISTRATIVE')] public function index(Assignment $assignment, Request $request): Response { - $applications = $this->applicationRepository->findBy([ - 'assignment' => $assignment, - ]); + $applications = $this + ->applicationRepository + ->getCurrentByAssignment($assignment) + ; - $dispositions = $this->dispositionRepository->findBy([ - 'assignment' => $assignment, - ]); + $dispositions = $this + ->dispositionRepository + ->getCurrentByAssignment($assignment) + ; return $this->render('admin/assignment/detail.html.twig', [ 'assignment' => $assignment, diff --git a/src/Event/ApplicationRejectedEvent.php b/src/Event/ApplicationStatusEvent.php similarity index 86% rename from src/Event/ApplicationRejectedEvent.php rename to src/Event/ApplicationStatusEvent.php index a701e94..0ccb0da 100644 --- a/src/Event/ApplicationRejectedEvent.php +++ b/src/Event/ApplicationStatusEvent.php @@ -6,9 +6,9 @@ use App\Entity\Application; use App\Model\ApplicationCheckDto; use Symfony\Contracts\EventDispatcher\Event; -class ApplicationRejectedEvent extends Event +class ApplicationStatusEvent extends Event { - public const NAME = 'application.rejected'; + public const NAME = 'application.status'; private Application $application; private ?string $comment; diff --git a/src/Form/ApplicationCheckType.php b/src/Form/ApplicationCheckType.php new file mode 100644 index 0000000..9f58fc9 --- /dev/null +++ b/src/Form/ApplicationCheckType.php @@ -0,0 +1,41 @@ +add('status', ChoiceType::class, [ + 'label' => 'neuer Status', + 'choices' => [ + 'in Bearbeitung' => Application::STATUS_PENDING, + 'abgelehnt' => Application::STATUS_REJECTED, + ], + ]) + ->add('comment', TextareaType::class, [ + 'label' => 'Kommentar/Begründung', + 'required' => false, + 'attr' => [ + 'rows' => 3, + ], + ]) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'data_class' => ApplicationCheckDto::class, + ]); + } +} \ No newline at end of file diff --git a/src/Model/ApplicationCheckDto.php b/src/Model/ApplicationCheckDto.php index fa0173e..56003bb 100644 --- a/src/Model/ApplicationCheckDto.php +++ b/src/Model/ApplicationCheckDto.php @@ -7,11 +7,13 @@ use App\Entity\Application; class ApplicationCheckDto { private Application $application; + private string $status; private ?string $comment = null; public function __construct(Application $application) { $this->application = $application; + $this->status = $application->getStatus(); } public function getApplication(): Application @@ -19,6 +21,18 @@ class ApplicationCheckDto return $this->application; } + public function getStatus(): string + { + return $this->status; + } + + public function setStatus(string $status): static + { + $this->status = $status; + + return $this; + } + public function getComment(): ?string { return $this->comment; diff --git a/src/Repository/ApplicationRepository.php b/src/Repository/ApplicationRepository.php index d47e372..6c7c9af 100644 --- a/src/Repository/ApplicationRepository.php +++ b/src/Repository/ApplicationRepository.php @@ -3,6 +3,7 @@ namespace App\Repository; use App\Entity\Application; +use App\Entity\Assignment; use App\Entity\Teamer; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\ORM\Query; @@ -53,4 +54,22 @@ class ApplicationRepository extends ServiceEntityRepository ->getQuery() ; } + + public function getCurrentByAssignment(Assignment $assignment): array + { + $qb = $this->createQueryBuilder('application'); + + return $qb + ->select('application', 'teamer') + ->innerJoin('application.teamer', 'teamer') + ->where($qb->expr()->andX( + $qb->expr()->eq('application.assignment', ':assignment'), + $qb->expr()->neq('application.status', ':status') + )) + ->setParameter('assignment', $assignment) + ->setParameter('status', Application::STATUS_REJECTED) + ->getQuery() + ->getResult() + ; + } } diff --git a/src/Repository/DispositionRepository.php b/src/Repository/DispositionRepository.php index fd588c4..ca935b3 100644 --- a/src/Repository/DispositionRepository.php +++ b/src/Repository/DispositionRepository.php @@ -2,6 +2,8 @@ namespace App\Repository; +use App\Entity\Application; +use App\Entity\Assignment; use App\Entity\Disposition; use App\Entity\Teamer; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; @@ -78,4 +80,18 @@ class DispositionRepository extends ServiceEntityRepository ->getQuery() ; } + + public function getCurrentByAssignment(Assignment $assignment): array + { + $qb = $this->createQueryBuilder('disposition'); + + return $qb + ->select('disposition', 'teamer') + ->innerJoin('disposition.teamer', 'teamer') + ->where($qb->expr()->eq('disposition.assignment', ':assignment')) + ->setParameter('assignment', $assignment) + ->getQuery() + ->getResult() + ; + } } diff --git a/src/Security/Voter/ApplicationVoter.php b/src/Security/Voter/ApplicationVoter.php index e850723..2cded3b 100644 --- a/src/Security/Voter/ApplicationVoter.php +++ b/src/Security/Voter/ApplicationVoter.php @@ -12,7 +12,7 @@ class ApplicationVoter extends Voter public const VIEW = 'VIEW'; public const DELETE = 'DELETE'; public const DISPOSE = 'DISPOSE'; - public const REJECT = 'REJECT'; + public const STATUS = 'STATUS'; protected function supports(string $attribute, mixed $subject): bool { @@ -20,7 +20,7 @@ class ApplicationVoter extends Voter return false; } - return in_array($attribute, [static::VIEW, static::DELETE, static::DISPOSE, static::REJECT]); + return in_array($attribute, [static::VIEW, static::DELETE, static::DISPOSE, static::STATUS]); } protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool @@ -34,9 +34,8 @@ class ApplicationVoter extends Voter if ($user->hasRole('ROLE_ADMINISTRATIVE')) { $assignment = $application->getAssignment(); return match ($attribute) { - static::VIEW => true, + static::VIEW, static::STATUS => Application::STATUS_REJECTED !== $application->getStatus(), static::DELETE => Application::STATUS_REJECTED === $application->getStatus(), - static::REJECT => Application::STATUS_REJECTED !== $application->getStatus(), static::DISPOSE => Application::STATUS_REJECTED !== $application->getStatus() && $assignment->getAvailableDispositions() > $assignment->getDispositions()->count(), default => false, diff --git a/templates/admin/application/status.html.twig b/templates/admin/application/status.html.twig new file mode 100644 index 0000000..29f8e9e --- /dev/null +++ b/templates/admin/application/status.html.twig @@ -0,0 +1,10 @@ +{{ form_start(form) }} +