svg
This commit is contained in:
@ -102,6 +102,26 @@ class ProjectController extends AbstractController
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/admin/project/moveto/{id}/{status}', name: 'app_admin_project_move')]
|
||||
#[Route('/user/project/moveto/{id}/{status}', name: 'app_user_project_move')]
|
||||
public function move(int $id, string $status, Request $request, ProjectRepository $projectRepository, EntityManagerInterface $em): Response
|
||||
{
|
||||
$project = $projectRepository->find($id);
|
||||
if (!$project) {
|
||||
throw new NotFoundHttpException('La ressource demandée est introuvable.');
|
||||
}
|
||||
|
||||
$attribute = constant(ProjectVoter::class.'::MOVE'.$status);
|
||||
$this->denyAccessUnlessGranted($attribute, $project);
|
||||
|
||||
$project->setStatus(constant(Project::class.'::'.$status));
|
||||
$em->flush();
|
||||
|
||||
$isAdmin = str_starts_with($request->attributes->get('_route'), 'app_admin');
|
||||
|
||||
return $this->redirectToRoute($isAdmin ? 'app_admin_project' : 'app_home');
|
||||
}
|
||||
|
||||
#[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
|
||||
@ -127,4 +147,23 @@ class ProjectController extends AbstractController
|
||||
|
||||
return $this->redirectToRoute($isAdmin ? 'app_admin_project' : 'app_home');
|
||||
}
|
||||
|
||||
#[Route('/user/project/view/{id}', name: 'app_user_project_view')]
|
||||
public function view(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::VIEW, $project);
|
||||
|
||||
return $this->render('project/view.html.twig', [
|
||||
'usemenu' => true,
|
||||
'usesidebar' => false,
|
||||
'title' => 'Projet = '.$project->getTitle(),
|
||||
'routecancel' => 'app_home',
|
||||
'project' => $project,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ class Project
|
||||
public const TOVOTE = 'A Voter';
|
||||
public const VOTED = 'Voté';
|
||||
public const ARCHIVED = 'Archivé';
|
||||
|
||||
public const NATURE_COLLECTIVE = 'Collective';
|
||||
public const NATURE_STRATEGIC = 'Stratégique';
|
||||
public const NATURE_TACTICAL = 'Tactique';
|
||||
|
@ -15,10 +15,11 @@ class ProjectVoter extends Voter
|
||||
public const UPDATE = 'UPDATE';
|
||||
public const DELETE = 'DELETE';
|
||||
public const MOVEDRAFT = 'MOVEDRAFT';
|
||||
public const MOVETOVOTE = 'MOVETOVOTE';
|
||||
|
||||
protected function supports(string $attribute, $subject): bool
|
||||
{
|
||||
$attributes = [self::VIEW, self::SUBMIT, self::UPDATE, self::DELETE, self::MOVEDRAFT];
|
||||
$attributes = [self::VIEW, self::SUBMIT, self::UPDATE, self::DELETE, self::MOVEDRAFT, self::MOVETOVOTE];
|
||||
|
||||
return in_array($attribute, $attributes) && $subject instanceof Project;
|
||||
}
|
||||
@ -48,6 +49,11 @@ class ProjectVoter extends Voter
|
||||
return $user->hasRole('ROLE_ADMIN') || (Project::TOVOTE === $project->getStatus() && $project->getUsers()->contains($user));
|
||||
}
|
||||
|
||||
private function canMoveToVote(Project $project, User $user): bool
|
||||
{
|
||||
return $user->hasRole('ROLE_ADMIN') || (Project::DRAFT === $project->getStatus() && $project->getUsers()->contains($user));
|
||||
}
|
||||
|
||||
protected function voteOnAttribute(string $attribute, $project, TokenInterface $token): bool
|
||||
{
|
||||
$user = $token->getUser();
|
||||
@ -61,6 +67,7 @@ class ProjectVoter extends Voter
|
||||
self::UPDATE => $this->canUpdate($project, $user),
|
||||
self::DELETE => $this->canDelete($project, $user),
|
||||
self::MOVEDRAFT => $this->canMoveDraft($project, $user),
|
||||
self::MOVETOVOTE => $this->canMoveToVote($project, $user),
|
||||
default => false,
|
||||
};
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
{% if is_granted('VIEW', project) %}
|
||||
<div class='card' style='width:300px; margin-right:10px;'>
|
||||
<div class='card-header d-flex justify-content-between align-items-center'>
|
||||
{{project.status}}<br>
|
||||
{{project.title}}
|
||||
|
||||
<div>
|
||||
@ -16,7 +17,7 @@
|
||||
<a href="{{ path("app_user_project_update",{id:project.id}) }}" class="btn btn-primary btn-sm"><i class="fas fa-pencil"></i></a>
|
||||
{% endif %}
|
||||
|
||||
<button type="button" class="btn btn-secondary btn-sm"><i class="fas fa-eye"></i></button>
|
||||
<a href="{{ path("app_user_project_view",{id:project.id}) }}" class="btn btn-secondary btn-sm"><i class="fas fa-eye"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class='card-body'>
|
||||
|
@ -10,6 +10,12 @@
|
||||
{{ form_widget(form.submit) }}
|
||||
<a href="{{ path(routecancel) }}" class="btn btn-secondary ms-1">Annuler</a>
|
||||
{%if mode=="update" %}
|
||||
{% if is_granted('MOVEDRAFT', project) %}
|
||||
<a href="{{ path("app_user_project_move",{id:form.vars.value.id, status:"DRAFT"}) }}" class="btn btn-primary" onclick="return confirm('Confirmez-vous le passage au vote ?')">Mettre en Brouillon</a>
|
||||
{% endif %}
|
||||
{% if is_granted('MOVETOVOTE', project) %}
|
||||
<a href="{{ path("app_user_project_move",{id:form.vars.value.id, status:"TOVOTE"}) }}" class="btn btn-primary" onclick="return confirm('Confirmez-vous le passage au vote ?')">Mettre au Vote</a>
|
||||
{% endif %}
|
||||
{% if is_granted('DELETE', project) %}
|
||||
<a href="{{ path(routedelete,{id:form.vars.value.id}) }}" class="btn btn-danger float-end" onclick="return confirm('Confirmez-vous la suppression de cet enregistrement ?')">Supprimer</a>
|
||||
{% endif %}
|
||||
|
52
templates/project/view.html.twig
Normal file
52
templates/project/view.html.twig
Normal file
@ -0,0 +1,52 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %} = {{title}}{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<h1>{{title}}</h1>
|
||||
|
||||
|
||||
<a href="{{ path(routecancel) }}" class="btn btn-secondary ms-1">Annuler</a>
|
||||
|
||||
{% if is_granted('MOVEDRAFT', project) %}
|
||||
<a href="{{ path("app_user_project_move",{id:project.id, status:"DRAFT"}) }}" class="btn btn-primary" onclick="return confirm('Confirmez-vous le passage au vote ?')">Mettre en Brouillon</a>
|
||||
{% endif %}
|
||||
{% if is_granted('MOVETOVOTE', project) %}
|
||||
<a href="{{ path("app_user_project_move",{id:project.id, status:"TOVOTE"}) }}" class="btn btn-primary" onclick="return confirm('Confirmez-vous le passage au vote ?')">Mettre au Vote</a>
|
||||
{% endif %}
|
||||
{% if is_granted('DELETE', project) %}
|
||||
<a href="{{ path(routedelete,{id:project.id}) }}" class="btn btn-danger float-end" onclick="return confirm('Confirmez-vous la suppression de cet enregistrement ?')">Supprimer</a>
|
||||
{% endif %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4 mx-auto">
|
||||
<div class="card mt-3">
|
||||
<div class="card-header">Information</div>
|
||||
<div class="card-body">
|
||||
{{ project.title }}
|
||||
{{ project.nature }}
|
||||
{{ project.summary }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ render(path("bninefiles_files",{domain:'project',id:project.id, editable:0})) }}
|
||||
|
||||
<div class="card mt-3">
|
||||
<div class="card-header">Timeline</div>
|
||||
<div class="card-body">
|
||||
{% include('project/timeline.html.twig') %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-8 mx-auto">
|
||||
<div class="card mt-3">
|
||||
<div class="card-header">Description du Projet</div>
|
||||
<div class="card-body">
|
||||
{{ project.description }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
Reference in New Issue
Block a user