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

Ajout Voter Entry. Page détail d'une entrée néologisme. Bouton "initialiser"...

Ajout Voter Entry. Page détail d'une entrée néologisme. Bouton "initialiser" une entrée néologisme afin de saisir la première définition. On initialise plus les nouvelles entrées avec uns structure minimale car on a pas de partOfSpeech où stocker les prononciations.
parent 2c5ce0c2
No related branches found
No related tags found
No related merge requests found
......@@ -438,13 +438,16 @@ table.label-table > tbody > tr > td {
#tabContent {
background-color: #FDF6F6;
border: 1px solid #767676;;
border: 1px solid #767676;
border-top-color: transparent;
padding: 30px;
}
#tabContent.tab-wiktionnary {
background-color: #FFE4E4;
}
#tabContent.new-words-entry {
border-top-color: #767676;
}
#tableLabels.table > tbody > tr > td {
height: 52px;
......
......@@ -347,7 +347,7 @@ class AppBaseController extends AbstractController
$entry->setHeadword($headword);
$entry->setLanguage($headword->getLanguage());
$entry->setLexicon($lexicon);
$entry = $this->initializeAttributes($entry);
$entry = $this->initializeAttributesAndCreateZeroEntry($entry);
// Gestion labels de liste : si le lexique est lié à une liste, on ajoute le label de la liste au lemme
foreach ($lexicon->getGraphyLists() as $graphyList) {
......@@ -403,27 +403,26 @@ class AppBaseController extends AbstractController
* Si le mot existe dans le wiktionnaire, on crée une entrée dans le lexique Zéro de la langue
* (Si elle n'existe pas déjà)
* et on initialise également l'entrée passée en paramètre avec ces infos.
* Sinon, on initialise l'entrée passée en paramètre avec une structure minimale presque vide
*
* @param Entry $entry
* @return Entry
* @throws \Exception
*/
public function initializeAttributes(Entry $entry)
public function initializeAttributesAndCreateZeroEntry(Entry $entry)
{
$headword = $entry->getHeadword();
$zeroEntry = $this->getOrCreateEntryInZeroLexicon($headword);
if ($zeroEntry) {
$entry->setAttributes($zeroEntry->getAttributes());
} else {
$this->initializeWithBasicAttributes($entry);
}
return $entry;
}
/**
* PLUS UTILISÉ car on ne connaît le PArt Of speech donc impossible de créer une structure minimale.
*
* On initialise l'entrée passée en paramètre avec une structure minimale presque vide
*
* @param Entry $entry
......@@ -453,10 +452,10 @@ class AppBaseController extends AbstractController
$entry->setHeadword($headword);
$entry->setLanguage($headword->getLanguage());
$entry->setLexicon($newWordsLexicon);
$this->initializeWithBasicAttributes($entry);
// $this->initializeWithBasicAttributes($entry);
$this->addLexiconLog($entry, Log::CATEGORY_ADD_ENTRY);
// On crée uen updateRequest qui permettra de voter pour l'approbation du nouveau mot
// On crée une updateRequest qui permettra de voter pour l'approbation du nouveau mot
$updateRequest = new UpdateRequest(UpdateRequest::CATEGORY_NEW_WORD_APPROVALS);
$updateRequest->setNewWordEntry($entry);
$this->em->persist($updateRequest);
......
......@@ -32,11 +32,13 @@ class EntryController extends AppBaseController
{
/**
* @Route("/{id}/show", name="app_entry_show", requirements={"id" = "\d+"})
* @Security("is_granted('LEXICON_VIEW', entry.getLexicon())")
* @Security("is_granted('ENTRY_VIEW', entry)")
*/
public function show(LabelManager $labelManager, Request $request, Entry $entry)
{
if ($entry->getLexicon()->isNewWords()) {
if (!$entry->getAttributes()) { // Néologisme non initialisé
$this->addFlash('info', sprintf("Veuillez initialiser l'entrée au préalable."));
return $this->redirectToRoute('app_lexicon_new_words', ['id' => $entry->getLexicon()->getId()]);
}
......@@ -64,7 +66,7 @@ class EntryController extends AppBaseController
* @Route("/{id}/copy/{lexiconId}", name="app_entry_copy", requirements={"id" = "\d+"})
* @ParamConverter("entry", options={"id" = "id"})
* @ParamConverter("lexicon", options={"id" = "lexiconId"})
* @Security("is_granted('LEXICON_VIEW', entry.getLexicon())")
* @Security("is_granted('ENTRY_VIEW', entry)")
* @Security("is_granted('LEXICON_EDIT', lexicon)")
*/
public function copyEntry(Request $request, Entry $entry, Lexicon $lexicon)
......@@ -100,7 +102,7 @@ class EntryController extends AppBaseController
/**
* @Route("/{id}/delete", name="app_entry_delete", requirements={"id" = "\d+"})
* @Security("is_granted('LEXICON_DELETE', entry.getLexicn())")
* @Security("is_granted('ENTRY_DELETE', entry.getLexicn())")
*/
public function deleteEntry(Request $request, Entry $entry)
{
......@@ -182,7 +184,7 @@ class EntryController extends AppBaseController
/**
* @Route("/{id}/edit-block/{blockId}", name="app_entry_edit_block", methods={"GET", "POST"})
* @Security("is_granted('LEXICON_EDIT', entry.getLexicon())")
* @Security("is_granted('ENTRY_EDIT', entry)")
*/
public function editBlock(Request $request, Entry $entry, $blockId): Response
{
......@@ -217,7 +219,7 @@ class EntryController extends AppBaseController
/**
* @Route("/{id}/add-block/{blockId}", name="app_entry_add_block", methods={"GET", "POST"})
* @Security("is_granted('LEXICON_EDIT', entry.getLexicon())")
* @Security("is_granted('ENTRY_EDIT', entry)")
*/
public function addBlock(Request $request, Entry $entry, $blockId): Response
{
......@@ -297,7 +299,7 @@ class EntryController extends AppBaseController
/**
* @Route("/{id}/add-block-pos", name="app_entry_add_block_pos", methods={"GET", "POST"})
* @Security("is_granted('LEXICON_EDIT', entry.getLexicon())")
* @Security("is_granted('ENTRY_EDIT', entry)")
*/
public function addBlockPartOfSpeech(Request $request, Entry $entry): Response
{
......@@ -343,7 +345,7 @@ class EntryController extends AppBaseController
/**
* @Route("/{id}/delete-block/{blockId}", name="app_entry_delete_block", methods={"GET", "POST"})
* @Security("is_granted('LEXICON_EDIT', entry.getLexicon())")
* @Security("is_granted('ENTRY_EDIT', entry)")
*/
public function deleteBlock(Request $request, Entry $entry, $blockId): Response
{
......@@ -385,7 +387,7 @@ class EntryController extends AppBaseController
/**
* @Route("/{id}/reorder", name="app_entry_reorder", methods={"GET"}, options={"expose" = true})
* @Security("is_granted('LEXICON_EDIT', entry.getLexicon())")
* @Security("is_granted('ENTRY_EDIT', entry)")
*/
public function reorderAttributes(Request $request, Entry $entry): Response
{
......@@ -427,4 +429,57 @@ class EntryController extends AppBaseController
array_splice($array, $toIndex, 0, $out);
}
/**
* @Route("/{id}/initialiser-nouveau-mot", name="app_entry_initialize", methods={"GET", "POST"})
* @Security("is_granted('ENTRY_VIEW', entry)")
*/
public function initializeEntry(Request $request, Entry $entry): Response
{
if ($entry->getAttributes()) {
$this->addFlash('warning', sprintf("Cette entrée est déjà initialisée"));
}
$form = $this->createForm(PartOfSpeechType::class, null, [
'action' => $this->generateUrl('app_entry_initialize', [
'id' => $entry->getId(),
]),
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$newPos = $form->get('PartOfSpeech')->getData();
$newPosId = $entry->getLanguage(). '_' . $newPos . '_balex';
$word = $entry->getHeadword()->getValue();
$attributes = [
'Headword' => $word,
'Items' => [
[
"id" => $newPosId,
"PartOfSpeech" => $newPos,
"Sense" => [
"Pronunciations" => [],
"Definitions" => [
[
'id' => $newPosId . '_Definitions_balex_0',
"Def" => $form->get('Def')->getData(),
]
]
]
]
]
];
$entry->setAttributes($attributes);
$this->addBlockLog($entry, 'add', Entry::ATTR_PART_OF_SPEECH);
$this->em->flush();
return $this->render('closeModalAndReload.html.twig');
}
return $this->render('genericModalForm.html.twig', [
'form' => $form->createView(),
'title' => "Initialisation de l'entrée",
]);
}
}
......@@ -21,6 +21,8 @@ use OpenApi\Annotations as OA;
*/
class Entry
{
use LoggableTrait;
const ATTR_PRONUNCIATION = 'Pronunciations';
const ATTR_DEFINITION = 'Definitions';
const ATTR_SUBDEFINITION = 'Subdefinitions';
......@@ -40,8 +42,6 @@ class Entry
"Prep" => "Prep",
];
use LoggableTrait;
/**
* @ORM\Id
* @ORM\GeneratedValue
......
<?php
namespace App\Security\Voter;
use App\Entity\Entry;
use App\Entity\User;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use function PHPUnit\Framework\isNan;
class EntryVoter extends Voter
{
public const VIEW = 'ENTRY_VIEW';
public const EDIT = 'ENTRY_EDIT';
public const DELETE = 'ENTRY_DELETE';
private $security;
public function __construct(Security $security)
{
$this->security = $security;
}
protected function supports(string $attribute, $subject): bool
{
return in_array($attribute, [
self::VIEW,
self::EDIT,
self::DELETE,
])
&& $subject instanceof Entry;
}
protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
{
$user = $token->getUser();
// if the user is anonymous, do not grant access
if (!$user instanceof User) {
return false;
}
switch ($attribute) {
case self::VIEW:
return $this->canView($subject, $user);
case self::EDIT:
return $this->canEdit($subject, $user);
case self::DELETE:
return $this->canDelete($subject, $user);
}
return false;
}
private function canView(Entry $entry, User $user): bool
{
if ($this->security->isGranted('LEXICON_VIEW', $entry->getLexicon())) {
return true;
}
return false;
}
private function canEdit(Entry $entry, User $user): bool
{
if (!$entry->getLexicon()->isZero() && $this->security->isGranted('LEXICON_VIEW', $entry->getLexicon())) {
return true;
}
return false;
}
private function canDelete(Entry $entry, User $user): bool
{
if (!$entry->getLexicon()->isZero() && !$entry->getLexicon()->isNewWords() && $this->security->isGranted('LEXICON_VIEW', $entry->getLexicon())) {
return true;
}
return false;
}
}
......@@ -91,15 +91,17 @@
<div class="fw-bold links-container" style="margin-bottom: 0.5rem;">
{{ loop.index }}. {{ definition.Def }}
<span class="dropdown d-inline-block">
<a href="#" class="dropdown-toggle" id="{{ definitionKey }}Btn" data-bs-toggle="dropdown" aria-expanded="false">
<i class="fa fa-plus-circle fa-fixed-sized text-light-green"></i>
</a>
<span class="dropdown-menu dropdown-inner" aria-labelledby="{{ definitionKey }}Btn">
<a href="#" data-url="{{ path('app_entry_add_block', {id: entry.id, blockId: definitionKey, blockCategory: 'Examples'}) }}" class="modal-form dropdown-item">{{ "Ajouter un exemple"|trans }}</a>
<a href="#" data-url="{{ path('app_entry_add_block', {id: entry.id, blockId: definitionKey, blockCategory: 'Subdefinitions'}) }}" class="modal-form dropdown-item">{{ "Ajouter une sous-définition"|trans }}</a>
{% if not entry.lexicon.zero %}
<span class="dropdown d-inline-block">
<a href="#" class="dropdown-toggle" id="{{ definitionKey }}Btn" data-bs-toggle="dropdown" aria-expanded="false">
<i class="fa fa-plus-circle fa-fixed-sized text-light-green"></i>
</a>
<span class="dropdown-menu dropdown-inner" aria-labelledby="{{ definitionKey }}Btn">
<a href="#" data-url="{{ path('app_entry_add_block', {id: entry.id, blockId: definitionKey, blockCategory: 'Examples'}) }}" class="modal-form dropdown-item">{{ "Ajouter un exemple"|trans }}</a>
<a href="#" data-url="{{ path('app_entry_add_block', {id: entry.id, blockId: definitionKey, blockCategory: 'Subdefinitions'}) }}" class="modal-form dropdown-item">{{ "Ajouter une sous-définition"|trans }}</a>
</span>
</span>
</span>
{% endif %}
{{ _self.actions(entry, definitionKey, ['comment'], "", 'Comments') }}
{{ _self.actions(entry, definitionKey, ['edit', 'delete'], '', 'Definitions') }}
</div>
......
......@@ -10,13 +10,10 @@
<div class="col-md-12">
{% if entry.lexicon.newWords %}
<h1>
<h1 class="mb-5">
<a href="{{ path('app_lexicon_new_words', {id: entry.lexicon.id}) }}">
{{ entry.lexicon|badgeXl }} {{ "Agora Des Néologismes"|trans }}</a>
</h1>
<h1 class="mt-5">
{{ entry|capitalize }}
</h1>
{% else %}
<h1>
{% if not entry.lexicon.zero %}
......@@ -38,14 +35,17 @@
{% if not entry.lexicon.newWords %}
{% include "entry/_lexiconsTabs.html.twig" %}
{% endif %}
<div id="tabContent" class="{{ entry.lexicon.zero ? 'tab-wiktionnary' }}">
<div id="tabContent" class="{{ entry.lexicon.zero ? 'tab-wiktionnary' }} {{ entry.lexicon.newWords ? 'new-words-entry' }}">
<div class="row d-flex align-items-end">
<div class="col-lg-6 col-md-9 col-xl-4">
{% include "entry/_entryLabels.html.twig" %}
{% if not entry.lexicon.newWords %}
<div class="row d-flex align-items-end">
<div class="col-lg-6 col-md-9 col-xl-4">
{% include "entry/_entryLabels.html.twig" %}
</div>
</div>
</div>
{% endif %}
<div class="row">
<div class="col-xl-10">
......@@ -54,7 +54,6 @@
</div>
</div>
{% endif %}
</div>
......
......@@ -10,7 +10,7 @@
{% include "flashes.html.twig" %}
<div class="alert alert-warning">{{ ("« " ~ word ~ " » est introuvable dans BaLex et dans le Wiktionnaire.<br>Souhaitez-vous l'ajouter à l'Agora des nouveax mots ?"|trans)|raw }}</div>
<div class="alert alert-warning">{{ ("« " ~ word ~ " » est introuvable dans BaLex et dans le Wiktionnaire.<br>Souhaitez-vous l'ajouter à l'Agora des néologismes ?"|trans)|raw }}</div>
<div class="row pt-3">
<div class="col-sm-4"></div>
......
......@@ -47,6 +47,7 @@
<th>
{{ macros.sorting_column_with_filter("Auteur"|trans, 'value', _context, {id: lexicon.id}) }}
</th>
<th>Définitions</th>
<th></th>
</tr>
</thead>
......@@ -62,20 +63,41 @@
<td>{{ entry.createdAt|date('d/m/Y') }}</td>
<td>{{ entry.createdBy }}</td>
<td>
<div class="d-flex justify-content-start align-items-end">
{% if entry.attributes %}
{% for pos, definitions in entry.formattedDefinitions %}
<a class="text-decoration-none text-toggle" data-bs-toggle="collapse" href="#def-{{ entry.id }}-{{ loop.index }}" role="button" aria-expanded="false" aria-controls="collapseExample">
<span class="badge bg-definition text-black"><i class="bi-caret-right-fill show-collapsed"></i><i class="bi-caret-down-fill show-expanded"></i> {{ pos }}</span>
</a>
<div class="collapse" id="def-{{ entry.id }}-{{ loop.index }}">
<div class="card card-body card-definition">
{% for definition in definitions %}
<div class="my-1">{{ loop.index }}. {{ definition }}</div>
{% endfor %}
</div>
</div>
{% endfor %}
{% endif %}
</td>
<td class="text-center">
{% if entry.attributes %}
<div><img src="{{ asset('assets/images/Ballot_box_icon_color.svg.png') }}" style="height: 30px"></div>
<div class="d-flex justify-content-start align-items-end">
<div><img src="{{ asset('assets/images/Ballot_box_icon_color.svg.png') }}" style="height: 30px"></div>
<div class="ps-2">
<div title="{{ "Approuver ce néologisme"|trans }}" class="request-votes d-flex justify-content-start">
<a href="{{ path('app_update_request_new_word_approve', {id: entry.newWordUpdateRequest.id}) }}" class="btn btn-light {{ not is_granted('CAN_APPROVE_NEW_WORD', entry.newWordUpdateRequest) ? 'disabled' }}">
<span class="text-success"><i class="fa fa-thumbs-up"></i> {{ entry.newWordUpdateRequest.votesFor|length }} / {{ entry_approval_nb }}</span>
</a>
<div class="ps-2">
<div title="{{ "Approuver ce néologisme"|trans }}" class="request-votes d-flex justify-content-start">
<a href="{{ path('app_update_request_new_word_approve', {id: entry.newWordUpdateRequest.id}) }}" class="btn btn-light {{ not is_granted('CAN_APPROVE_NEW_WORD', entry.newWordUpdateRequest) ? 'disabled' }}">
<span class="text-success"><i class="fa fa-thumbs-up"></i> {{ entry.newWordUpdateRequest.votesFor|length }} / {{ entry_approval_nb }}</span>
</a>
</div>
</div>
</div>
</div>
{% else %}
<a href="#" data-url="{{ path('app_entry_initialize', {id: entry.id}) }}" class="modal-form btn btn-dark btn-xs">{{ "Initialiser"|trans }}</a>
{% endif %}
</td>
</tr>
{% endfor %}
......
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