Skip to content
Snippets Groups Projects
Commit 347b5997 authored by Pierre Fleutot's avatar Pierre Fleutot
Browse files

Page entrée: log spécifique lors de la modification d'une entrée. Ajout d'un bloc "historique"

parent ee6c65b3
No related branches found
No related tags found
No related merge requests found
...@@ -6,6 +6,7 @@ twig: ...@@ -6,6 +6,7 @@ twig:
label_manager: '@App\Manager\LabelManager' label_manager: '@App\Manager\LabelManager'
lexicon_manager: '@App\Manager\LexiconManager' lexicon_manager: '@App\Manager\LexiconManager'
entry_manager: '@App\Manager\EntryManager' entry_manager: '@App\Manager\EntryManager'
log_manager: '@App\Manager\LogManager'
when@test: when@test:
twig: twig:
......
...@@ -290,4 +290,11 @@ td:hover .fa.text-light-green, p:hover .fa.text-light-green, h4:hover .fa.text-l ...@@ -290,4 +290,11 @@ td:hover .fa.text-light-green, p:hover .fa.text-light-green, h4:hover .fa.text-l
.border-auto { .border-auto {
border: 2px solid rgba(0,0,0, 0.25); 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
...@@ -188,6 +188,7 @@ class EntryController extends AppBaseController ...@@ -188,6 +188,7 @@ class EntryController extends AppBaseController
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
$propertyAccessor->setValue($attributes, $blockId, $form->getData()); $propertyAccessor->setValue($attributes, $blockId, $form->getData());
$entry->setAttributes($attributes); $entry->setAttributes($attributes);
$this->addLog($entry, 'edit', $blockCategory);
$this->em->flush(); $this->em->flush();
return $this->render('closeModalAndReload.html.twig'); return $this->render('closeModalAndReload.html.twig');
...@@ -222,6 +223,7 @@ class EntryController extends AppBaseController ...@@ -222,6 +223,7 @@ class EntryController extends AppBaseController
$parentBlock[$blockCategory][] = $form->getData(); $parentBlock[$blockCategory][] = $form->getData();
$propertyAccessor->setValue($attributes, $blockId, $parentBlock); $propertyAccessor->setValue($attributes, $blockId, $parentBlock);
$entry->setAttributes($attributes); $entry->setAttributes($attributes);
$this->addLog($entry, 'add', $blockCategory);
$this->em->flush(); $this->em->flush();
return $this->render('closeModalAndReload.html.twig'); return $this->render('closeModalAndReload.html.twig');
...@@ -269,6 +271,7 @@ class EntryController extends AppBaseController ...@@ -269,6 +271,7 @@ class EntryController extends AppBaseController
] ]
]; ];
$entry->setAttributes($attributes); $entry->setAttributes($attributes);
$this->addLog($entry, 'add', Entry::ATTR_PART_OF_SPEECH);
$this->em->flush(); $this->em->flush();
return $this->render('closeModalAndReload.html.twig'); return $this->render('closeModalAndReload.html.twig');
...@@ -287,6 +290,7 @@ class EntryController extends AppBaseController ...@@ -287,6 +290,7 @@ class EntryController extends AppBaseController
*/ */
public function deleteBlock(Request $request, Entry $entry, $blockId): Response public function deleteBlock(Request $request, Entry $entry, $blockId): Response
{ {
$blockCategory = $request->get('blockCategory');
$attributes = $entry->getAttributes(); $attributes = $entry->getAttributes();
$propertyAccessor = PropertyAccess::createPropertyAccessor(); $propertyAccessor = PropertyAccess::createPropertyAccessor();
preg_match("/(.*)\[([^]]+)\]$/", $blockId, $matches); preg_match("/(.*)\[([^]]+)\]$/", $blockId, $matches);
...@@ -297,9 +301,29 @@ class EntryController extends AppBaseController ...@@ -297,9 +301,29 @@ class EntryController extends AppBaseController
unset($parentBlock[$childId]); unset($parentBlock[$childId]);
$propertyAccessor->setValue($attributes, $parentId, $parentBlock); $propertyAccessor->setValue($attributes, $parentId, $parentBlock);
$entry->setAttributes($attributes); $entry->setAttributes($attributes);
$this->addLog($entry, 'delete', $blockCategory);
$this->em->flush(); $this->em->flush();
return $this->redirectToRoute('app_entry_show', ['id' => $entry->getId()]); 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);
}
}
} }
...@@ -25,6 +25,7 @@ class Entry ...@@ -25,6 +25,7 @@ class Entry
const ATTR_DEFINITION = 'Definitions'; const ATTR_DEFINITION = 'Definitions';
const ATTR_COMMENT = 'Comments'; const ATTR_COMMENT = 'Comments';
const ATTR_EXAMPLE = 'Examples'; const ATTR_EXAMPLE = 'Examples';
const ATTR_PART_OF_SPEECH = 'PartOfSpeech';
const PART_OF_SPEECH_LIST = [ const PART_OF_SPEECH_LIST = [
"N" => "N", "N" => "N",
......
...@@ -16,6 +16,7 @@ class Log ...@@ -16,6 +16,7 @@ class Log
{ {
const CATEGORY_UPDATE_COMMENT = 'update_comment'; const CATEGORY_UPDATE_COMMENT = 'update_comment';
const CATEGORY_UPDATE_DISCUSSION = 'update_discussion'; const CATEGORY_UPDATE_DISCUSSION = 'update_discussion';
const CATEGORY_UPDATE_ENTRY = 'update_entry';
const LOG_LIST_CATEGORIES = [ const LOG_LIST_CATEGORIES = [
self::CATEGORY_UPDATE_COMMENT, self::CATEGORY_UPDATE_DISCUSSION self::CATEGORY_UPDATE_COMMENT, self::CATEGORY_UPDATE_DISCUSSION
...@@ -46,6 +47,12 @@ class Log ...@@ -46,6 +47,12 @@ class Log
*/ */
private $category; private $category;
/**
* @ORM\Column(type="string", length=80)
* @Groups({"log:read"})
*/
private $blockCategory;
/** /**
* @Groups({"log:read"}) * @Groups({"log:read"})
* @ORM\Column(type="text", nullable=true) * @ORM\Column(type="text", nullable=true)
...@@ -153,4 +160,16 @@ class Log ...@@ -153,4 +160,16 @@ class Log
return $this; return $this;
} }
public function getBlockCategory(): ?string
{
return $this->blockCategory;
}
public function setBlockCategory(string $blockCategory): self
{
$this->blockCategory = $blockCategory;
return $this;
}
} }
<?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);
}
}
...@@ -23,7 +23,8 @@ class LogRepository extends ServiceEntityRepository ...@@ -23,7 +23,8 @@ class LogRepository extends ServiceEntityRepository
public function search($filter) public function search($filter)
{ {
$qb = $this->createQueryBuilder('l'); $qb = $this->createQueryBuilder('l')
->orderBy('l.createdAt', 'DESC');
if ($filter['date'] ?? null) { if ($filter['date'] ?? null) {
$qb->andWhere('DATE(l.createdAt) = DATE(:date)') $qb->andWhere('DATE(l.createdAt) = DATE(:date)')
...@@ -55,6 +56,12 @@ class LogRepository extends ServiceEntityRepository ...@@ -55,6 +56,12 @@ class LogRepository extends ServiceEntityRepository
; ;
} }
if ($filter['limit'] ?? null) {
$qb->setMaxResults($filter['limit'])
;
}
return $qb->getQuery()->getResult(); return $qb->getQuery()->getResult();
} }
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
<h4> <h4>
{{ item.PartOfSpeech|trans }} {{ item.PartOfSpeech|trans }}
{{ _self.actions(entry, itemKey~'[Sense]', ['add'], "Ajouter une définition à cette nature", 'Definitions') }} {{ _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> </h4>
<div class="ms-1 ps-4 left-border-blue bg-light-grey"> <div class="ms-1 ps-4 left-border-blue bg-light-grey">
...@@ -108,7 +108,7 @@ ...@@ -108,7 +108,7 @@
{% endif %} {% endif %}
{% if 'delete' in operations %} {% 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> 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 %} {% endif %}
......
<ul class="nav nav-tabs mt-3"> <ul class="nav nav-tabs mt-3 justify-content-end">
{% for lexicon in app.user.myLexicons %} {% for lexicon in app.user.myLexicons %}
{% set entryWithSameHeadwordInThisLexicon = lexicon.getEntryForHeadword(entry.headword) %} {% set entryWithSameHeadwordInThisLexicon = lexicon.getEntryForHeadword(entry.headword) %}
......
...@@ -7,7 +7,8 @@ ...@@ -7,7 +7,8 @@
{% block body %} {% block body %}
<div class="row justify-content-center m-lg-5 m-sm-3"> <div class="row justify-content-center m-lg-5 m-sm-3">
<div class="col-md-12">
<div class="col">
{% if entry.lexicon.newWords %} {% if entry.lexicon.newWords %}
<h1> <h1>
...@@ -53,6 +54,16 @@ ...@@ -53,6 +54,16 @@
{% endif %} {% endif %}
</div> </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> </div>
{% endblock %} {% endblock %}
{% 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
"Your password reset request": "Réinitialisation de votre mot de passe" "Your password reset request": "Réinitialisation de votre mot de passe"
"personal" : "Personnel" "personal" : "Personnel"
"group" : "Groupe" "group" : "Groupe"
"public" : "Public" "public" : "Public"
"N": "Nom" "N": "Nom"
"V": "Verbe" "V": "Verbe"
"Interj": "Interjection" "Interj": "Interjection"
...@@ -14,6 +16,7 @@ ...@@ -14,6 +16,7 @@
"general": "général" "general": "général"
"institutional": "institutionnel" "institutional": "institutionnel"
"milestone": "échéance" "milestone": "échéance"
"Definitions": "Définition" "Definitions": "Définition"
"Pronunciations": "Prononciation" "Pronunciations": "Prononciation"
"Examples": "Exemple" "Examples": "Exemple"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment