From 347b5997357fc76294cd9115facfa7a90d4ca511 Mon Sep 17 00:00:00 2001 From: pfleu <fleutotp@gmail.com> Date: Sun, 28 May 2023 23:16:11 +0200 Subject: [PATCH] =?UTF-8?q?Page=20entr=C3=A9e:=20log=20sp=C3=A9cifique=20l?= =?UTF-8?q?ors=20de=20la=20modification=20d'une=20entr=C3=A9e.=20Ajout=20d?= =?UTF-8?q?'un=20bloc=20"historique"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/packages/twig.yaml | 1 + public/assets/css/app.css | 7 ++ src/Controller/EntryController.php | 24 +++++++ src/Entity/Entry.php | 1 + src/Entity/Log.php | 19 ++++++ src/Manager/LogManager.php | 76 ++++++++++++++++++++++ src/Repository/LogRepository.php | 9 ++- templates/entry/_entryAttributes.html.twig | 4 +- templates/entry/_lexiconsTabs.html.twig | 2 +- templates/entry/show.html.twig | 13 +++- templates/log/_formattedLog.html.twig | 11 ++++ translations/messages.fr.yaml | 3 + 12 files changed, 165 insertions(+), 5 deletions(-) create mode 100644 src/Manager/LogManager.php create mode 100644 templates/log/_formattedLog.html.twig diff --git a/config/packages/twig.yaml b/config/packages/twig.yaml index b2d93a2..d25a41f 100644 --- a/config/packages/twig.yaml +++ b/config/packages/twig.yaml @@ -6,6 +6,7 @@ twig: label_manager: '@App\Manager\LabelManager' lexicon_manager: '@App\Manager\LexiconManager' entry_manager: '@App\Manager\EntryManager' + log_manager: '@App\Manager\LogManager' when@test: twig: diff --git a/public/assets/css/app.css b/public/assets/css/app.css index 021f16e..d4507e8 100644 --- a/public/assets/css/app.css +++ b/public/assets/css/app.css @@ -290,4 +290,11 @@ td:hover .fa.text-light-green, p:hover .fa.text-light-green, h4:hover .fa.text-l .border-auto { border: 2px solid rgba(0,0,0, 0.25); +} + +.grey-panel { + background-color: darkgrey; + border: 2px solid black; + font-size: 0.8rem; + padding: 20px; } \ No newline at end of file diff --git a/src/Controller/EntryController.php b/src/Controller/EntryController.php index 9d49862..99749e5 100644 --- a/src/Controller/EntryController.php +++ b/src/Controller/EntryController.php @@ -188,6 +188,7 @@ class EntryController extends AppBaseController if ($form->isSubmitted() && $form->isValid()) { $propertyAccessor->setValue($attributes, $blockId, $form->getData()); $entry->setAttributes($attributes); + $this->addLog($entry, 'edit', $blockCategory); $this->em->flush(); return $this->render('closeModalAndReload.html.twig'); @@ -222,6 +223,7 @@ class EntryController extends AppBaseController $parentBlock[$blockCategory][] = $form->getData(); $propertyAccessor->setValue($attributes, $blockId, $parentBlock); $entry->setAttributes($attributes); + $this->addLog($entry, 'add', $blockCategory); $this->em->flush(); return $this->render('closeModalAndReload.html.twig'); @@ -269,6 +271,7 @@ class EntryController extends AppBaseController ] ]; $entry->setAttributes($attributes); + $this->addLog($entry, 'add', Entry::ATTR_PART_OF_SPEECH); $this->em->flush(); return $this->render('closeModalAndReload.html.twig'); @@ -287,6 +290,7 @@ class EntryController extends AppBaseController */ public function deleteBlock(Request $request, Entry $entry, $blockId): Response { + $blockCategory = $request->get('blockCategory'); $attributes = $entry->getAttributes(); $propertyAccessor = PropertyAccess::createPropertyAccessor(); preg_match("/(.*)\[([^]]+)\]$/", $blockId, $matches); @@ -297,9 +301,29 @@ class EntryController extends AppBaseController unset($parentBlock[$childId]); $propertyAccessor->setValue($attributes, $parentId, $parentBlock); $entry->setAttributes($attributes); + $this->addLog($entry, 'delete', $blockCategory); $this->em->flush(); return $this->redirectToRoute('app_entry_show', ['id' => $entry->getId()]); } + public function addLog(Entry $entry, $type, $blockCategory) + { + if (in_array($blockCategory, [ + Entry::ATTR_DEFINITION, + Entry::ATTR_EXAMPLE, + Entry::ATTR_PRONUNCIATION, + Entry::ATTR_PART_OF_SPEECH, + ])) { + + $log = new Log(); + $log->setCreatedBy($this->getUser()); + $log->setContent($type); + $log->setCategory(Log::CATEGORY_UPDATE_ENTRY); + $log->setBlockCategory($blockCategory); + + $entry->addLog($log); + } + } + } diff --git a/src/Entity/Entry.php b/src/Entity/Entry.php index 5442bfa..ab772bc 100644 --- a/src/Entity/Entry.php +++ b/src/Entity/Entry.php @@ -25,6 +25,7 @@ class Entry const ATTR_DEFINITION = 'Definitions'; const ATTR_COMMENT = 'Comments'; const ATTR_EXAMPLE = 'Examples'; + const ATTR_PART_OF_SPEECH = 'PartOfSpeech'; const PART_OF_SPEECH_LIST = [ "N" => "N", diff --git a/src/Entity/Log.php b/src/Entity/Log.php index 6ca7020..49d1015 100644 --- a/src/Entity/Log.php +++ b/src/Entity/Log.php @@ -16,6 +16,7 @@ class Log { const CATEGORY_UPDATE_COMMENT = 'update_comment'; const CATEGORY_UPDATE_DISCUSSION = 'update_discussion'; + const CATEGORY_UPDATE_ENTRY = 'update_entry'; const LOG_LIST_CATEGORIES = [ self::CATEGORY_UPDATE_COMMENT, self::CATEGORY_UPDATE_DISCUSSION @@ -46,6 +47,12 @@ class Log */ private $category; + /** + * @ORM\Column(type="string", length=80) + * @Groups({"log:read"}) + */ + private $blockCategory; + /** * @Groups({"log:read"}) * @ORM\Column(type="text", nullable=true) @@ -153,4 +160,16 @@ class Log return $this; } + + public function getBlockCategory(): ?string + { + return $this->blockCategory; + } + + public function setBlockCategory(string $blockCategory): self + { + $this->blockCategory = $blockCategory; + + return $this; + } } diff --git a/src/Manager/LogManager.php b/src/Manager/LogManager.php new file mode 100644 index 0000000..a04750d --- /dev/null +++ b/src/Manager/LogManager.php @@ -0,0 +1,76 @@ +<?php + +namespace App\Manager; + +use App\Entity\Entry; +use App\Entity\Group; +use App\Entity\Headword; +use App\Entity\Label; +use App\Entity\LabelVisibility; +use App\Entity\Lexicon; +use App\Entity\Log; +use App\Entity\User; +use App\Languages\LanguagesIso; +use Doctrine\Persistence\ManagerRegistry; +use JsonSchema\Validator; +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Serializer\SerializerAwareInterface; +use Symfony\Component\Serializer\SerializerInterface; + +class LogManager +{ + /** + * @var ManagerRegistry + */ + protected $doctrine; + + public function __construct(ManagerRegistry $doctrine) + { + $this->doctrine = $doctrine; + } + + + // Retourne les 5 derniers logs visibles par un user classés par date de création DESC + public function getLastLogsForEntry(Entry $entry, User $user) + { + return $this->doctrine->getRepository(Log::class)->search([ + 'user' => $user, + 'entry' => $entry, + 'limit' => 5, + ]); + } + + // Retourne les logs visibles dans un lexique pour un user (pour une catégorie si renseignée) + public function getVisibleLabelsInLexicon(Lexicon $lexicon, User $user, $category = null) + { + if ($lexicon->isZero()) { + return $this->doctrine->getRepository(Label::class)->queryVisiblesByUser($user, $category)->getQuery()->getresult(); + } + return $this->doctrine->getRepository(Label::class)->getVisiblesByUserInLexicon($user, $lexicon, $category); + } + + // Retourne les labels de l'entrée visibles pour un user (en fonction de leur visibilité dans le lexique et des permissions si non public) (pour une catégorie si renseignée) + public function getEntryVisibleLabels(Entry $entry, User $user, $category = null) + { + $labelsVisiblesInLexicon = $this->getVisibleLabelsInLexicon($entry->getLexicon(), $user, $category); + + return array_intersect($entry->getHeadword()->getLabelsForCategory($category), $labelsVisiblesInLexicon); + } + + public function filter($filter) + { + if ($this->searchString) { + $filter['searchString'] = $this->searchString; + } + return $this->doctrine->getRepository(Label::class)->filter($filter); + } + + // Retourne le nb total de mot-vedettes portant le label + // Si $user est renseigné, Retourne le nb total de mot-vedettes portant le label ayant au moins une entrée dans un lexique de l'utilisateur + public function getHeadwordsNbWithLabel(Label $label, User $user = null) + { + return $this->doctrine->getRepository(Headword::class)->countHavingLabel($label, $user); + } +} diff --git a/src/Repository/LogRepository.php b/src/Repository/LogRepository.php index 9b2b564..cfcb183 100644 --- a/src/Repository/LogRepository.php +++ b/src/Repository/LogRepository.php @@ -23,7 +23,8 @@ class LogRepository extends ServiceEntityRepository public function search($filter) { - $qb = $this->createQueryBuilder('l'); + $qb = $this->createQueryBuilder('l') + ->orderBy('l.createdAt', 'DESC'); if ($filter['date'] ?? null) { $qb->andWhere('DATE(l.createdAt) = DATE(:date)') @@ -55,6 +56,12 @@ class LogRepository extends ServiceEntityRepository ; } + if ($filter['limit'] ?? null) { + $qb->setMaxResults($filter['limit']) + ; + } + + return $qb->getQuery()->getResult(); } diff --git a/templates/entry/_entryAttributes.html.twig b/templates/entry/_entryAttributes.html.twig index c10b388..34af44a 100644 --- a/templates/entry/_entryAttributes.html.twig +++ b/templates/entry/_entryAttributes.html.twig @@ -35,7 +35,7 @@ <h4> {{ item.PartOfSpeech|trans }} {{ _self.actions(entry, itemKey~'[Sense]', ['add'], "Ajouter une définition à cette nature", 'Definitions') }} - {{ _self.actions(entry, itemKey, ['delete']) }} + {{ _self.actions(entry, itemKey, ['delete'], '', 'Definitions') }} </h4> <div class="ms-1 ps-4 left-border-blue bg-light-grey"> @@ -108,7 +108,7 @@ {% endif %} {% if 'delete' in operations %} - <a href="#" data-href="{{ path('app_entry_delete_block', {id: entry.id, blockId: key}) }}" + <a href="#" data-href="{{ path('app_entry_delete_block', {id: entry.id, blockId: key, blockCategory: category}) }}" data-confirm="{{ "Confirmer la suppression ?"|trans }}" data-bs-toggle="modal" data-bs-target="#confirm-dialog"><i class="fa fa-trash fa-fixed-sized text-grey" title="{{ key }}"></i></a> {% endif %} diff --git a/templates/entry/_lexiconsTabs.html.twig b/templates/entry/_lexiconsTabs.html.twig index e83979d..ebefbdf 100644 --- a/templates/entry/_lexiconsTabs.html.twig +++ b/templates/entry/_lexiconsTabs.html.twig @@ -1,4 +1,4 @@ -<ul class="nav nav-tabs mt-3"> +<ul class="nav nav-tabs mt-3 justify-content-end"> {% for lexicon in app.user.myLexicons %} {% set entryWithSameHeadwordInThisLexicon = lexicon.getEntryForHeadword(entry.headword) %} diff --git a/templates/entry/show.html.twig b/templates/entry/show.html.twig index 0cbc9ac..cb5ed87 100644 --- a/templates/entry/show.html.twig +++ b/templates/entry/show.html.twig @@ -7,7 +7,8 @@ {% block body %} <div class="row justify-content-center m-lg-5 m-sm-3"> - <div class="col-md-12"> + + <div class="col"> {% if entry.lexicon.newWords %} <h1> @@ -53,6 +54,16 @@ {% endif %} </div> + + <div class="col-3 align-self-end"> + <div id="history" class="grey-panel"> + <h5>{{ "Historique des modifications"|trans }}</h5> + {% for log in log_manager.lastLogsForEntry(entry, app.user) %} + <p>{% include "log/_formattedLog.html.twig" %}</p> + {% endfor %} + </div> + </div> + </div> {% endblock %} diff --git a/templates/log/_formattedLog.html.twig b/templates/log/_formattedLog.html.twig new file mode 100644 index 0000000..e1369a5 --- /dev/null +++ b/templates/log/_formattedLog.html.twig @@ -0,0 +1,11 @@ +{% if log.category == constant('App\\Entity\\Log::CATEGORY_UPDATE_ENTRY') %} + + {{ log.createdAt|date('d/m/Y') }} : + {{ log.createdBy }} + {% if log.content == 'add' %}{{ 'a ajouté'|trans }}{% endif %} + {% if log.content == 'edit' %}{{ 'a modifié'|trans }}{% endif %} + {% if log.content == 'add' %}{{ 'a supprimé'|trans }}{% endif %} + {{ 'un bloc de type'|trans }} + {{ log.blockCategory }} + +{% endif %} \ No newline at end of file diff --git a/translations/messages.fr.yaml b/translations/messages.fr.yaml index 5aa9135..d690e39 100644 --- a/translations/messages.fr.yaml +++ b/translations/messages.fr.yaml @@ -1,7 +1,9 @@ "Your password reset request": "Réinitialisation de votre mot de passe" + "personal" : "Personnel" "group" : "Groupe" "public" : "Public" + "N": "Nom" "V": "Verbe" "Interj": "Interjection" @@ -14,6 +16,7 @@ "general": "général" "institutional": "institutionnel" "milestone": "échéance" + "Definitions": "Définition" "Pronunciations": "Prononciation" "Examples": "Exemple" -- GitLab