diff --git a/public/assets/css/app.css b/public/assets/css/app.css index 1a699c65098a8db739ea75687e1b2784216ec320..5f3f205233ed269987e803f43addcb6b3f7c3997 100644 --- a/public/assets/css/app.css +++ b/public/assets/css/app.css @@ -148,13 +148,13 @@ table.label-table > tbody > tr > td { .text-grey { color:lightgrey; } -p:hover .fa.text-grey, h4:hover .fa.text-grey, h1:hover .fa.text-grey { +td:hover .fa.text-grey, p:hover .fa.text-grey, h4:hover .fa.text-grey, h1:hover .fa.text-grey { color: dimgrey; } .text-light-green { color: #d2e8d2; } -p:hover .fa.text-light-green, h4:hover .fa.text-light-green, h1:hover .fa.text-light-green { +td:hover .fa.text-light-green, p:hover .fa.text-light-green, h4:hover .fa.text-light-green, h1:hover .fa.text-light-green { color: limegreen; } .fa-fixed-sized { @@ -273,4 +273,11 @@ p:hover .fa.text-light-green, h4:hover .fa.text-light-green, h1:hover .fa.text-l #entryAttributes { font-size: .8rem; +} + +.comment-block { + padding: 10px; + background-color: lightyellow; + border: 1px solid lightgoldenrodyellow; + border-radius: 3px; } \ No newline at end of file diff --git a/src/Controller/EntryController.php b/src/Controller/EntryController.php index e6b4fd5a7221270227eb8bbddbc226a4cac43913..f03b557a548969c80cb5d815023c102784ddb495 100644 --- a/src/Controller/EntryController.php +++ b/src/Controller/EntryController.php @@ -7,6 +7,7 @@ use App\Entity\Label; use App\Entity\Lexicon; use App\Entity\Log; use App\Form\BlockType; +use App\Form\CommentType; use App\Form\PartOfSpeechType; use App\Form\SearchStringType; use App\Manager\LabelManager; @@ -288,4 +289,5 @@ class EntryController extends AppBaseController 'title' => "Ajouter une nature", ]); } + } diff --git a/src/Controller/LabelController.php b/src/Controller/LabelController.php index e60c9e4718e1b7ffd6397c504297e13dfdd275f6..03db8522f25bacf4d738b29e7385b5075b4bc808 100644 --- a/src/Controller/LabelController.php +++ b/src/Controller/LabelController.php @@ -52,7 +52,7 @@ class LabelController extends AppBaseController /** * @Route("/add/{masterType}/{category}", name="app_label_new", methods={"GET", "POST"}, * requirements={"category"=App\Entity\Label::REQUIREMENTS_LABEL_CATEGORY, "masterType"=App\Entity\Label::REQUIREMENTS_MASTERS_TYPES}) - * @Security("is_granted('ROLE_TEACHER')") + * @Security("is_granted('ROLE_TEACHER') or category != constant('App\\Entity\\Label::LABEL_CATEGORY_INSTITUTIONAL')") */ public function new(ManagerRegistry $doctrine, Request $request, $masterType, $category, LabelRepository $labelRepository): Response { @@ -70,7 +70,11 @@ class LabelController extends AppBaseController $label->setGroup($group); } $form = $this->createForm(LabelType::class, $label, [ - 'action' => $this->generateUrl('app_label_new', ['masterType' => $masterType, 'category' => $category]) + 'action' => $this->generateUrl('app_label_new', [ + 'masterType' => $masterType, + 'category' => $category, + 'groupId' => $request->get('groupId') + ]) ]); $form->handleRequest($request); diff --git a/src/Entity/Entry.php b/src/Entity/Entry.php index 01cfca59069d0e5b299397e98aad045c9d2c1a07..743e4d61f006d2f3f31627b2eb1a80057918fef0 100644 --- a/src/Entity/Entry.php +++ b/src/Entity/Entry.php @@ -23,6 +23,7 @@ class Entry { const ATTR_PRONUNCIATION = 'Pronunciations'; const ATTR_DEFINITION = 'Definitions'; + const ATTR_COMMENT = 'Comments'; const PART_OF_SPEECH_LIST = [ "N" => "N", diff --git a/src/Form/BlockType.php b/src/Form/BlockType.php index 82b177a0adb2b8edca9a37d8aa4841066be92c2d..b1294b1b6d9045814532ce948dec879450510666 100644 --- a/src/Form/BlockType.php +++ b/src/Form/BlockType.php @@ -17,11 +17,24 @@ use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Security\Core\Security; class BlockType extends AbstractType { + /** + * @var Security + */ + private $security; + + public function __construct(Security $security) + { + $this->security = $security; + } + public function buildForm(FormBuilderInterface $builder, array $options): void { + $user = $this->security->getUser(); + $blockCategory = $options['blockCategory']; if ($blockCategory === Entry::ATTR_PRONUNCIATION) { @@ -36,6 +49,13 @@ class BlockType extends AbstractType 'label' => false, ]) ; + } elseif ($blockCategory === Entry::ATTR_COMMENT) { + $builder + ->add('block', CommentType::class, [ + 'label' => false, + 'user' => $user->getPseudo(), + ]) + ; } else { $builder ->add('block', TextareaType::class, [ diff --git a/src/Form/CommentType.php b/src/Form/CommentType.php new file mode 100644 index 0000000000000000000000000000000000000000..b2e86751ffbecc671290ac97a4ef55f9e2dc1f88 --- /dev/null +++ b/src/Form/CommentType.php @@ -0,0 +1,48 @@ +<?php + +namespace App\Form; + +use App\Entity\Entry; +use App\Entity\Label; +use App\Entity\User; +use App\Languages\LanguagesIso; +use App\Repository\GroupRepository; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\Extension\Core\Type\DateTimeType; +use Symfony\Component\Form\Extension\Core\Type\DateType; +use Symfony\Component\Form\Extension\Core\Type\HiddenType; +use Symfony\Component\Form\Extension\Core\Type\SubmitType; +use Symfony\Component\Form\Extension\Core\Type\TextareaType; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; + +class CommentType extends AbstractType +{ + public function buildForm(FormBuilderInterface $builder, array $options): void + { + $builder + ->add('text', TextareaType::class, [ + 'label' => "Commentaire", + ]) + ->add('user', HiddenType::class, [ + 'label' => false, + 'data' => $options['user'], + ]) + ->add('date', HiddenType::class, [ + 'label' => false, + 'data' => (new \DateTime('now'))->format('d/m/Y - H:i'), + ]) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'user' => null, + 'date' => null, + ]); + } +} diff --git a/src/Manager/LabelManager.php b/src/Manager/LabelManager.php index 40f59c7523c1c3a76a0c6c5269df117e10780970..a07067bd899d48d16cacd3545e3a32fceb40d7b7 100644 --- a/src/Manager/LabelManager.php +++ b/src/Manager/LabelManager.php @@ -56,7 +56,7 @@ class LabelManager } // Retourne les labels visibles dans un lexique pour un user (pour une catégorie si renseignée) - public function getVisibleLabels(Lexicon $lexicon, User $user, $category = null) + public function getVisibleLabelsInLexicon(Lexicon $lexicon, User $user, $category = null) { if ($lexicon->isZero()) { return $this->doctrine->getRepository(Label::class)->queryVisiblesByUser($user, $category)->getQuery()->getresult(); @@ -64,6 +64,14 @@ class LabelManager 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) { diff --git a/src/Repository/LabelRepository.php b/src/Repository/LabelRepository.php index 0e5d0157fa72210df1e5f88d982cd0bcadf5c4cb..bb394282f7f5598666d6e7826501b5bd03747aef 100644 --- a/src/Repository/LabelRepository.php +++ b/src/Repository/LabelRepository.php @@ -2,6 +2,7 @@ namespace App\Repository; +use App\Entity\Entry; use App\Entity\Label; use App\Entity\Lexicon; use App\Entity\User; @@ -84,10 +85,12 @@ class LabelRepository extends ServiceEntityRepository public function getVisiblesByUserInLexicon(User $user, Lexicon $lexicon, $category = null): array { $qb = $this->createQueryBuilder('l') + ->leftJoin('l.group', 'g') + ->leftJoin('g.groupMemberships', 'gms') ->innerJoin('l.labelVisibilities', 'lv') ->andWhere('lv.user = :user') ->andWhere('lv.lexicon = :lexicon') - ->andWhere('l.category != :milestone OR l.user = :user') + ->andWhere('l.category != :milestone OR l.user = :user OR gms.user = :user') ->setParameter('user', $user) ->setParameter('milestone', Label::LABEL_CATEGORY_MILESTONE) ->setParameter('lexicon', $lexicon) @@ -113,8 +116,10 @@ class LabelRepository extends ServiceEntityRepository public function queryVisiblesByUser(User $user, $category = null) { $qb = $this->createQueryBuilder('l') + ->leftJoin('l.group', 'g') + ->leftJoin('g.groupMemberships', 'gms') ->andWhere('l.master != :personal OR l.user = :user') - ->andWhere('l.category != :milestone OR l.user = :user') + ->andWhere('l.category != :milestone OR l.user = :user OR gms.user = :user') ->andWhere('l.category IN (:commonLabelCategories)') ->setParameter('milestone', Label::LABEL_CATEGORY_MILESTONE) ->setParameter('personal', Label::MASTER_PERSONAL) diff --git a/templates/entry/_chooseLabel.html.twig b/templates/entry/_chooseLabel.html.twig index 9aae5fc0619237b30dee44609176a4dfdee35792..eaeaef2e865ba73ad86c7cf870af678bd02eaddc 100644 --- a/templates/entry/_chooseLabel.html.twig +++ b/templates/entry/_chooseLabel.html.twig @@ -34,7 +34,7 @@ {% set master = '' %} <div id="chooseLabelList"> - {% for label in label_manager.visibleLabels(lexicon, app.user, category) %} + {% for label in label_manager.visibleLabelsInLexicon(lexicon, app.user, category) %} {% if entry|default(null) %} diff --git a/templates/entry/_entryAttributes.html.twig b/templates/entry/_entryAttributes.html.twig index 91b5492cc36a0683f07d9523723d59f017a191d4..3bdb9edb7b3a11ee1836b7d413c144c3b0051fa2 100644 --- a/templates/entry/_entryAttributes.html.twig +++ b/templates/entry/_entryAttributes.html.twig @@ -1,5 +1,5 @@ <div id="entryAttributes" class="ps-5"> -{# {{ dump(entry.attributes) }}#} + {{ dump(entry.attributes) }} <h1> {{ entry }} @@ -14,20 +14,22 @@ </h4> <div class="ms-1 ps-4 mb-2"> {% for key, pronunciation in entry_manager.pronunciations(entry) %} - {######### SET KEY ##########} + {### PRONUNCIATION ######### SET KEY ##########} {% set pronunciationKey = '[Items][0][Sense][Pronunciations]['~key~']' %} {% if pronunciation.accent is defined %}{{ pronunciation.accent }} :{% endif %} {{ pronunciation.api }} + {{ _self.actions(entry, pronunciationKey, ['comment'], "", 'Comments') }} {{ _self.actions(entry, pronunciationKey, ['edit', 'delete'], '', 'Pronunciations') }} <br> + {{ _self.comments(entry, pronunciation, pronunciationKey) }} {% endfor %} </div> {% set attr = entry.attributes %} {% for key, item in attr.Items %} - {######### SET KEY ##########} + {### POS ######### SET KEY ##########} {% set itemKey = '[Items]['~key~']' %} <h4> @@ -39,7 +41,7 @@ <div class="ms-1 ps-4 left-border-blue bg-light-grey"> {% for key, definition in item.Sense.Definitions %} - {######### SET KEY ##########} + {### DEFINITIONS ######### SET KEY ##########} {% set definitionKey = itemKey~'[Sense][Definitions]['~key~']' %} <div class="mb-3"> @@ -47,17 +49,23 @@ <p class="fw-bold"> {{ loop.index }}. {{ definition.Def }} {{ _self.actions(entry, definitionKey, ['add'], "Ajouter un exemple à cette définition", 'Examples') }} + {{ _self.actions(entry, definitionKey, ['comment'], "", 'Comments') }} {{ _self.actions(entry, definitionKey, ['edit', 'delete'], '', 'Definitions') }} </p> + {{ _self.comments(entry, definition, definitionKey) }} + {% for key, example in definition.Examples|default([]) %} - {######### SET KEY ##########} + {### EXEMPLES ######### SET KEY ##########} {% set exampleKey = definitionKey~'[Examples]['~key~']' %} - <p class="fst-italic"> - {{ example }} - {{ _self.actions(entry, exampleKey, ['edit', 'delete']) }} - </p> + <p class="fst-italic"> + {{ example }} +{# {{ _self.actions(entry, exampleKey, ['comment'], "", 'Comments') }}#} + {{ _self.actions(entry, exampleKey, ['edit', 'delete']) }} + </p> + +{# {{ _self.comments(entry, example, exampleKey) }}#} {% endfor %} </div> @@ -68,6 +76,23 @@ </div> +{% macro comments(entry, parent, parentKey) %} + {% for key, comment in parent.Comments|default([]) %} + {### COMMENTAIRES ######### SET KEY ##########} + {% set commentKey = parentKey~'[Comments]['~key~']' %} + + <div class="comment-block"> + {{ comment.text|nl2br }} + <div class=" pt-2"> + <span class="fst-italic"> + {{ "Par"|trans }} {{ comment.user }} {{ "le"|trans }} {{ comment.date }} + </span> + {{ _self.actions(entry, commentKey, ['edit', 'delete'], '', 'Comments') }} + </div> + </div> + {% endfor %} +{% endmacro %} + {% macro actions(entry, key, operations, title, category) %} {% if not entry.lexicon.zero %} @@ -85,6 +110,10 @@ 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 %} + {% if 'comment' in operations %} + <a href="#" data-url="{{ path('app_entry_add_block', {id: entry.id, blockId: key, blockCategory: category}) }}" class="modal-form"><i class="fa fa-comment fa-fixed-sized text-light-green" title="{{ "Ajouter un commentaire"|trans }} {{ key }}"></i></a> + {% endif %} + {% endif %} {% endmacro %} diff --git a/templates/entry/_entryLabels.html.twig b/templates/entry/_entryLabels.html.twig index 5bf0cc03f8bac57becb0003e9e8dd94677661188..bc468c41f8972a41bfbe3c85896d0a8b6f04932e 100644 --- a/templates/entry/_entryLabels.html.twig +++ b/templates/entry/_entryLabels.html.twig @@ -4,7 +4,7 @@ <tr> {% set category = constant("App\\Entity\\Label::LABEL_CATEGORY_GENERAL") %} <td class="col-md-2 modal-form" data-url="{{ path('app_entry_choose_label', {id: entry.id, category: category}) }}"> - {% for label in entry.headword.generalLabels %} + {% for label in label_manager.entryVisibleLabels(entry, app.user, category) %} <span class="blink-target">{% include "label/_labelBadge.html.twig" %}</span> {% else %} <i class="text-grey">{{ category|trans|capitalize }} : {{ "Cliquez ici pour ajouter un label"|trans }}</i> @@ -14,7 +14,7 @@ <tr> {% set category = constant("App\\Entity\\Label::LABEL_CATEGORY_INSTITUTIONAL") %} <td class="col-md-2 modal-form" data-url="{{ path('app_entry_choose_label', {id: entry.id, category: category}) }}"> - {% for label in entry.headword.institutionalLabels %} + {% for label in label_manager.entryVisibleLabels(entry, app.user, category) %} <span class="blink-target">{% include "label/_labelBadge.html.twig" %}</span> {% else %} <i class="text-grey">{{ category|trans|capitalize }} : {{ "Cliquez ici pour ajouter un label"|trans }}</i> @@ -24,7 +24,7 @@ <tr> {% set category = constant("App\\Entity\\Label::LABEL_CATEGORY_MILESTONE") %} <td class="col-md-2 modal-form" data-url="{{ path('app_entry_choose_label', {id: entry.id, category: category}) }}"> - {% for label in entry.headword.milestoneLabels %} + {% for label in label_manager.entryVisibleLabels(entry, app.user, category) %} <span class="blink-target">{% include "label/_labelBadge.html.twig" %}</span> {% else %} <i class="text-grey">{{ category|trans|capitalize }} : {{ "Cliquez ici pour ajouter un label"|trans }}</i> diff --git a/templates/label/_labelsGeneral.html.twig b/templates/label/_labelsGeneral.html.twig index a561a7b57a3cdd90cc8609cd31f786dece1937d6..9afae4f31a1ff7504a1d2d7cbb06ef77a44e6503 100644 --- a/templates/label/_labelsGeneral.html.twig +++ b/templates/label/_labelsGeneral.html.twig @@ -19,7 +19,7 @@ <tr> <td class="d-flex justify-content-between"> <strong>{{ "Personnel"|trans }}</strong> - <a title="{{ 'Ajouter un label'|trans }}" href="#" data-url="{{ path('app_label_new', {category: category, masterType: constant("App\\Entity\\Label::MASTER_PERSONAL")}) }}" class="modal-form btn btn-dark btn-sm ms-2"><i class="bi-plus"></i></a> + <a title="{{ 'Ajouter un label'|trans }}" href="#" data-url="{{ path('app_label_new', {category: category, masterType: constant("App\\Entity\\Label::MASTER_PERSONAL")}) }}" class="modal-form ms-2"><i class="fa fa-plus-circle fa-fixed-sized text-light-green"></i></a> </td> <td colspan="{{ lexiconsNb }}"></td> </tr> @@ -37,8 +37,10 @@ {% for group in app.user.myGroups %} <tr> <td> - {# {{ "Groupe"|trans }}:#} {{ group }} - <a title="{{ 'Ajouter un label'|trans }}" href="#" data-url="{{ path('app_label_new', {groupId: group.id, category: category, masterType: constant("App\\Entity\\Label::MASTER_GROUP")}) }}" class="modal-form btn btn-dark btn-sm ms-2"><i class="bi-plus"></i></a> + <div class="d-flex justify-content-between"> + {# {{ "Groupe"|trans }}:#} <span>{{ group }}</span> + <a title="{{ 'Ajouter un label'|trans }}" href="#" data-url="{{ path('app_label_new', {groupId: group.id, category: category, masterType: constant("App\\Entity\\Label::MASTER_GROUP")}) }}" class="modal-form ms-2"><i class="fa fa-plus-circle fa-fixed-sized text-light-green"></i></a> + </div> </td> <td colspan="2"></td> </tr> @@ -51,7 +53,7 @@ <tr> <td class="d-flex justify-content-between"> <strong>{{ "Public"|trans }}</strong> - <a title="{{ 'Ajouter un label'|trans }}" href="#" data-url="{{ path('app_label_new', {category: category, masterType: constant("App\\Entity\\Label::MASTER_PUBLIC")}) }}" class="modal-form btn btn-dark btn-sm ms-2"><i class="bi-plus"></i></a> + <a title="{{ 'Ajouter un label'|trans }}" href="#" data-url="{{ path('app_label_new', {category: category, masterType: constant("App\\Entity\\Label::MASTER_PUBLIC")}) }}" class="modal-form ms-2"><i class="fa fa-plus-circle fa-fixed-sized text-light-green"></i></a> </td> <td colspan="{{ lexiconsNb }}"></td> </tr> diff --git a/templates/label/_labelsInstitutional.html.twig b/templates/label/_labelsInstitutional.html.twig index b02c1f4d3619337889327f077135de8d4576def5..ef1ceea0d432bf56b28867dd66c59abe00759a24 100644 --- a/templates/label/_labelsInstitutional.html.twig +++ b/templates/label/_labelsInstitutional.html.twig @@ -9,7 +9,7 @@ <td class="label-category">{{ "Institutionnel"|trans }}</td> <td colspan="{{ lexiconsNb }}" class="text-end"> {% if is_granted('ROLE_TEACHER') %} - <a title="{{ 'Ajouter un label'|trans }}" href="#" data-url="{{ path('app_label_new', {category: category, masterType: constant("App\\Entity\\Label::MASTER_PUBLIC")}) }}" class="modal-form btn btn-dark btn-sm ms-2"><i class="bi-plus"></i></a> + <a title="{{ 'Ajouter un label'|trans }}" href="#" data-url="{{ path('app_label_new', {category: category, masterType: constant("App\\Entity\\Label::MASTER_PUBLIC")}) }}" class="modal-form ms-2"><i class="fa fa-plus-circle fa-fixed-sized text-light-green"></i></a> {% endif %} <button class="toggle-visibility btn btn-dark btn-sm" type="button"> <i class="fa fa-exchange"></i> {{ "Visibilité"|trans }} diff --git a/templates/label/_labelsMilestone.html.twig b/templates/label/_labelsMilestone.html.twig index 8f0269ebf46b1546412aa3ac8f83508c3083d6c1..1f773fcf9e3ff8e1a77498f95d7b1f3fa2d090a6 100644 --- a/templates/label/_labelsMilestone.html.twig +++ b/templates/label/_labelsMilestone.html.twig @@ -19,7 +19,7 @@ <tr> <td class="d-flex justify-content-between"> <strong>{{ "Personnel"|trans }}</strong> - <a title="{{ 'Ajouter un label'|trans }}" href="#" data-url="{{ path('app_label_new', {category: category, masterType: constant("App\\Entity\\Label::MASTER_PERSONAL")}) }}" class="modal-form btn btn-dark btn-sm ms-2"><i class="bi-plus"></i></a> + <a title="{{ 'Ajouter un label'|trans }}" href="#" data-url="{{ path('app_label_new', {category: category, masterType: constant("App\\Entity\\Label::MASTER_PERSONAL")}) }}" class="modal-form ms-2"><i class="fa fa-plus-circle fa-fixed-sized text-light-green"></i></a> </td> <td colspan="{{ lexiconsNb }}"></td> </tr> @@ -37,8 +37,10 @@ {% for group in app.user.myGroups %} <tr> <td> - {# {{ "Groupe"|trans }}:#} {{ group }} - <a title="{{ 'Ajouter un label'|trans }}" href="#" data-url="{{ path('app_label_new', {groupId: group.id, category: category, masterType: constant("App\\Entity\\Label::MASTER_GROUP")}) }}" class="modal-form btn btn-dark btn-sm ms-2"><i class="bi-plus"></i></a> + <div class="d-flex justify-content-between"> + {# {{ "Groupe"|trans }}:#} <span>{{ group }}</span> + <a title="{{ 'Ajouter un label'|trans }}" href="#" data-url="{{ path('app_label_new', {groupId: group.id, category: category, masterType: constant("App\\Entity\\Label::MASTER_GROUP")}) }}" class="modal-form ms-2"><i class="fa fa-plus-circle fa-fixed-sized text-light-green"></i></a> + </div> </td> <td colspan="2"></td> </tr> diff --git a/translations/messages.fr.yaml b/translations/messages.fr.yaml index ddd0c16155cc4c9bc58d942530a9664cdc712bb2..5aa9135089a5e0526cb2f61047b27b2aef2a59c8 100644 --- a/translations/messages.fr.yaml +++ b/translations/messages.fr.yaml @@ -18,3 +18,4 @@ "Pronunciations": "Prononciation" "Examples": "Exemple" "PartOfSpeech": "Nature" +"Comments": "Commentaire"