svg
This commit is contained in:
@@ -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,
|
||||
]);
|
||||
}
|
||||
|
@@ -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,
|
||||
]);
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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,
|
||||
|
@@ -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,
|
||||
|
@@ -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,
|
||||
};
|
||||
}
|
||||
|
@@ -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,
|
||||
};
|
||||
}
|
||||
|
@@ -20,6 +20,7 @@
|
||||
<div class="card-header">Information</div>
|
||||
<div class="card-body">
|
||||
{{ form_row(form.title) }}
|
||||
{{ form_row(form.open) }}
|
||||
{{ form_row(form.dueDate) }}
|
||||
{{ form_row(form.users) }}
|
||||
{{ form_row(form.summary) }}
|
||||
|
@@ -15,6 +15,12 @@
|
||||
|
||||
<a href="{{ path(routecancel) }}" class="btn btn-secondary me-5">Retour</a>
|
||||
|
||||
{% if is_granted('CANSUBSCRIBE', group) %}
|
||||
<a href="{{ path(routesubscribe,{id:group.id}) }}" class="btn btn-secondary me-1" onclick="return confirm('Participer à ce groupe ?')">
|
||||
<i class="fas fa-users"></i> Participer à ce groupe
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
{% if is_granted('MOVETOINACTIVE', group) and group.status=="Actif"%}
|
||||
<a href="{{ path(routemove,{id:group.id, status:"INACTIVE"}) }}" class="btn btn-primary me-1" onclick="return confirm('Statut = Inactif ?')">
|
||||
<i class="fas fa-angle-double-right"></i> Statut = Inactif
|
||||
@@ -39,6 +45,7 @@
|
||||
<div class="card-header">Information</div>
|
||||
<div class="card-body">
|
||||
<b>Titre</b> = {{ group.title }}<br>
|
||||
<b>Groupe Ouvert</b> = {{ group.open ? "Oui" : "Non" }}<br>
|
||||
<b>A Voter pour le</b> = {{ group.dueDate ? group.dueDate|date("d/m/Y"):"" }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -50,6 +57,15 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mt-3">
|
||||
<div class="card-header">Participants</div>
|
||||
<div class="card-body">
|
||||
{%for user in group.users%}
|
||||
{{loop.first ? user.username : ' - '~user.username}}
|
||||
{%endfor%}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ render(path("bninefiles_files",{domain:'group',id:group.id, editable:0})) }}
|
||||
|
||||
<div class="card mt-3">
|
||||
|
@@ -84,7 +84,7 @@
|
||||
<b>A Voter pour le</b> = {{ project.dueDate|date("d/m/Y") }}<br>
|
||||
{% endif %}
|
||||
<b>Nature</b> = {{ project.nature }}<br>
|
||||
<b>Propriétaires</b> =
|
||||
<b>Participants</b> =
|
||||
{%for user in project.users%}
|
||||
{{loop.first ? user.username : ' - '~user.username}}
|
||||
{%endfor%}
|
||||
|
@@ -21,6 +21,8 @@
|
||||
<div class="card-header">Information</div>
|
||||
<div class="card-body">
|
||||
{{ form_row(form.title) }}
|
||||
{{ form_row(form.open) }}
|
||||
|
||||
{{ form_row(form.nature) }}
|
||||
{{ form_row(form.dueDate) }}
|
||||
{{ form_row(form.users) }}
|
||||
|
@@ -15,6 +15,12 @@
|
||||
|
||||
<a href="{{ path(routecancel) }}" class="btn btn-secondary me-5">Retour</a>
|
||||
|
||||
{% if is_granted('CANSUBSCRIBE', project) %}
|
||||
<a href="{{ path(routesubscribe,{id:project.id}) }}" class="btn btn-secondary me-1" onclick="return confirm('Participer à ce projet ?')">
|
||||
<i class="fas fa-users"></i> Participer à ce projet
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
{% if is_granted('MOVETOVOTE', project) and project.status=="Brouillon"%}
|
||||
<a href="{{ path(routemove,{id:project.id, status:"TOVOTE"}) }}" class="btn btn-primary me-1" onclick="return confirm('Statut = à Voter ?')">
|
||||
<i class="fas fa-angle-double-right"></i> Statut = à Voter
|
||||
@@ -59,6 +65,7 @@
|
||||
<div class="card-header">Information</div>
|
||||
<div class="card-body">
|
||||
<b>Titre</b> = {{ project.title }}<br>
|
||||
<b>Projet Ouvert</b> = {{ project.open ? "Oui" : "Non" }}<br>
|
||||
<b>Nature</b> = {{ project.nature }}<br>
|
||||
<b>A Voter pour le</b> = {{ project.dueDate ? project.dueDate|date("d/m/Y"):"" }}
|
||||
</div>
|
||||
@@ -71,6 +78,15 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mt-3">
|
||||
<div class="card-header">Participants</div>
|
||||
<div class="card-body">
|
||||
{%for user in project.users%}
|
||||
{{loop.first ? user.username : ' - '~user.username}}
|
||||
{%endfor%}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ render(path("bninefiles_files",{domain:'project',id:project.id, editable:0})) }}
|
||||
|
||||
<div class="card mt-3">
|
||||
|
Reference in New Issue
Block a user