fix delete links in documents

This commit is contained in:
Julien Fastré 2022-03-03 13:56:26 +01:00
parent 6171b3411f
commit 6edf0bcb3b
16 changed files with 226 additions and 79 deletions

View File

@ -76,7 +76,7 @@ activity:
Insert a document: Insérer un document Insert a document: Insérer un document
Remove a document: Supprimer le document Remove a document: Supprimer le document
comment: Commentaire comment: Commentaire
No documents: Pas de documents No documents: Aucun document
#timeline #timeline
'%user% has done an %activity_type%': '%user% a effectué une activité de type "%activity_type%"' '%user% has done an %activity_type%': '%user% a effectué une activité de type "%activity_type%"'

View File

@ -21,6 +21,8 @@ use Chill\PersonBundle\Entity\AccompanyingPeriod;
use DateTime; use DateTime;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
@ -59,21 +61,37 @@ class DocumentAccompanyingCourseController extends AbstractController
} }
/** /**
* @Route("/{id}", name="accompanying_course_document_delete", methods="DELETE") * @Route("/{id}/delete", name="chill_docstore_accompanying_course_document_delete")
*/ */
public function delete(Request $request, AccompanyingPeriod $course, AccompanyingCourseDocument $document): Response public function delete(Request $request, AccompanyingPeriod $course, AccompanyingCourseDocument $document): Response
{ {
$this->denyAccessUnlessGranted(AccompanyingCourseDocumentVoter::DELETE, $document); $this->denyAccessUnlessGranted(AccompanyingCourseDocumentVoter::DELETE, $document);
if ($this->isCsrfTokenValid('delete' . $document->getId(), $request->request->get('_token'))) { $form = $this->createForm(FormType::class);
$em = $this->getDoctrine()->getManager(); $form->add('submit', SubmitType::class, ['label' => 'Delete']);
$em->remove($document);
$em->flush(); $form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->remove($document);
$this->getDoctrine()->getManager()->flush();
$this->addFlash('success', $this->translator->trans('The document is successfully removed'));
if ($request->query->has('returnPath')) {
return $this->redirect($request->query->get('returnPath'));
}
return $this->redirectToRoute('accompanying_course_document_index', ['course' => $course->getId()]);
} }
return $this->redirectToRoute( return $this->render(
'accompanying_course_document_index', 'ChillDocStoreBundle:AccompanyingCourseDocument:delete.html.twig',
['accompanyingCourse' => $course->getId()] [
'document' => $document,
'delete_form' => $form->createView(),
'accompanyingCourse' => $course,
]
); );
} }

View File

@ -14,6 +14,7 @@ namespace Chill\DocStoreBundle\Controller;
use Chill\DocStoreBundle\Entity\PersonDocument; use Chill\DocStoreBundle\Entity\PersonDocument;
use Chill\DocStoreBundle\Form\PersonDocumentType; use Chill\DocStoreBundle\Form\PersonDocumentType;
use Chill\DocStoreBundle\Repository\PersonDocumentACLAwareRepositoryInterface; use Chill\DocStoreBundle\Repository\PersonDocumentACLAwareRepositoryInterface;
use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter;
use Chill\MainBundle\Pagination\PaginatorFactory; use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person;
@ -22,6 +23,8 @@ use Chill\PersonBundle\Security\Authorization\PersonVoter;
use DateTime; use DateTime;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
@ -64,22 +67,37 @@ class DocumentPersonController extends AbstractController
} }
/** /**
* @Route("/{id}", name="person_document_delete", methods="DELETE") * @Route("/{id}/delete", name="chill_docstore_person_document_delete")
*/ */
public function delete(Request $request, Person $person, PersonDocument $document): Response public function delete(Request $request, Person $person, PersonDocument $document): Response
{ {
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); $this->denyAccessUnlessGranted(PersonDocumentVoter::DELETE, $document);
$this->denyAccessUnlessGranted('CHILL_PERSON_DOCUMENT_DELETE', $document);
if ($this->isCsrfTokenValid('delete' . $document->getId(), $request->request->get('_token'))) { $form = $this->createForm(FormType::class);
$em = $this->getDoctrine()->getManager(); $form->add('submit', SubmitType::class, ['label' => 'Delete']);
$em->remove($document);
$em->flush(); $form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->remove($document);
$this->getDoctrine()->getManager()->flush();
$this->addFlash('success', $this->translator->trans('The document is successfully removed'));
if ($request->query->has('returnPath')) {
return $this->redirect($request->query->get('returnPath'));
}
return $this->redirectToRoute('person_document_index', ['person' => $person->getId()]);
} }
return $this->redirectToRoute( return $this->render(
'person_document_index', 'ChillDocStoreBundle:PersonDocument:delete.html.twig',
['person' => $person->getId()] [
'document' => $document,
'delete_form' => $form->createView(),
'person' => $person,
]
); );
} }

