svg
This commit is contained in:
@ -56,12 +56,12 @@ class ProjectController extends AbstractController
|
||||
$em->flush();
|
||||
$this->fileService->init('project', $project->getId());
|
||||
|
||||
return $this->redirectToRoute($isAdmin ? 'app_admin_project' : 'app_user_update', ['id' => $project->getId()]);
|
||||
return $this->redirectToRoute($isAdmin ? 'app_admin_project_update' : 'app_user_project_update', ['id' => $project->getId()]);
|
||||
}
|
||||
|
||||
return $this->render('project/edit.html.twig', [
|
||||
'usemenu' => true,
|
||||
'usesidebar' => true,
|
||||
'usesidebar' => $isAdmin,
|
||||
'title' => 'Création Projet',
|
||||
'routecancel' => $isAdmin ? 'app_admin_project' : 'app_home',
|
||||
'routedelete' => $isAdmin ? 'app_admin_project_delete' : 'app_user_project_delete',
|
||||
@ -87,7 +87,11 @@ class ProjectController extends AbstractController
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$em->flush();
|
||||
|
||||
return $this->redirectToRoute($isAdmin ? 'app_admin_project' : 'app_home');
|
||||
if ($isAdmin) {
|
||||
return $this->redirectToRoute('app_admin_project');
|
||||
} else {
|
||||
return $this->redirectToRoute('app_user_project_view', ['id' => $project->getId()]);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->render('project/edit.html.twig', [
|
||||
@ -95,7 +99,10 @@ class ProjectController extends AbstractController
|
||||
'usesidebar' => $isAdmin,
|
||||
'title' => 'Modification Projet = '.$project->getTitle(),
|
||||
'routecancel' => $isAdmin ? 'app_admin_project' : 'app_home',
|
||||
'routemove' => $isAdmin ? 'app_admin_project_move' : 'app_user_project_move',
|
||||
'routedelete' => $isAdmin ? 'app_admin_project_delete' : 'app_user_project_delete',
|
||||
'routesubmitoption' => $isAdmin ? 'app_admin_option_submit' : 'app_user_option_submit',
|
||||
'routeupdateoption' => $isAdmin ? 'app_admin_option_update' : 'app_user_option_update',
|
||||
'mode' => 'update',
|
||||
'form' => $form,
|
||||
'project' => $project,
|
||||
@ -119,7 +126,7 @@ class ProjectController extends AbstractController
|
||||
|
||||
$isAdmin = str_starts_with($request->attributes->get('_route'), 'app_admin');
|
||||
|
||||
return $this->redirectToRoute($isAdmin ? 'app_admin_project' : 'app_home');
|
||||
return $this->redirectToRoute($isAdmin ? 'app_admin_project' : 'app_user_project_view', ['id' => $project->getId()]);
|
||||
}
|
||||
|
||||
#[Route('/admin/project/delete/{id}', name: 'app_admin_project_delete')]
|
||||
@ -141,8 +148,6 @@ class ProjectController extends AbstractController
|
||||
$em->flush();
|
||||
} catch (\Exception $e) {
|
||||
$this->addflash('error', $e->getMessage());
|
||||
|
||||
return $this->redirectToRoute($isAdmin ? 'app_admin_project' : 'app_user_update', ['id' => $project->getId()]);
|
||||
}
|
||||
|
||||
return $this->redirectToRoute($isAdmin ? 'app_admin_project' : 'app_home');
|
||||
@ -158,11 +163,16 @@ class ProjectController extends AbstractController
|
||||
|
||||
$this->denyAccessUnlessGranted(ProjectVoter::VIEW, $project);
|
||||
|
||||
$isAdmin = str_starts_with($request->attributes->get('_route'), 'app_admin');
|
||||
|
||||
return $this->render('project/view.html.twig', [
|
||||
'usemenu' => true,
|
||||
'usesidebar' => false,
|
||||
'title' => 'Projet = '.$project->getTitle(),
|
||||
'routecancel' => 'app_home',
|
||||
'routeupdate' => $isAdmin ? 'app_admin_project_update' : 'app_user_project_update',
|
||||
'routecancel' => $isAdmin ? 'app_admin_project' : 'app_home',
|
||||
'routedelete' => $isAdmin ? 'app_admin_project_delete' : 'app_user_project_delete',
|
||||
'routemove' => $isAdmin ? 'app_admin_project_move' : 'app_user_project_move',
|
||||
'project' => $project,
|
||||
]);
|
||||
}
|
||||
|
111
src/Controller/ProjectOptionController.php
Normal file
111
src/Controller/ProjectOptionController.php
Normal file
@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\ProjectOption;
|
||||
use App\Form\OptionType;
|
||||
use App\Repository\ProjectOptionRepository;
|
||||
use App\Repository\ProjectRepository;
|
||||
use App\Security\ProjectVoter;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class ProjectOptionController extends AbstractController
|
||||
{
|
||||
#[Route('/admin/option/submit/{idproject}', name: 'app_admin_option_submit')]
|
||||
#[Route('/user/option/submit/{idproject}', name: 'app_user_option_submit')]
|
||||
public function submit(int $idproject, Request $request, ProjectRepository $projectRepository, EntityManagerInterface $em): Response
|
||||
{
|
||||
$project = $projectRepository->find($idproject);
|
||||
if (!$project) {
|
||||
throw new NotFoundHttpException('La ressource demandée est introuvable.');
|
||||
}
|
||||
$this->denyAccessUnlessGranted(ProjectVoter::UPDATE, $project);
|
||||
|
||||
$option = new ProjectOption();
|
||||
$option->setProject($project);
|
||||
|
||||
$isAdmin = str_starts_with($request->attributes->get('_route'), 'app_admin');
|
||||
|
||||
$form = $this->createForm(OptionType::class, $option, ['mode' => 'submit']);
|
||||
$form->handleRequest($request);
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$em->persist($option);
|
||||
$em->flush();
|
||||
|
||||
return $this->redirectToRoute($isAdmin ? 'app_admin_project_update' : 'app_user_project_update', ['id' => $idproject]);
|
||||
}
|
||||
|
||||
return $this->render('option/edit.html.twig', [
|
||||
'usemenu' => true,
|
||||
'usesidebar' => $isAdmin,
|
||||
'title' => 'Création Option',
|
||||
'routecancel' => $isAdmin ? 'app_admin_project_update' : 'app_admin_project_update',
|
||||
'routedelete' => $isAdmin ? 'app_admin_option_delete' : 'app_user_option_delete',
|
||||
'mode' => 'submit',
|
||||
'idproject' => $idproject,
|
||||
'form' => $form,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/admin/option/update/{idproject}/{id}', name: 'app_admin_option_update')]
|
||||
#[Route('/user/option/update/{idproject}/{id}', name: 'app_user_option_update')]
|
||||
public function update(int $idproject, int $id, Request $request, ProjectOptionRepository $projectOptionResitory, EntityManagerInterface $em): Response
|
||||
{
|
||||
$option = $projectOptionResitory->find($id);
|
||||
if (!$option) {
|
||||
throw new NotFoundHttpException('La ressource demandée est introuvable.');
|
||||
}
|
||||
|
||||
$this->denyAccessUnlessGranted(ProjectVoter::UPDATE, $option->getProject());
|
||||
|
||||
$isAdmin = str_starts_with($request->attributes->get('_route'), 'app_admin');
|
||||
$form = $this->createForm(OptionType::class, $option, ['mode' => 'update']);
|
||||
$form->handleRequest($request);
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$em->flush();
|
||||
|
||||
return $this->redirectToRoute($isAdmin ? 'app_admin_project_update' : 'app_user_project_update', ['id' => $idproject]);
|
||||
}
|
||||
|
||||
return $this->render('option/edit.html.twig', [
|
||||
'usemenu' => true,
|
||||
'usesidebar' => $isAdmin,
|
||||
'title' => 'Modification Option = '.$option->getTitle(),
|
||||
'routecancel' => $isAdmin ? 'app_admin_project_update' : 'app_user_project_update',
|
||||
'routedelete' => $isAdmin ? 'app_admin_option_delete' : 'app_user_option_delete',
|
||||
'mode' => 'update',
|
||||
'idproject' => $idproject,
|
||||
'option' => $option,
|
||||
'form' => $form,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/admin/option/delete/{idproject}/{id}', name: 'app_admin_option_delete')]
|
||||
#[Route('/user/option/delete/{idproject}/{id}', name: 'app_user_option_delete')]
|
||||
public function delete(int $idproject, int $id, Request $request, ProjectOptionRepository $projectOptionResitory, EntityManagerInterface $em): Response
|
||||
{
|
||||
$option = $projectOptionResitory->find($id);
|
||||
if (!$option) {
|
||||
throw new NotFoundHttpException('La ressource demandée est introuvable.');
|
||||
}
|
||||
|
||||
$this->denyAccessUnlessGranted(ProjectVoter::UPDATE, $option->getProject());
|
||||
|
||||
$isAdmin = str_starts_with($request->attributes->get('_route'), 'app_admin');
|
||||
|
||||
// Tentative de suppression
|
||||
try {
|
||||
$em->remove($option);
|
||||
$em->flush();
|
||||
} catch (\Exception $e) {
|
||||
$this->addflash('error', $e->getMessage());
|
||||
}
|
||||
|
||||
return $this->redirectToRoute($isAdmin ? 'app_admin_project_update' : 'app_user_project_update', ['id' => $idproject]);
|
||||
}
|
||||
}
|
@ -55,10 +55,18 @@ class Project
|
||||
#[ORM\OrderBy(['createdAt' => 'DESC'])]
|
||||
private Collection $timelines;
|
||||
|
||||
/**
|
||||
* @var Collection<int, ProjectTimeline>
|
||||
*/
|
||||
#[ORM\OneToMany(mappedBy: 'project', targetEntity: ProjectOption::class, cascade: ['remove'])]
|
||||
#[ORM\OrderBy(['title' => 'ASC'])]
|
||||
private Collection $options;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->users = new ArrayCollection();
|
||||
$this->timelines = new ArrayCollection();
|
||||
$this->options = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
@ -169,4 +177,9 @@ class Project
|
||||
{
|
||||
return $this->timelines;
|
||||
}
|
||||
|
||||
public function getOptions(): Collection
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
}
|
||||
|
81
src/Entity/ProjectOption.php
Normal file
81
src/Entity/ProjectOption.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\ProjectOptionRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: ProjectOptionRepository::class)]
|
||||
class ProjectOption
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\ManyToOne(targetEntity: Project::class, inversedBy: 'timelines')]
|
||||
#[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
|
||||
private Project $project;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private string $title;
|
||||
|
||||
#[ORM\Column(type: 'text', nullable: true)]
|
||||
private ?string $whyYes = null;
|
||||
|
||||
#[ORM\Column(type: 'text', nullable: true)]
|
||||
private ?string $whyNot = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getProject(): Project
|
||||
{
|
||||
return $this->project;
|
||||
}
|
||||
|
||||
public function setProject(Project $project): self
|
||||
{
|
||||
$this->project = $project;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function setTitle(string $title): self
|
||||
{
|
||||
$this->title = $title;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getWhyYes(): ?string
|
||||
{
|
||||
return $this->whyYes;
|
||||
}
|
||||
|
||||
public function setWhyYes(?string $whyYes): self
|
||||
{
|
||||
$this->whyYes = $whyYes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getWhyNot(): ?string
|
||||
{
|
||||
return $this->whyNot;
|
||||
}
|
||||
|
||||
public function setWhyNot(?string $whyNot): self
|
||||
{
|
||||
$this->whyNot = $whyNot;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
45
src/Form/OptionType.php
Normal file
45
src/Form/OptionType.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Form;
|
||||
|
||||
use App\Entity\ProjectOption;
|
||||
use Bnine\MdEditorBundle\Form\Type\MarkdownType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class OptionType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$builder
|
||||
->add('submit', SubmitType::class, [
|
||||
'label' => 'Valider',
|
||||
'attr' => ['class' => 'btn btn-success no-print me-1'],
|
||||
])
|
||||
|
||||
->add('title', TextType::class, [
|
||||
'label' => 'Titre',
|
||||
])
|
||||
|
||||
->add('whyYes', MarkdownType::class, [
|
||||
'label' => 'Pourquoi Voter Pour',
|
||||
'markdown_height' => 200,
|
||||
])
|
||||
|
||||
->add('whyNot', MarkdownType::class, [
|
||||
'label' => 'Pourquoi Voter Contre',
|
||||
'markdown_height' => 200,
|
||||
]);
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => ProjectOption::class,
|
||||
'mode' => 'submit',
|
||||
]);
|
||||
}
|
||||
}
|
@ -21,7 +21,7 @@ class ProjectType extends AbstractType
|
||||
$builder
|
||||
->add('submit', SubmitType::class, [
|
||||
'label' => 'Valider',
|
||||
'attr' => ['class' => 'btn btn-success no-print'],
|
||||
'attr' => ['class' => 'btn btn-success no-print me-1'],
|
||||
])
|
||||
|
||||
->add('title', TextType::class, [
|
||||
|
@ -24,7 +24,7 @@ class UserType extends AbstractType
|
||||
$builder
|
||||
->add('submit', SubmitType::class, [
|
||||
'label' => 'Valider',
|
||||
'attr' => ['class' => 'btn btn-success no-print'],
|
||||
'attr' => ['class' => 'btn btn-success no-print me-1'],
|
||||
])
|
||||
|
||||
->add('username', TextType::class, [
|
||||
|
18
src/Repository/ProjectOptionRepository.php
Normal file
18
src/Repository/ProjectOptionRepository.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\ProjectOption;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<ProjectOption>
|
||||
*/
|
||||
class ProjectOptionRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, ProjectOption::class);
|
||||
}
|
||||
}
|
@ -16,10 +16,12 @@ class ProjectVoter extends Voter
|
||||
public const DELETE = 'DELETE';
|
||||
public const MOVEDRAFT = 'MOVEDRAFT';
|
||||
public const MOVETOVOTE = 'MOVETOVOTE';
|
||||
public const MOVEVOTED = 'MOVEVOTED';
|
||||
public const MOVEARCHIVED = 'MOVEARCHIVED';
|
||||
|
||||
protected function supports(string $attribute, $subject): bool
|
||||
{
|
||||
$attributes = [self::VIEW, self::SUBMIT, self::UPDATE, self::DELETE, self::MOVEDRAFT, self::MOVETOVOTE];
|
||||
$attributes = [self::VIEW, self::SUBMIT, self::UPDATE, self::DELETE, self::MOVEDRAFT, self::MOVETOVOTE, self::MOVEVOTED, self::MOVEARCHIVED];
|
||||
|
||||
return in_array($attribute, $attributes) && $subject instanceof Project;
|
||||
}
|
||||
@ -36,22 +38,58 @@ class ProjectVoter extends Voter
|
||||
|
||||
private function canUpdate(Project $project, User $user): bool
|
||||
{
|
||||
return $user->hasRole('ROLE_ADMIN') || (Project::DRAFT === $project->getStatus() && $project->getUsers()->contains($user));
|
||||
$hasMaster = $user->hasRole('ROLE_ADMIN') || $user->hasRole('ROLE_MASTER');
|
||||
$hasUser = $project->getUsers()->contains($user);
|
||||
$hasStatus = Project::DRAFT === $project->getStatus();
|
||||
|
||||
return $hasMaster || ($hasUser && $hasStatus);
|
||||
}
|
||||
|
||||
private function canDelete(Project $project, User $user): bool
|
||||
{
|
||||
return $user->hasRole('ROLE_ADMIN') || (Project::DRAFT === $project->getStatus() && $project->getUsers()->contains($user));
|
||||
$hasMaster = $user->hasRole('ROLE_ADMIN') || $user->hasRole('ROLE_MASTER');
|
||||
$hasUser = $project->getUsers()->contains($user);
|
||||
$hasStatus = Project::DRAFT === $project->getStatus();
|
||||
|
||||
return $hasMaster || ($hasUser && $hasStatus);
|
||||
}
|
||||
|
||||
private function canMoveDraft(Project $project, User $user): bool
|
||||
{
|
||||
return $user->hasRole('ROLE_ADMIN') || (Project::TOVOTE === $project->getStatus() && $project->getUsers()->contains($user));
|
||||
$hasUser = $user->hasRole('ROLE_ADMIN') || $user->hasRole('ROLE_MASTER') || $project->getUsers()->contains($user);
|
||||
$hasStatus = Project::TOVOTE === $project->getStatus();
|
||||
|
||||
return $hasUser && $hasStatus;
|
||||
}
|
||||
|
||||
private function canMoveToVote(Project $project, User $user): bool
|
||||
{
|
||||
return $user->hasRole('ROLE_ADMIN') || (Project::DRAFT === $project->getStatus() && $project->getUsers()->contains($user));
|
||||
$hasMaster = $user->hasRole('ROLE_ADMIN') || $user->hasRole('ROLE_MASTER');
|
||||
$hasUser = $project->getUsers()->contains($user);
|
||||
if (Project::VOTED === $project->getStatus()) {
|
||||
return $hasMaster;
|
||||
} elseif (Project::DRAFT === $project->getStatus()) {
|
||||
return $hasMaster || $hasUser;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function canMoveVoted(Project $project, User $user): bool
|
||||
{
|
||||
$hasUser = $user->hasRole('ROLE_ADMIN') || $user->hasRole('ROLE_MASTER');
|
||||
$hasStatus = Project::TOVOTE === $project->getStatus() || Project::ARCHIVED === $project->getStatus();
|
||||
dump($hasStatus);
|
||||
|
||||
return $hasUser && $hasStatus;
|
||||
}
|
||||
|
||||
private function canMoveArchived(Project $project, User $user): bool
|
||||
{
|
||||
$hasUser = $user->hasRole('ROLE_ADMIN') || $user->hasRole('ROLE_MASTER');
|
||||
$hasStatus = Project::VOTED === $project->getStatus();
|
||||
|
||||
return $hasUser && $hasStatus;
|
||||
}
|
||||
|
||||
protected function voteOnAttribute(string $attribute, $project, TokenInterface $token): bool
|
||||
@ -60,6 +98,7 @@ class ProjectVoter extends Voter
|
||||
if (!$user instanceof User) {
|
||||
return false;
|
||||
}
|
||||
dump($attribute);
|
||||
|
||||
return match ($attribute) {
|
||||
self::VIEW => $this->canView($project, $user),
|
||||
@ -68,6 +107,8 @@ class ProjectVoter extends Voter
|
||||
self::DELETE => $this->canDelete($project, $user),
|
||||
self::MOVEDRAFT => $this->canMoveDraft($project, $user),
|
||||
self::MOVETOVOTE => $this->canMoveToVote($project, $user),
|
||||
self::MOVEVOTED => $this->canMoveVoted($project, $user),
|
||||
self::MOVEARCHIVED => $this->canMoveArchived($project, $user),
|
||||
default => false,
|
||||
};
|
||||
}
|
||||
|
Reference in New Issue
Block a user