From f269068b71be8ef12b0ba6865fee53b7b6877206 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Fromme?= Date: Wed, 8 Jan 2025 13:04:49 +0100 Subject: [PATCH 1/2] feat: upload in behalf of teamer for administrative users --- .../Disposition/DocumentUploadController.php | 107 ++++++++++++++++++ .../DispositionWorkflowGuardSubscriber.php | 13 ++- .../assignment/detail.html.twig | 9 ++ .../modal_document_upload.html.twig | 20 ++++ 4 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 src/Controller/Administrative/Disposition/DocumentUploadController.php create mode 100644 templates/administrative/disposition/modal_document_upload.html.twig diff --git a/src/Controller/Administrative/Disposition/DocumentUploadController.php b/src/Controller/Administrative/Disposition/DocumentUploadController.php new file mode 100644 index 0000000..2a49821 --- /dev/null +++ b/src/Controller/Administrative/Disposition/DocumentUploadController.php @@ -0,0 +1,107 @@ +workflow->can($disposition, 'upload_contract')) { + $uploadType = Upload::TYPE_CONTRACT; + $uploadTypeLabel = 'Honorarvertrag'; + $uploaderRoute = '_uploader_upload_contract'; + } elseif (true === $this->workflow->can($disposition, 'upload_invoice')) { + $uploadType = Upload::TYPE_INVOICE; + $uploadTypeLabel = 'Honoranote'; + $uploaderRoute = '_uploader_upload_invoice'; + } else { + $this->addFlash('error', 'Kein Upload möglich beim aktuellen Status der Einteilung'); + + return $this->getRedirectResponse($disposition); + } + + $teamer = $disposition->getTeamer(); + $modalTitle = sprintf('%s für %s hochladen', $uploadTypeLabel, $teamer); + + $form = $this->createFormBuilder()->getForm(); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $this->processUpload($disposition, $uploadType); + + $this->addFlash('success', sprintf('%s wurde hochgeladen', $uploadTypeLabel)); + + return $this->getRedirectResponse($disposition); + } + + return $this->render('administrative/disposition/modal_document_upload.html.twig', [ + 'disposition' => $disposition, + 'modalTitle' => $modalTitle, + 'uploaderRoute' => $uploaderRoute, + 'form' => $form->createView(), + ]); + } + + private function processUpload(Disposition $disposition, string $uploadType): void + { + if (null !== $existingUpload = $disposition->getDocumentByType($uploadType)) { + $this->entityManager->remove($existingUpload); + } + + $teamer = $disposition->getTeamer(); + $user = $teamer->getUser(); + + $uploadSession = $this->uploadHandler->getUploadSession(); + + $upload = Upload::fromUploadDto($uploadSession->getUploads()->first(), $user, $uploadType); + $upload->setStatus(Upload::STATUS_NEW); + + $disposition->addDocument($upload); + + $transitionName = sprintf('upload_%s', $uploadType); + $this->workflow->apply($disposition, $transitionName); + + $this->entityManager->flush(); + + $this->uploadHandler->moveUploadSessionFilesFromOrphanage($uploadType, $uploadSession); + $this->uploadHandler->destroyUploadSession(); + + $this->eventDispatcher->dispatch(new DocumentUploadedEvent($upload), DocumentUploadedEvent::NAME); + } + + private function getRedirectResponse(Disposition $disposition): HxRedirectResponse + { + return new HxRedirectResponse($this->generateUrl('app_administrative_assignment_detail', [ + 'uuid' => $disposition->getAssignment()->getUuid(), + ])); + } +} diff --git a/src/EventListener/DispositionWorkflowGuardSubscriber.php b/src/EventListener/DispositionWorkflowGuardSubscriber.php index 65fe97d..fbc5859 100644 --- a/src/EventListener/DispositionWorkflowGuardSubscriber.php +++ b/src/EventListener/DispositionWorkflowGuardSubscriber.php @@ -4,13 +4,14 @@ namespace App\EventListener; use App\Entity\Disposition; use App\Entity\Upload; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Workflow\Event\GuardEvent; use Symfony\Contracts\Translation\TranslatorInterface; class DispositionWorkflowGuardSubscriber implements EventSubscriberInterface { - public function __construct(private readonly TranslatorInterface $translator) + public function __construct(private readonly TranslatorInterface $translator, private readonly Security $security) {} public static function getSubscribedEvents(): array @@ -40,6 +41,11 @@ class DispositionWorkflowGuardSubscriber implements EventSubscriberInterface public function guardUploadContract(GuardEvent $event): void { + // no checks for administrative users + if ($this->security->isGranted('ROLE_ADMINISTRATIVE')) { + return; + } + /** @var Disposition $disposition */ $disposition = $event->getSubject(); $assignment = $disposition->getAssignment(); @@ -79,6 +85,11 @@ class DispositionWorkflowGuardSubscriber implements EventSubscriberInterface $event->setBlocked(true, $message); } + // no further checks for administrative users + if ($this->security->isGranted('ROLE_ADMINISTRATIVE')) { + return; + } + $earliestDate = $destination->getDateTo(); if ($earliestDate > $today) { diff --git a/templates/administrative/assignment/detail.html.twig b/templates/administrative/assignment/detail.html.twig index b95deb4..aece30e 100644 --- a/templates/administrative/assignment/detail.html.twig +++ b/templates/administrative/assignment/detail.html.twig @@ -179,6 +179,15 @@
+ {% if workflow_can(disposition, 'upload_contract') or workflow_can(disposition, 'upload_invoice') %} + + {% endif %} {% if is_granted('DELETE', disposition) %}
+ + {{ form_rest(form) }} + {{ form_end(form) }} +{% endblock %} \ No newline at end of file From dad6965494ca840132d90bda286e086701dc3f92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Fromme?= Date: Wed, 8 Jan 2025 13:10:14 +0100 Subject: [PATCH 2/2] feat: log uploads by administrative users on behalf of teamers --- .../Disposition/DocumentUploadController.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Controller/Administrative/Disposition/DocumentUploadController.php b/src/Controller/Administrative/Disposition/DocumentUploadController.php index 2a49821..e090c1a 100644 --- a/src/Controller/Administrative/Disposition/DocumentUploadController.php +++ b/src/Controller/Administrative/Disposition/DocumentUploadController.php @@ -8,6 +8,7 @@ use App\Event\DocumentUploadedEvent; use App\Htmx\HxRedirectResponse; use App\Service\Upload\UploadHandler; use Doctrine\ORM\EntityManagerInterface; +use Psr\Log\LoggerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\DependencyInjection\Attribute\Target; use Symfony\Component\HttpFoundation\Request; @@ -25,6 +26,7 @@ class DocumentUploadController extends AbstractController #[Target('disposition')] private readonly WorkflowInterface $workflow, private readonly EventDispatcherInterface $eventDispatcher, + private readonly LoggerInterface $logger, ) { } @@ -96,6 +98,14 @@ class DocumentUploadController extends AbstractController $this->uploadHandler->destroyUploadSession(); $this->eventDispatcher->dispatch(new DocumentUploadedEvent($upload), DocumentUploadedEvent::NAME); + + $this->logger->info('Document upload for teamer', [ + 'teamer_id' => $teamer->getId(), + 'teamer_name' => $teamer->getFullName(), + 'disposition_id' => $disposition->getId(), + 'document_id' => $upload->getId(), + 'upload_type' => $uploadType, + ]); } private function getRedirectResponse(Disposition $disposition): HxRedirectResponse