View File

@ -1,5 +0,0 @@
<form method="post" action="{{ path('accompanying_course_document_delete', {'id': document.id, 'course': course.id}) }}" onsubmit="return confirm('Are you sure you want to delete this item?');">
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ document.id) }}">
<button class="btn btn-delete">{{ 'Delete' | trans }}</button>
</form>

View File

@ -0,0 +1,43 @@
{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
{% set activeRouteKey = '' %}
{% block title %}{{ 'Delete document ?' }}{% endblock %}
{% block docdescription %}
<dl class="chill_view_data">
<dt>{{ 'Title'|trans }}</dt>
<dd>{{ document.title }}</dd>
{% if document.scope is not null %}
<dt>{{ 'Scope' | trans }}</dt>
<dd>{{ document.scope.name | localize_translatable_string }}</dd>
{% endif %}
<dt>{{ 'Category'|trans }}</dt>
<dd>{{ document.category.name|localize_translatable_string }}</dd>
<dt>{{ 'Description' | trans }}</dt>
<dd>
{% if document.description is empty %}
<span class="chill-no-data-statement">{{ 'Any description'|trans }}</span>
{% else %}
<blockquote class="chill-user-quote">
{{ document.description|chill_markdown_to_html }}
</blockquote>
{% endif %}
</dd>
</dl>
{% endblock %}
{% block content %}
{{ include('@ChillMain/Util/confirmation_template.html.twig',
{
'title' : 'Delete document ?'|trans,
'display_content' : block('docdescription'),
'confirm_question' : 'Are you sure you want to remove this document ?'|trans,
'cancel_route' : 'accompanying_course_document_index',
'cancel_parameters' : {'course' : accompanyingCourse.id, 'id': document.id},
'form' : delete_form
} ) }}
{% endblock %}

View File

@ -25,8 +25,13 @@
{{ 'Back to the list' | trans }} {{ 'Back to the list' | trans }}
</a> </a>
</li> </li>
<li class="edit"> {% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_DELETE', document) %}
<button class="btn btn-edit">{{ 'Edit'|trans }}</button> <li class="delete">
<a href="{{ chill_return_path_or('chill_docstore_accompanying_course_document_delete', {'course': accompanyingCourse.id, 'id': document.id}) }}" class="btn btn-delete"></a>
</li>
{% endif %}
<li class="edit">
<button class="btn btn-edit">{{ 'Edit'|trans }}</button>
</li> </li>
</ul> </ul>

View File

@ -49,12 +49,9 @@
{{ 'Back to the list' | trans }} {{ 'Back to the list' | trans }}
</a> </a>
</li> </li>
<li> {% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_DELETE', document) %}
{{ m.download_button(document.object, document.title) }} <li class="delete">
</li> <a href="{{ chill_return_path_or('chill_docstore_accompanying_course_document_delete', {'course': accompanyingCourse.id, 'id': document.id}) }}" class="btn btn-delete"></a>
{% if chill_document_is_editable(document.object) %}
<li>
{{ document.object|chill_document_edit_button }}
</li> </li>
{% endif %} {% endif %}
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE', document) %} {% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE', document) %}
@ -63,6 +60,14 @@
class="btn btn-edit" title="{{ 'Edit attributes' | trans }}"></a> class="btn btn-edit" title="{{ 'Edit attributes' | trans }}"></a>
</li> </li>
{% endif %} {% endif %}
<li>
{{ m.download_button(document.object, document.title) }}
</li>
{% if chill_document_is_editable(document.object) %}
<li>
{{ document.object|chill_document_edit_button }}
</li>
{% endif %}
{% set workflows_frame = chill_entity_workflow_list('Chill\\DocStoreBundle\\Entity\\AccompanyingCourseDocument', document.id) %} {% set workflows_frame = chill_entity_workflow_list('Chill\\DocStoreBundle\\Entity\\AccompanyingCourseDocument', document.id) %}
{% if workflows_frame is not empty %} {% if workflows_frame is not empty %}
<li> <li>

View File

@ -44,6 +44,16 @@
</div> </div>
<ul class="item-col record_actions flex-shrink-1"> <ul class="item-col record_actions flex-shrink-1">
{% if document.course is defined %} {% if document.course is defined %}
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_DELETE', document) %}
<li class="delete">
<a href="{{ chill_return_path_or('chill_docstore_accompanying_course_document_delete', {'course': accompanyingCourse.id, 'id': document.id}) }}" class="btn btn-delete"></a>
</li>
{% endif %}
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE', document) %}
<li>
<a href="{{ path('accompanying_course_document_edit', {'course': accompanyingCourse.id, 'id': document.id }) }}" class="btn btn-update"></a>
</li>
{% endif %}
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_SEE_DETAILS', document) %} {% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_SEE_DETAILS', document) %}
<li> <li>
{{ m.download_button(document.object, document.title) }} {{ m.download_button(document.object, document.title) }}
@ -52,15 +62,20 @@
<a href="{{ chill_path_add_return_path('accompanying_course_document_show', {'course': accompanyingCourse.id, 'id': document.id}) }}" class="btn btn-show"></a> <a href="{{ chill_path_add_return_path('accompanying_course_document_show', {'course': accompanyingCourse.id, 'id': document.id}) }}" class="btn btn-show"></a>
</li> </li>
{% endif %} {% endif %}
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE', document) %}
<li>
<a href="{{ path('accompanying_course_document_edit', {'course': accompanyingCourse.id, 'id': document.id }) }}" class="btn btn-update"></a>
</li>
{% endif %}
<li> <li>
{{ chill_entity_workflow_list('Chill\\DocStoreBundle\\Entity\\AccompanyingCourseDocument', document.id) }} {{ chill_entity_workflow_list('Chill\\DocStoreBundle\\Entity\\AccompanyingCourseDocument', document.id) }}
</li> </li>
{% else %} {% else %}
{% if is_granted('CHILL_PERSON_DOCUMENT_DELETE', document) %}
<li class="delete">
<a href="{{ chill_return_path_or('chill_docstore_person_document_delete', {'person': person.id, 'id': document.id}) }}" class="btn btn-delete"></a>
</li>
{% endif %}
{% if is_granted('CHILL_PERSON_DOCUMENT_UPDATE', document) %}
<li>
<a href="{{ path('person_document_edit', {'person': person.id, 'id': document.id}) }}" class="btn btn-update"></a>
</li>
{% endif %}
{% if is_granted('CHILL_PERSON_DOCUMENT_SEE_DETAILS', document) %} {% if is_granted('CHILL_PERSON_DOCUMENT_SEE_DETAILS', document) %}
<li> <li>
{{ m.download_button(document.object, document.title) }} {{ m.download_button(document.object, document.title) }}
@ -69,13 +84,8 @@
<a href="{{ path('person_document_show', {'person': person.id, 'id': document.id}) }}" class="btn btn-show"></a> <a href="{{ path('person_document_show', {'person': person.id, 'id': document.id}) }}" class="btn btn-show"></a>
</li> </li>
{% endif %} {% endif %}
{% if is_granted('CHILL_PERSON_DOCUMENT_UPDATE', document) %}
<li>
<a href="{{ path('person_document_edit', {'person': person.id, 'id': document.id}) }}" class="btn btn-update"></a>
</li>
{% endif %}
{% endif %} {% endif %}
</ul> </ul>
</div> </div>
</div> </div>

