diff --git a/src/Controller/GroupController.php b/src/Controller/GroupController.php index 87bf0df..be6c072 100644 --- a/src/Controller/GroupController.php +++ b/src/Controller/GroupController.php @@ -45,6 +45,7 @@ class GroupController extends AbstractController $group = new Group(); $group->addUser($this->getUser()); $group->setStatus(Group::ACTIVE); + $group->setOpen(true); $this->denyAccessUnlessGranted(GroupVoter::SUBMIT, $group); @@ -130,6 +131,25 @@ class GroupController extends AbstractController return $this->redirectToRoute($isAdmin ? 'app_admin_group' : 'app_user_group_view', ['id' => $group->getId()]); } + #[Route('/admin/group/subscribe/{id}', name: 'app_admin_group_subscribe')] + #[Route('/user/group/subscribe/{id}', name: 'app_user_group_subscribe')] + public function subscribe(int $id, Request $request, GroupRepository $groupRepository, EntityManagerInterface $em): Response + { + $group = $groupRepository->find($id); + if (!$group) { + throw new NotFoundHttpException('La ressource demandée est introuvable.'); + } + + $this->denyAccessUnlessGranted(GroupVoter::CANSUBSCRIBE, $group); + + $group->addUser($this->getUser()); + $em->flush(); + + $isAdmin = str_starts_with($request->attributes->get('_route'), 'app_admin'); + + return $this->redirectToRoute($isAdmin ? 'app_admin_group' : 'app_user_group_view', ['id' => $group->getId()]); + } + #[Route('/admin/group/delete/{id}', name: 'app_admin_group_delete')] #[Route('/user/group/delete/{id}', name: 'app_user_group_delete')] public function delete(int $id, Request $request, GroupRepository $groupRepository, EntityManagerInterface $em): Response @@ -174,6 +194,7 @@ class GroupController extends AbstractController 'routecancel' => $isAdmin ? 'app_admin_group' : 'app_home', 'routedelete' => $isAdmin ? 'app_admin_group_delete' : 'app_user_group_delete', 'routemove' => $isAdmin ? 'app_admin_group_move' : 'app_user_group_move', + 'routesubscribe' => $isAdmin ? 'app_admin_group_subscribe' : 'app_user_group_subscribe', 'group' => $group, ]); } diff --git a/src/Controller/ProjectController.php b/src/Controller/ProjectController.php index 95a255f..8514656 100644 --- a/src/Controller/ProjectController.php +++ b/src/Controller/ProjectController.php @@ -47,6 +47,7 @@ class ProjectController extends AbstractController $project = new Project(); $project->addUser($this->getUser()); $project->setStatus(Project::DRAFT); + $project->setOpen(true); $this->denyAccessUnlessGranted(ProjectVoter::SUBMIT, $project); @@ -161,6 +162,25 @@ class ProjectController extends AbstractController return $this->redirectToRoute($isAdmin ? 'app_admin_project' : 'app_user_project_view', ['id' => $project->getId()]); } + #[Route('/admin/project/subscribe/{id}', name: 'app_admin_project_subscribe')] + #[Route('/user/project/subscribe/{id}', name: 'app_user_project_subscribe')] + public function subscribe(int $id, Request $request, ProjectRepository $projectRepository, EntityManagerInterface $em): Response + { + $project = $projectRepository->find($id); + if (!$project) { + throw new NotFoundHttpException('La ressource demandée est introuvable.'); + } + + $this->denyAccessUnlessGranted(ProjectVoter::CANSUBSCRIBE, $project); + + $project->addUser($this->getUser()); + $em->flush(); + + $isAdmin = str_starts_with($request->attributes->get('_route'), 'app_admin'); + + return $this->redirectToRoute($isAdmin ? 'app_admin_project' : 'app_user_project_view', ['id' => $project->getId()]); + } + #[Route('/admin/project/delete/{id}', name: 'app_admin_project_delete')] #[Route('/user/project/delete/{id}', name: 'app_user_project_delete')] public function delete(int $id, Request $request, ProjectRepository $projectRepository, EntityManagerInterface $em): Response @@ -205,6 +225,7 @@ class ProjectController extends AbstractController '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', + 'routesubscribe' => $isAdmin ? 'app_admin_project_subscribe' : 'app_user_project_subscribe', 'project' => $project, ]); } diff --git a/src/Entity/Group.php b/src/Entity/Group.php index 41d5e2b..aca2902 100644 --- a/src/Entity/Group.php +++ b/src/Entity/Group.php @@ -29,6 +29,9 @@ class Group #[ORM\Column(type: 'text', nullable: true)] private ?string $description = null; + #[ORM\Column(type: 'boolean', nullable: false)] + private bool $open; + #[ORM\Column] private string $status; @@ -95,6 +98,18 @@ class Group return $this; } + public function isOpen(): bool + { + return $this->open; + } + + public function setOpen(bool $open): static + { + $this->open = $open; + + return $this; + } + public function getStatus(): string { return $this->status; diff --git a/src/Entity/Project.php b/src/Entity/Project.php index c18e43e..1280c27 100644 --- a/src/Entity/Project.php +++ b/src/Entity/Project.php @@ -36,6 +36,9 @@ class Project #[ORM\Column(type: 'string', length: 20)] private string $nature; + #[ORM\Column(type: 'boolean', nullable: false)] + private bool $open; + #[ORM\Column] private string $status; @@ -131,6 +134,18 @@ class Project return $this; } + public function isOpen(): bool + { + return $this->open; + } + + public function setOpen(bool $open): static + { + $this->open = $open; + + return $this; + } + public function getStatus(): string { return $this->status; diff --git a/src/Form/GroupType.php b/src/Form/GroupType.php index b8e7518..73fc3f4 100644 --- a/src/Form/GroupType.php +++ b/src/Form/GroupType.php @@ -7,6 +7,7 @@ use App\Entity\User; use Bnine\MdEditorBundle\Form\Type\MarkdownType; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\DateType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\TextareaType; @@ -38,8 +39,13 @@ class GroupType extends AbstractType 'label' => 'Résumé', ]) + ->add('open', CheckboxType::class, [ + 'label' => 'Groupe Ouvert', + 'required' => false, + ]) + ->add('users', EntityType::class, [ - 'label' => 'Propriétaires', + 'label' => 'Paticipants', 'class' => User::class, 'choice_label' => 'username', 'multiple' => true, diff --git a/src/Form/ProjectType.php b/src/Form/ProjectType.php index 95cb679..681dc88 100644 --- a/src/Form/ProjectType.php +++ b/src/Form/ProjectType.php @@ -7,6 +7,7 @@ use App\Entity\User; use Bnine\MdEditorBundle\Form\Type\MarkdownType; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\DateType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; @@ -39,6 +40,11 @@ class ProjectType extends AbstractType 'label' => 'Résumé', ]) + ->add('open', CheckboxType::class, [ + 'label' => 'Projet Ouvert', + 'required' => false, + ]) + ->add('nature', ChoiceType::class, [ 'label' => 'Nature', 'choices' => [ @@ -49,7 +55,7 @@ class ProjectType extends AbstractType ]) ->add('users', EntityType::class, [ - 'label' => 'Propriétaires', + 'label' => 'Paticipants', 'class' => User::class, 'choice_label' => 'username', 'multiple' => true, diff --git a/src/Security/GroupVoter.php b/src/Security/GroupVoter.php index ebf190a..79a8427 100644 --- a/src/Security/GroupVoter.php +++ b/src/Security/GroupVoter.php @@ -17,10 +17,11 @@ class GroupVoter extends Voter public const MOVETOACTIVE = 'MOVETOACTIVE'; public const MOVETOINACTIVE = 'MOVETOINACTIVE'; public const TOME = 'TOME'; + public const CANSUBSCRIBE = 'CANSUBSCRIBE'; protected function supports(string $attribute, $subject): bool { - $attributes = [self::VIEW, self::SUBMIT, self::UPDATE, self::DELETE, self::MOVETOACTIVE, self::MOVETOINACTIVE, self::TOME]; + $attributes = [self::VIEW, self::SUBMIT, self::UPDATE, self::DELETE, self::MOVETOACTIVE, self::MOVETOINACTIVE, self::TOME, self::CANSUBSCRIBE]; return in_array($attribute, $attributes) && $subject instanceof Group; } @@ -76,6 +77,11 @@ class GroupVoter extends Voter return $group->getUsers()->contains($user); } + private function canSubscribe(Group $group, User $user): bool + { + return $group->isOpen() && !$group->getUsers()->contains($user); + } + protected function voteOnAttribute(string $attribute, $group, TokenInterface $token): bool { $user = $token->getUser(); @@ -91,6 +97,8 @@ class GroupVoter extends Voter self::MOVETOACTIVE => $this->canMoveToActive($group, $user), self::MOVETOINACTIVE => $this->canMoveToInactive($group, $user), self::TOME => $this->toMe($group, $user), + self::CANSUBSCRIBE => $this->canSubscribe($group, $user), + default => false, }; } diff --git a/src/Security/ProjectVoter.php b/src/Security/ProjectVoter.php index cc6e6c2..03b0d50 100644 --- a/src/Security/ProjectVoter.php +++ b/src/Security/ProjectVoter.php @@ -19,10 +19,11 @@ class ProjectVoter extends Voter public const MOVEVOTED = 'MOVEVOTED'; public const MOVEARCHIVED = 'MOVEARCHIVED'; public const TOME = 'TOME'; + public const CANSUBSCRIBE = 'CANSUBSCRIBE'; protected function supports(string $attribute, $subject): bool { - $attributes = [self::VIEW, self::SUBMIT, self::UPDATE, self::DELETE, self::MOVEDRAFT, self::MOVETOVOTE, self::MOVEVOTED, self::MOVEARCHIVED, self::TOME]; + $attributes = [self::VIEW, self::SUBMIT, self::UPDATE, self::DELETE, self::MOVEDRAFT, self::MOVETOVOTE, self::MOVEVOTED, self::MOVEARCHIVED, self::TOME, self::CANSUBSCRIBE]; return in_array($attribute, $attributes) && $subject instanceof Project; } @@ -97,6 +98,11 @@ class ProjectVoter extends Voter return $project->getUsers()->contains($user); } + private function canSubscribe(Project $project, User $user): bool + { + return $project->isOpen() && !$project->getUsers()->contains($user); + } + protected function voteOnAttribute(string $attribute, $project, TokenInterface $token): bool { $user = $token->getUser(); @@ -114,6 +120,7 @@ class ProjectVoter extends Voter self::MOVEVOTED => $this->canMoveVoted($project, $user), self::MOVEARCHIVED => $this->canMoveArchived($project, $user), self::TOME => $this->toMe($project, $user), + self::CANSUBSCRIBE => $this->canSubscribe($project, $user), default => false, }; } diff --git a/templates/group/edit.html.twig b/templates/group/edit.html.twig index 99aa6d5..e024a0b 100644 --- a/templates/group/edit.html.twig +++ b/templates/group/edit.html.twig @@ -20,6 +20,7 @@
Information
{{ form_row(form.title) }} + {{ form_row(form.open) }} {{ form_row(form.dueDate) }} {{ form_row(form.users) }} {{ form_row(form.summary) }} diff --git a/templates/group/view.html.twig b/templates/group/view.html.twig index 2911e25..b51452d 100644 --- a/templates/group/view.html.twig +++ b/templates/group/view.html.twig @@ -15,6 +15,12 @@ Retour + {% if is_granted('CANSUBSCRIBE', group) %} + + Participer à ce groupe + + {% endif %} + {% if is_granted('MOVETOINACTIVE', group) and group.status=="Actif"%} Statut = Inactif @@ -39,6 +45,7 @@
Information
Titre = {{ group.title }}
+ Groupe Ouvert = {{ group.open ? "Oui" : "Non" }}
A Voter pour le = {{ group.dueDate ? group.dueDate|date("d/m/Y"):"" }}
@@ -50,6 +57,15 @@ +
+
Participants
+
+ {%for user in group.users%} + {{loop.first ? user.username : ' - '~user.username}} + {%endfor%} +
+
+ {{ render(path("bninefiles_files",{domain:'group',id:group.id, editable:0})) }}
diff --git a/templates/home/home.html.twig b/templates/home/home.html.twig index 68ce1ba..5d5e34f 100644 --- a/templates/home/home.html.twig +++ b/templates/home/home.html.twig @@ -84,7 +84,7 @@ A Voter pour le = {{ project.dueDate|date("d/m/Y") }}
{% endif %} Nature = {{ project.nature }}
- Propriétaires = + Participants = {%for user in project.users%} {{loop.first ? user.username : ' - '~user.username}} {%endfor%} diff --git a/templates/project/edit.html.twig b/templates/project/edit.html.twig index 60953df..3a132ae 100644 --- a/templates/project/edit.html.twig +++ b/templates/project/edit.html.twig @@ -21,6 +21,8 @@
Information
{{ form_row(form.title) }} + {{ form_row(form.open) }} + {{ form_row(form.nature) }} {{ form_row(form.dueDate) }} {{ form_row(form.users) }} diff --git a/templates/project/view.html.twig b/templates/project/view.html.twig index 00bc9c4..8e9ac31 100644 --- a/templates/project/view.html.twig +++ b/templates/project/view.html.twig @@ -15,6 +15,12 @@ Retour + {% if is_granted('CANSUBSCRIBE', project) %} + + Participer à ce projet + + {% endif %} + {% if is_granted('MOVETOVOTE', project) and project.status=="Brouillon"%} Statut = à Voter @@ -59,6 +65,7 @@
Information
Titre = {{ project.title }}
+ Projet Ouvert = {{ project.open ? "Oui" : "Non" }}
Nature = {{ project.nature }}
A Voter pour le = {{ project.dueDate ? project.dueDate|date("d/m/Y"):"" }}
@@ -71,6 +78,15 @@
+
+
Participants
+
+ {%for user in project.users%} + {{loop.first ? user.username : ' - '~user.username}} + {%endfor%} +
+
+ {{ render(path("bninefiles_files",{domain:'project',id:project.id, editable:0})) }}