Feature: [saved export] Edit and delete saved exports

This commit is contained in:
Julien Fastré 2022-11-08 19:24:22 +01:00
parent 79e9906a05
commit 43791badd5
7 changed files with 175 additions and 7 deletions

View File

@ -170,7 +170,11 @@ class ExportController extends AbstractController
return $this->redirectToRoute(
'chill_main_export_download',
['alias' => $savedExport->getExportAlias(), 'key' => $key, 'prevent_save' => true]
[
'alias' => $savedExport->getExportAlias(),
'key' => $key, 'prevent_save' => true,
'returnPath' => $this->generateUrl('chill_main_export_saved_list_my'),
]
);
}

View File

@ -16,38 +16,132 @@ use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\ExportManager;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\MainBundle\Form\SavedExportType;
use Chill\MainBundle\Repository\SavedExportRepositoryInterface;
use Chill\MainBundle\Security\Authorization\SavedExportVoter;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Templating\EngineInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use function count;
class SavedExportController
{
private EntityManagerInterface $entityManager;
private ExportManager $exportManager;
private FormFactoryInterface $formFactory;
private SavedExportRepositoryInterface $savedExportRepository;
private Security $security;
private SessionInterface $session;
private EngineInterface $templating;
private TranslatorInterface $translator;
private UrlGeneratorInterface $urlGenerator;
public function __construct(
EngineInterface $templating,
EntityManagerInterface $entityManager,
ExportManager $exportManager,
FormFactoryInterface $formBuilder,
SavedExportRepositoryInterface $savedExportRepository,
Security $security,
TranslatorInterface $translator
SessionInterface $session,
TranslatorInterface $translator,
UrlGeneratorInterface $urlGenerator
) {
$this->exportManager = $exportManager;
$this->entityManager = $entityManager;
$this->formFactory = $formBuilder;
$this->savedExportRepository = $savedExportRepository;
$this->security = $security;
$this->session = $session;
$this->templating = $templating;
$this->translator = $translator;
$this->urlGenerator = $urlGenerator;
}
/**
* @Route("/{_locale}/exports/saved/{id}/delete", name="chill_main_export_saved_delete")
*/
public function delete(SavedExport $savedExport, Request $request): Response
{
if (!$this->security->isGranted(SavedExportVoter::DELETE, $savedExport)) {
throw new AccessDeniedHttpException();
}
$form = $this->formFactory->create();
$form->add('submit', SubmitType::class, ['label' => 'Delete']);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->entityManager->remove($savedExport);
$this->entityManager->flush();
$this->session->getFlashBag()->add('success', $this->translator->trans('saved_export.Export is deleted'));
return new RedirectResponse(
$this->urlGenerator->generate('chill_main_export_saved_list_my')
);
}
return new Response(
$this->templating->render(
'@ChillMain/SavedExport/delete.html.twig',
[
'saved_export' => $savedExport,
'delete_form' => $form->createView(),
]
)
);
}
/**
* @Route("/{_locale}/exports/saved/{id}/edit", name="chill_main_export_saved_edit")
*/
public function edit(SavedExport $savedExport, Request $request): Response
{
if (!$this->security->isGranted(SavedExportVoter::EDIT, $savedExport)) {
throw new AccessDeniedHttpException();
}
$form = $this->formFactory->create(SavedExportType::class, $savedExport);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->entityManager->flush();
$this->session->getFlashBag()->add('success', $this->translator->trans('saved_export.Saved export is saved!'));
return new RedirectResponse(
$this->urlGenerator->generate('chill_main_export_saved_list_my')
);
}
return new Response(
$this->templating->render(
'@ChillMain/SavedExport/edit.html.twig',
[
'form' => $form->createView(),
]
)
);
}
/**
@ -83,6 +177,7 @@ class SavedExportController
'@ChillMain/SavedExport/index.html.twig',
[
'grouped_exports' => $exportsGrouped,
'total' => count($exports),
]
)
);

View File

@ -0,0 +1,25 @@
{% extends '@ChillMain/layout.html.twig' %}
{% block title 'saved_export.Delete saved ?'|trans %}
{% block display_content %}
<div class="col-10">
<h3>{{ saved_export.title }}</h3>
<p>{{ saved_export.description|chill_markdown_to_html }}</p>
</div>
{% endblock %}
{% block content %}
<div class="container chill-md-10">
{{ include('@ChillMain/Util/confirmation_template.html.twig',
{
'title' : 'saved_export.Delete saved ?'|trans,
'confirm_question' : 'saved_export.Are you sure you want to delete this saved ?'|trans,
'display_content' : block('display_content'),
'cancel_route' : 'chill_main_export_saved_list_my',
'cancel_parameters' : {},
'form' : delete_form
} ) }}
</div>
{% endblock %}

View File

@ -0,0 +1,21 @@
{% extends "@ChillMain/layout.html.twig" %}
{% block title %}{{ 'saved_export.Edit'|trans }}{% endblock %}
{% block content %}
<h1>{{ block('title') }}</h1>
{{ form_start(form) }}
{{ form_row(form.title) }}
{{ form_row(form.description) }}
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a href="{{ chill_return_path_or('chill_main_homepage') }}" class="btn btn-cancel">{{ 'Cancel'|trans }}</a>
</li>
<li>
<button type="submit" class="btn btn-save">{{ 'Save'|trans }}</button>
</li>
</ul>
{{ form_end(form) }}
{% endblock %}

View File

@ -8,6 +8,10 @@
<div class="container mt-4">
{% if total == 0 %}
<p class="chill-no-data-statement" >{{ 'saved_export.Any saved export'|trans }}</p>
{% endif %}
{% for group, saveds in grouped_exports %}
{% if group != '_' %}
<h2 class="display-6">{{ group }}</h2>
@ -21,8 +25,8 @@
</div>
<ul class="record_actions">
<li><a href="#" class="btn btn-delete"></a></li>
<li><a href="#" class="btn btn-edit"></a></li>
<li><a href="{{ chill_path_add_return_path('chill_main_export_saved_delete', {'id': s.saved.id }) }}" class="btn btn-delete"></a></li>
<li><a href="{{ chill_path_add_return_path('chill_main_export_saved_edit', {'id': s.saved.id }) }}" class="btn btn-edit"></a></li>
<li><a href="{{ path('chill_main_export_generate_from_saved', { id: s.saved.id }) }}" class="btn btn-action"><i class="fa fa-cog"></i></a></li>
</ul>
</div>
@ -47,8 +51,8 @@
</div>
<ul class="record_actions">
<li><a href="#" class="btn btn-delete"></a></li>
<li><a href="#" class="btn btn-edit"></a></li>
<li><a href="{{ chill_path_add_return_path('chill_main_export_saved_delete', {'id': s.saved.id }) }}" class="btn btn-delete"></a></li>
<li><a href="{{ chill_path_add_return_path('chill_main_export_saved_edit', {'id': s.saved.id }) }}" class="btn btn-edit"></a></li>
<li><a href="{{ path('chill_main_export_generate_from_saved', { id: s.saved.id }) }}" class="btn btn-action"><i class="fa fa-cog"></i></a></li>
</ul>
</div>

View File

@ -15,20 +15,33 @@ use Chill\MainBundle\Entity\SavedExport;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use UnexpectedValueException;
use function in_array;
class SavedExportVoter extends Voter
{
public const DELETE = 'CHLL_MAIN_EXPORT_SAVED_DELETE';
public const EDIT = 'CHLL_MAIN_EXPORT_SAVED_EDIT';
public const GENERATE = 'CHLL_MAIN_EXPORT_SAVED_GENERATE';
private const ALL = [
self::DELETE,
self::EDIT,
self::GENERATE,
];
protected function supports($attribute, $subject): bool
{
return $subject instanceof SavedExport && self::GENERATE === $attribute;
return $subject instanceof SavedExport && in_array($attribute, self::ALL, true);
}
protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool
{
/** @var SavedExport $subject */
switch ($attribute) {
case self::DELETE:
case self::EDIT:
case self::GENERATE:
return $subject->getUser() === $token->getUser();

View File

@ -558,5 +558,11 @@ rolling_date:
fixed_date_date: Date fixe
saved_export:
Any saved export: Aucun rapport enregistré
New: Nouveau rapport enregistré
Edit: Modifier un rapport enregistré
Delete saved ?: Supprimer un rapport enregistré ?
Are you sure you want to delete this saved ?: Êtes-vous sûr·e de vouloir supprimer ce rapport ?
My saved exports: Mes rapports enregistrés
Export is deleted: Le rapport est supprimé
Saved export is saved!: Le rapport est enregistré