View File

@ -0,0 +1,43 @@
{% extends "@ChillPerson/Person/layout.html.twig" %}
{% set activeRouteKey = '' %}
{% block title %}{{ 'Delete document ?' }}{% endblock %}
{% block docdescription %}
<dl class="chill_view_data">
<dt>{{ 'Title'|trans }}</dt>
<dd>{{ document.title }}</dd>
{% if document.scope is not null %}
<dt>{{ 'Scope' | trans }}</dt>
<dd>{{ document.scope.name | localize_translatable_string }}</dd>
{% endif %}
<dt>{{ 'Category'|trans }}</dt>
<dd>{{ document.category.name|localize_translatable_string }}</dd>
<dt>{{ 'Description' | trans }}</dt>
<dd>
{% if document.description is empty %}
<span class="chill-no-data-statement">{{ 'Any description'|trans }}</span>
{% else %}
<blockquote class="chill-user-quote">
{{ document.description|chill_markdown_to_html }}
</blockquote>
{% endif %}
</dd>
</dl>
{% endblock %}
{% block personcontent %}
{{ include('@ChillMain/Util/confirmation_template.html.twig',
{
'title' : 'Delete document ?'|trans,
'display_content' : block('docdescription'),
'confirm_question' : 'Are you sure you want to remove this document ?'|trans,
'cancel_route' : 'person_document_index',
'cancel_parameters' : {'person' : person.id, 'id': document.id},
'form' : delete_form
} ) }}
{% endblock %}

