<?php
namespace App\Controller\District;
use App\Application\ApplicationHelper;
use App\Entity\Attachment;
use App\Entity\Project;
use App\Form\AttachmentFormType;
use App\Project\AttachmentHelper;
use App\Project\ProjectForm;
use App\Project\ProjectHelper;
use App\Project\ProjectOutput;
use App\Repository\AttachmentRepository;
use App\Service\ProjectPdfCreator;
use App\Service\StatusHelper;
use App\Service\UploaderHelper;
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\Annotation\Route;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
class ProjectController extends AbstractController
{
private ProjectForm $projectForm;
private ProjectHelper $projectHelper;
private ApplicationHelper $applicationHelper;
private AttachmentHelper $attachmentHelper;
private StatusHelper $statusHelper;
public function __construct(
ProjectForm $projectForm,
ProjectHelper $projectHelper,
AttachmentHelper $attachmentHelper,
ApplicationHelper $applicationHelper,
StatusHelper $statusHelper
) {
$this->projectForm = $projectForm;
$this->projectHelper = $projectHelper;
$this->applicationHelper = $applicationHelper;
$this->attachmentHelper = $attachmentHelper;
$this->statusHelper = $statusHelper;
}
/**
* @Route("/district/project/new", name="app_district_project_new")
*/
public function new(): Response
{
$project = $this->applicationHelper->addNewProject($this->getUser());
return $this->redirectToRoute('app_district_project', ['projectId' => $project->getId(), 'page' => -1]);
}
/**
* @Route("/district/project/edit/{projectId}/{page}", name="app_district_project", defaults={"projectId" = 0, "page" = 0})
*/
public function edit($projectId, $page, Request $request): Response
{
$project = $this->projectHelper->findUserProject($projectId);
$this->denyAccessUnlessGranted('IS_EDITABLE', $project);
$firstLoad = false;
if ($page == -1) {
$firstLoad = true;
$page = 0;
}
if ($this->isFormSent()) {
$action = $this->getAction();
if (in_array($action, ['action_add_attachments', 'action_save', 'action_save_list', 'action_next', 'action_prev', 'action_page'])) {
$this->projectForm->setProject($project);
$this->projectForm->savePage($page);
}
$redirect = $this->handleAction($action, $page, $project, $request);
if ($redirect) {
return $redirect;
}
}
$this->projectForm->setProject($project, !$firstLoad);
$pageNav = $this->projectForm->generatePagenav($page);
$formOutput = $this->projectForm->generatePage($page, $pageNav);
return $this->render('district/project/index.html.twig', [
'formOutput' => $formOutput,
]);
}
/**
* @Route("/district/project/delete/{projectId}", name="app_district_project_delete")
*/
public function delete($projectId, LoggerInterface $logger): Response
{
$project = $this->projectHelper->findUserProject($projectId);
$this->denyAccessUnlessGranted('IS_OWNER', $project);
try {
$this->projectHelper->deleteProject($project);
$this->addFlash('success', 'Das Projekt wurde gelöscht.');
} catch(\Exception $e) {
$this->addFlash('error', 'Das Projekt konnte nicht gelöscht werden.');
$logger->error('project could not be deleted - ' . $e->getMessage());
}
return $this->redirectToRoute('app_district_application');
}
/**
* @Route("/district/project/copy/{projectId}", name="app_district_project_copy")
*/
public function copy($projectId): Response
{
$project = $this->projectHelper->findUserProject($projectId);
$this->denyAccessUnlessGranted('IS_EDITABLE', $project);
$this->statusHelper->checkProjectLimit();
$this->addFlash('success', 'Das Projekt wurde kopiert.');
$this->projectHelper->copyProject($project);
return $this->redirectToRoute('app_district_application');
}
/**
* @Route("/district/project/migrate/{projectId}", name="app_district_project_migrate")
*/
public function migrate($projectId): Response
{
$project = $this->projectHelper->findUserProject($projectId);
$this->denyAccessUnlessGranted('IS_OWNER', $project);
$this->statusHelper->checkProjectLimit();
if ($this->getUser()->getDistrict()->hasActiveApplication()) {
$this->projectHelper->migrateProject($project);
$this->addFlash('success', 'Das Projekt wurde dem aktuellen Wettbewerb hinzugefügt.');
}
return $this->redirectToRoute('app_district_application', ['applicationId' => $project->getApplication()->getId()]);
}
/**
* @Route("/district/project/show/{projectId}", name="app_district_project_show")
*/
public function show($projectId, ProjectOutput $projectOutput, ProjectForm $projectForm): Response
{
$project = $this->projectHelper->findUserProject($projectId);
$this->denyAccessUnlessGranted('IS_OWNER', $project);
$projectOutput->setProject($project);
$output = $projectOutput->output('district');
return $this->render('district/project/show.html.twig', [
'output' => $output,
'project' => $project,
]);
}
/**
* @Route("/district/project/download/{projectId}", name="app_district_project_download")
*/
public function downloadProject($projectId, ProjectPdfCreator $pdfCreator): Response
{
$project = $this->projectHelper->findUserProject($projectId);
$this->denyAccessUnlessGranted('IS_OWNER', $project);
$pdfCreator->setProject($project);
$pdfCreator->addLogo();
$pdfCreator->addIsDistrict();
return $pdfCreator->download('project.pdf');
}
/**
* @Route("/district/project/attachments/{projectId}", name="app_district_project_attachment")
*/
public function attachments($projectId, Request $request, UploaderHelper $uploaderHelper, EntityManagerInterface $em, LoggerInterface $logger): Response
{
$project = $this->projectHelper->findUserProject($projectId);
$this->denyAccessUnlessGranted('IS_OWNER', $project);
$templateName = 'district/project/attachment' . (!$this->projectHelper->isActive($project) ? '_prev' : '');
$maxNumAttachments = $this->getParameter('app.hdfh.max_num_attachments');
$attachments = $project->getAttachments();
$uploadLimitReached = $attachments && sizeof($attachments) >= $maxNumAttachments;
$formView = '';
if (!$uploadLimitReached) {
$attachment = new Attachment();
$attachment->setProject($project);
$form = $this->createForm(AttachmentFormType::class, $attachment, [
'max_upload_size' => $this->getParameter('app.hdfh.max_attachment_size'),
'allowed_mimetypes' => $uploaderHelper->getAllowedMimetypes(),
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$uploadFile = $form['file']->getData();
try {
$attachment = $uploaderHelper->uploadAttachment($uploadFile, $attachment);
$em->persist($attachment);
$em->flush();
// dd($attachment);
// $em->persist($attachment);
$this->addFlash('success', 'Upload erfolgreich');
} catch (\Exception $e) {
// dd($e->getMessage()); // TODO
$logger->error('upload failed - ' . $e->getMessage());
$this->addFlash('error', 'Upload fehlgeschlagen');
}
return $this->redirectToRoute('app_district_project_attachment', ['projectId' => $project->getId()]);
}
$formView = $form->createView();
}
return $this->render($templateName . '.html.twig', [
'form' => $formView,
'uploadLimitReached' => $uploadLimitReached,
'attachments' => $attachments,
'project' => $project,
'maxNumAttachments' => $maxNumAttachments,
'allowedFileTypes' => implode(', ', $uploaderHelper->getAllowedMimetypes(true)),
'maxFileSize' => $this->getParameter('app.hdfh.max_attachment_size'),
]);
}
/**
* @Route("/district/project/delattach/{attachmentId}", name="app_district_project_delete_attachment")
*/
public function deleteAttachment($attachmentId, Request $request, AttachmentHelper $attachmentHelper, EntityManagerInterface $em, AttachmentRepository $attachmentRepository): Response
{
$attachment = $this->attachmentHelper->findUserAttachment($attachmentId);
$this->denyAccessUnlessGranted('IS_OWNER', $attachment);
$attachmentHelper->deleteAttachment($attachment);
// $em->remove($attachment);
// $em->flush();
$this->addFlash('success', 'Anhang gelöscht');
return $this->redirectToRoute('app_district_project_attachment', ['projectId' => $attachment->getProject()->getId()]);
}
/**
* @Route("/attachment/{attachmentId}", name="app_download_attachment")
*/
public function downloadAttachment($attachmentId, UploaderHelper $uploaderHelper): Response
{
$attachment = $this->attachmentHelper->findUserAttachment($attachmentId);
// $this->denyAccessUnlessGranted('IS_OWNER', $attachment);
if (!$this->isGranted('IS_OWNER', $attachment) && !$this->isGranted('ROLE_MANAGER') && !$this->isGranted('ROLE_JURY')) {
throw new AccessDeniedException();
}
return $uploaderHelper->streamAttachment($attachment);
// force download with original filename
// return $uploaderHelper->streamAttachment($attachment, true, true);
}
protected function handleAction($action, $page, Project $project, Request $request): ?Response
{
if ($action == 'action_save_list') {
return $this->redirectToRoute('app_district_application');
}
if ($action == 'action_add_attachments') {
return $this->redirectToRoute('app_district_project_attachment', [
'projectId' => $project->getId(),
]);
}
if ($action == 'action_save') {
$firstInvalidPage = $this->projectForm->getFirstInvalidPage();
if ($firstInvalidPage === false) {
return $this->redirectToRoute('app_district_application');
}
$targetPage = $firstInvalidPage;
return $this->redirectToRoute('app_district_project', [
'projectId' => $project->getId(),
'page' => $targetPage,
]);
}
if ($action == 'action_next') {
$targetPage = $page + 1;
return $this->redirectToRoute('app_district_project', [
'projectId' => $project->getId(),
'page' => $targetPage,
]);
}
if ($action == 'action_prev') {
$targetPage = $page - 1;
return $this->redirectToRoute('app_district_project', [
'projectId' => $project->getId(),
'page' => $targetPage,
]);
}
if ($action == 'action_page') {
$targetPage = $request->get('action_page');
return $this->redirectToRoute('app_district_project', [
'projectId' => $project->getId(),
'page' => $targetPage,
]);
}
return null;
}
protected function getAction()
{
$availableActions = $this->projectForm->getAllActions();
$parameters = array_keys($_POST);
$actions = array_values(array_intersect($availableActions, $parameters));
if (sizeof($actions)) {
return $actions[0];
}
return false;
}
protected function isFormSent(): bool
{
return !empty($_POST);
}
}