View File

@ -36,20 +36,20 @@
{{ form_row(form.description) }} {{ form_row(form.description) }}
{{ form_row(form.object, { 'label': 'Document', 'existing': document.object }) }} {{ form_row(form.object, { 'label': 'Document', 'existing': document.object }) }}
<ul class="record_actions"> <ul class="record_actions sticky-form-buttons">
<li class="cancel"> <li class="cancel">
<a href="{{ path('person_document_index', {'person': person.id}) }}" class="btn btn-cancel"> <a href="{{ chill_return_path_or('person_document_index', {'person': person.id}) }}" class="btn btn-cancel">
{{ 'Back to the list' | trans }} {{ 'Back to the list' | trans }}
</a> </a>
</li> </li>
{% if is_granted('CHILL_PERSON_DOCUMENT_DELETE', document) %}
<li class="delete">
<a href="{{ chill_return_path_or('chill_docstore_person_document_delete', {'person': person.id, 'id': document.id}) }}" class="btn btn-delete"></a>
</li>
{% endif %}
<li class="edit"> <li class="edit">
<button class="btn btn-edit">{{ 'Edit'|trans }}</button> <button class="btn btn-edit">{{ 'Edit'|trans }}</button>
</li> </li>
{# {% if is_granted('CHILL_PERSON_DOCUMENT_DELETE', document) %}
<li class="delete">
{{ include('ChillDocStoreBundle:PersonDocument:_delete_form.html.twig') }}
</li>
{% endif %} #}
</ul> </ul>
{{ form_end(form) }} {{ form_end(form) }}

View File

@ -40,9 +40,9 @@
{{ form_row(form.description) }} {{ form_row(form.description) }}
{{ form_row(form.object, { 'label': 'Document', 'existing': document.object }) }} {{ form_row(form.object, { 'label': 'Document', 'existing': document.object }) }}
<ul class="record_actions"> <ul class="record_actions sticky-form-buttons">
<li class="cancel"> <li class="cancel">
<a href="{{ path('person_document_index', {'person': person.id}) }}" class="btn btn-cancel"> <a href="{{ chill_return_path_or('person_document_index', {'person': person.id}) }}" class="btn btn-cancel">
{{ 'Back to the list' | trans }} {{ 'Back to the list' | trans }}
</a> </a>
</li> </li>

View File

@ -64,13 +64,9 @@
</a> </a>
</li> </li>
<li> {% if is_granted('CHILL_PERSON_DOCUMENT_DELETE', document) %}
{{ m.download_button(document.object, document.title) }} <li class="delete">
</li> <a href="{{ chill_return_path_or('chill_docstore_person_document_delete', {'person': person.id, 'id': document.id}) }}" class="btn btn-delete"></a>
{% if chill_document_is_editable(document.object) %}
<li>
{{ document.object|chill_document_edit_button }}
</li> </li>
{% endif %} {% endif %}
@ -82,5 +78,15 @@
</li> </li>
{% endif %} {% endif %}
{# {{ include('ChillDocStoreBundle:PersonDocument:_delete_form.html.twig') }} #} <li>
{{ m.download_button(document.object, document.title) }}
</li>
{% if chill_document_is_editable(document.object) %}
<li>
{{ document.object|chill_document_edit_button }}
</li>
{% endif %}
{# {{ include('ChillDocStoreBundle:PersonDocument:_delete_form.html.twig') }} #}
{% endblock %} {% endblock %}

View File

@ -19,6 +19,12 @@ The document is successfully registered: Le document est enregistré
The document is successfully updated: Le document est mis à jour The document is successfully updated: Le document est mis à jour
Any description: Aucune description Any description: Aucune description
# delete
Delete document ?: Supprimer le document ?
Are you sure you want to remove this document ?: Êtes-vous sûr·e de vouloir supprimer ce document ?
The document is successfully removed: Le document a été supprimé
# dropzone upload # dropzone upload
File too big: Fichier trop volumineux File too big: Fichier trop volumineux
Drop your file or click here: Cliquez ici ou faites glissez votre nouveau fichier dans cette zone Drop your file or click here: Cliquez ici ou faites glissez votre nouveau fichier dans cette zone

View File

@ -18,8 +18,8 @@ use Chill\PersonBundle\Repository\ResidentialAddressRepository;
use Chill\ThirdPartyBundle\Entity\ThirdParty; use Chill\ThirdPartyBundle\Entity\ThirdParty;
use DateTimeImmutable; use DateTimeImmutable;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Serializer\Annotation\Context; use Symfony\Component\Serializer\Annotation\Context;
use Symfony\Component\Serializer\Annotation\Groups;
/** /**
* @ORM\Entity(repositoryClass=ResidentialAddressRepository::class) * @ORM\Entity(repositoryClass=ResidentialAddressRepository::class)
@ -49,7 +49,7 @@ class ResidentialAddress
* @ORM\ManyToOne(targetEntity=Person::class) * @ORM\ManyToOne(targetEntity=Person::class)
* @ORM\JoinColumn(nullable=true) * @ORM\JoinColumn(nullable=true)
* @Groups({"read"}) * @Groups({"read"})
* @Context(normalizationContext={"groups"={"minimal"}}) * @Context(normalizationContext={"groups": {"minimal"}})
*/ */
private ?Person $hostPerson = null; private ?Person $hostPerson = null;

View File

@ -32,26 +32,11 @@ class ResidentialAddressRepository extends ServiceEntityRepository
parent::__construct($registry, ResidentialAddress::class); parent::__construct($registry, ResidentialAddress::class);
} }
/**
* @param Person $person
* @param DateTimeImmutable|null $at
* @return array|ResidentialAddress[]|null
*/
public function findCurrentResidentialAddressByPerson(Person $person, ?DateTimeImmutable $at = null): array
{
return $this->buildQueryFindCurrentResidentialAddresses($person, $at)
->select('ra')
->getQuery()
->getResult();
}
public function buildQueryFindCurrentResidentialAddresses(Person $person, ?DateTimeImmutable $at = null): QueryBuilder public function buildQueryFindCurrentResidentialAddresses(Person $person, ?DateTimeImmutable $at = null): QueryBuilder
{ {
$date = null === $at ? new DateTimeImmutable('today') : $at; $date = null === $at ? new DateTimeImmutable('today') : $at;
$qb = $this->createQueryBuilder('ra'); $qb = $this->createQueryBuilder('ra');
$dateFilter = $qb->expr()->andX( $dateFilter = $qb->expr()->andX(
$qb->expr()->lte('ra.startDate', ':dateIn'), $qb->expr()->lte('ra.startDate', ':dateIn'),
$qb->expr()->orX( $qb->expr()->orX(
@ -69,6 +54,17 @@ class ResidentialAddressRepository extends ServiceEntityRepository
return $qb; return $qb;
} }
/**
* @return array|ResidentialAddress[]|null
*/
public function findCurrentResidentialAddressByPerson(Person $person, ?DateTimeImmutable $at = null): array
{
return $this->buildQueryFindCurrentResidentialAddresses($person, $at)
->select('ra')
->getQuery()
->getResult();
}
// /** // /**
// * @return ResidentialAddress[] Returns an array of ResidentialAddress objects // * @return ResidentialAddress[] Returns an array of ResidentialAddress objects
// */ // */

View File

@ -31,6 +31,8 @@ use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait; use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\ObjectToPopulateTrait; use Symfony\Component\Serializer\Normalizer\ObjectToPopulateTrait;
use function array_key_exists; use function array_key_exists;
use function count;
use function in_array;
/** /**
* Serialize a Person entity. * Serialize a Person entity.
@ -207,8 +209,8 @@ class PersonJsonNormalizer implements DenormalizerAwareInterface, NormalizerAwar
'gender' => $person->getGender(), 'gender' => $person->getGender(),
]; ];
if (in_array("minimal", $groups) && 1 === count($groups)) { if (in_array('minimal', $groups, true) && 1 === count($groups)) {
return $data; return $data;
} }
return array_merge($data, [ return array_merge($data, [