From 284ba6b14bfd2f392856de6136647217b2d09e4f Mon Sep 17 00:00:00 2001 From: Stakovicz Date: Sun, 28 Dec 2025 16:33:37 +0100 Subject: [PATCH 1/3] =?UTF-8?q?Refonte=20-=20=C3=89v=C3=A9nements=20>=20Co?= =?UTF-8?q?nf=C3=A9rences=20-=20CRUD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/config/packages/backoffice_menu.yaml | 4 +- app/config/routing/admin_talk.yml | 16 +++ .../AppBundle/Controller/Admin/HomeAction.php | 2 +- .../Controller/Admin/Talk/AddAction.php | 51 +++++++++ .../Controller/Admin/Talk/DeleteAction.php | 35 ++++++ .../Controller/Admin/Talk/EditAction.php | 62 ++++++++++ .../Controller/Admin/Talk/IndexAction.php | 9 -- .../Admin/Talk/UpdateIndexationAction.php | 2 +- .../AppBundle/Event/Form/TalkAdminType.php | 107 ++++++++++++++++++ .../Event/Model/Repository/TalkRepository.php | 8 ++ .../Repository/TalkToSpeakersRepository.php | 2 +- sources/AppBundle/Event/Model/Talk.php | 23 +++- sources/AppBundle/Slack/MessageFactory.php | 4 +- templates/admin/speaker/edit.html.twig | 2 +- templates/admin/speaker/list.html.twig | 2 +- templates/admin/talk/add.html.twig | 11 ++ templates/admin/talk/edit.html.twig | 15 +++ templates/admin/talk/form.html.twig | 45 ++++++++ templates/admin/talk/index.html.twig | 8 +- .../features/Admin/Events/Conferences.feature | 35 +++--- 20 files changed, 401 insertions(+), 42 deletions(-) create mode 100644 sources/AppBundle/Controller/Admin/Talk/AddAction.php create mode 100644 sources/AppBundle/Controller/Admin/Talk/DeleteAction.php create mode 100644 sources/AppBundle/Controller/Admin/Talk/EditAction.php create mode 100644 sources/AppBundle/Event/Form/TalkAdminType.php create mode 100644 templates/admin/talk/add.html.twig create mode 100644 templates/admin/talk/edit.html.twig create mode 100644 templates/admin/talk/form.html.twig diff --git a/app/config/packages/backoffice_menu.yaml b/app/config/packages/backoffice_menu.yaml index a3d7edb6e..7a53bbcf9 100644 --- a/app/config/packages/backoffice_menu.yaml +++ b/app/config/packages/backoffice_menu.yaml @@ -157,12 +157,14 @@ parameters: forum_facturation: nom: "Factures d'évènement" niveau: 'ROLE_ADMIN' - forum_sessions: + talks: nom: 'Conférences' niveau: 'ROLE_FORUM' url: '/admin/talk/' extra_routes: - admin_talk_list + - admin_talk_add + - admin_talk_edit forum_vote_github: nom: 'Votes visiteurs' niveau: 'ROLE_FORUM' diff --git a/app/config/routing/admin_talk.yml b/app/config/routing/admin_talk.yml index 5658331eb..f76bb7915 100644 --- a/app/config/routing/admin_talk.yml +++ b/app/config/routing/admin_talk.yml @@ -2,6 +2,22 @@ admin_talk_list: path: / defaults: {_controller: AppBundle\Controller\Admin\Talk\IndexAction} +admin_talk_add: + path: /add + defaults: {_controller: AppBundle\Controller\Admin\Talk\AddAction} + +admin_talk_edit: + path: /edit/{id} + defaults: {_controller: AppBundle\Controller\Admin\Talk\EditAction} + requirements: + id: \d+ + +admin_talk_delete: + path: /delete/{id} + defaults: {_controller: AppBundle\Controller\Admin\Talk\DeleteAction} + requirements: + id: \d+ + admin_talk_export_joind_in: path: /export/joind-in/{eventId}/ defaults: {_controller: AppBundle\Controller\Admin\Talk\ExportJoindInAction} diff --git a/sources/AppBundle/Controller/Admin/HomeAction.php b/sources/AppBundle/Controller/Admin/HomeAction.php index f93172e74..c0a0271fc 100644 --- a/sources/AppBundle/Controller/Admin/HomeAction.php +++ b/sources/AppBundle/Controller/Admin/HomeAction.php @@ -37,7 +37,7 @@ public function __invoke(): Response $cfp = [ 'title' => 'CFP', 'subtitle' => 'Talks et speakers', - 'url' => '/pages/administration/index.php?page=forum_sessions', + 'url' => '/admin/talk/', 'statistics' => [], ]; diff --git a/sources/AppBundle/Controller/Admin/Talk/AddAction.php b/sources/AppBundle/Controller/Admin/Talk/AddAction.php new file mode 100644 index 000000000..3c9b08f35 --- /dev/null +++ b/sources/AppBundle/Controller/Admin/Talk/AddAction.php @@ -0,0 +1,51 @@ +setForumId($eventSelection->event->getId()); + + $form = $this->createForm(TalkAdminType::class, $talk, [ + 'event' => $eventSelection->event, + ]); + + $form->handleRequest($request); + if ($form->isSubmitted() && $form->isValid()) { + $this->talkRepository->save($talk); + $this->talkToSpeakersRepository->replaceSpeakers($talk, $form->get('speakers')->getData()); + + $this->audit->log(sprintf('Ajout de la session de %s', $talk->getTitle())); + $this->addFlash('notice', 'La conférence a été ajoutée.'); + + return $this->redirectToRoute('admin_talk_list'); + } + + return $this->render('admin/talk/add.html.twig', [ + 'event' => $eventSelection->event, + 'form' => $form, + ]); + } + +} diff --git a/sources/AppBundle/Controller/Admin/Talk/DeleteAction.php b/sources/AppBundle/Controller/Admin/Talk/DeleteAction.php new file mode 100644 index 000000000..be9e3279f --- /dev/null +++ b/sources/AppBundle/Controller/Admin/Talk/DeleteAction.php @@ -0,0 +1,35 @@ +talkRepository->get($id); + if (!$talk instanceof Talk) { + throw $this->createNotFoundException(sprintf('Talk not found with id "%s"', $id)); + } + $this->talkRepository->delete($talk); + + $this->audit->log(sprintf('Suppression de la session de %s (%d)', $talk->getTitle(), $talk->getId())); + $this->addFlash('notice', 'La conférence a été supprimée.'); + + return $this->redirectToRoute('admin_talk_list'); + } + +} diff --git a/sources/AppBundle/Controller/Admin/Talk/EditAction.php b/sources/AppBundle/Controller/Admin/Talk/EditAction.php new file mode 100644 index 000000000..d3ec7e459 --- /dev/null +++ b/sources/AppBundle/Controller/Admin/Talk/EditAction.php @@ -0,0 +1,62 @@ +talkRepository->get($id); + if (!$talk instanceof Talk) { + throw $this->createNotFoundException(sprintf('Talk not found with id "%s"', $id)); + } + $event = $this->eventRepository->get($talk->getForumId()); + if (!$event instanceof Event) { + throw $this->createNotFoundException(sprintf('Event not found with id "%s"', $talk->getForumId())); + } + + $form = $this->createForm(TalkAdminType::class, $talk, [ + 'event' => $event, + TalkType::OPT_COC_CHECKED => true, + ]); + + $form->handleRequest($request); + if ($form->isSubmitted() && $form->isValid()) { + $this->talkRepository->save($talk); + $this->talkToSpeakersRepository->replaceSpeakers($talk, $form->get('speakers')->getData()); + + $this->audit->log(sprintf('Modification de la session de %s (%d)', $talk->getTitle(), $talk->getId())); + $this->addFlash('notice', 'La conférence a été modifiée.'); + + return $this->redirectToRoute('admin_talk_list'); + } + + return $this->render('admin/talk/edit.html.twig', [ + 'event' => $event, + 'form' => $form, + 'talk' => $talk, + ]); + } + +} diff --git a/sources/AppBundle/Controller/Admin/Talk/IndexAction.php b/sources/AppBundle/Controller/Admin/Talk/IndexAction.php index 76996683d..3e7b22f2e 100644 --- a/sources/AppBundle/Controller/Admin/Talk/IndexAction.php +++ b/sources/AppBundle/Controller/Admin/Talk/IndexAction.php @@ -26,15 +26,6 @@ public function __construct( public function __invoke(Request $request, AdminEventSelection $eventSelection): Response { - //TODO : à supprimer quand les actions via le formulaire auront été migrées - if (isset($_SESSION['flash']['message'])) { - $this->addFlash('notice', $_SESSION['flash']['message']); - } - if (isset($_SESSION['flash']['erreur'])) { - $this->addFlash('error', $_SESSION['flash']['erreur']); - } - unset($_SESSION['flash']); - $event = $eventSelection->event; $data = [ diff --git a/sources/AppBundle/Controller/Admin/Talk/UpdateIndexationAction.php b/sources/AppBundle/Controller/Admin/Talk/UpdateIndexationAction.php index 7ea027a3c..d35ecb332 100644 --- a/sources/AppBundle/Controller/Admin/Talk/UpdateIndexationAction.php +++ b/sources/AppBundle/Controller/Admin/Talk/UpdateIndexationAction.php @@ -21,6 +21,6 @@ public function __invoke(Request $request): RedirectResponse $this->addFlash('notice', 'Indexation effectuée'); - return $this->redirect($request->headers->get('referer', '/pages/administration/index.php?page=forum_sessions')); + return $this->redirect($request->headers->get('referer', $this->generateUrl('admin_talk_list'))); } } diff --git a/sources/AppBundle/Event/Form/TalkAdminType.php b/sources/AppBundle/Event/Form/TalkAdminType.php new file mode 100644 index 000000000..d3884726e --- /dev/null +++ b/sources/AppBundle/Event/Form/TalkAdminType.php @@ -0,0 +1,107 @@ +speakerRepository->searchSpeakers($options['event']); + $speakers = $this->speakerRepository->getSpeakersByTalk($builder->getData()); + $speakers = iterator_to_array($speakers->getIterator()); + + parent::buildForm($builder, $options); + $builder->remove('hasAllowedToSharingWithLocalOffices'); + $builder + ->add('hasAllowedToSharingWithLocalOffices', CheckboxType::class, [ + 'label' => 'Autoriser l’AFUP à transmettre ma proposition de conférence à ses antennes locales ?', + 'required' => false, + ]) + ->add('joindinId', TextType::class, [ + 'label' => 'joind.in ID', + 'required' => false, + 'attr' => ['placeholder' => '4639e'], + ]) + ->add('youtubeId', TextType::class, [ + 'label' => 'Youtube ID', + 'required' => false, + 'attr' => ['placeholder' => '9P7K3sdg6s4'], + ]) + ->add('slidesUrl', UrlType::class, [ + 'label' => 'URL des slides', + 'required' => false, + 'default_protocol' => 'https', + 'attr' => ['placeholder' => 'https://'], + ]) + ->add('openfeedbackPath', TextType::class, [ + 'label' => 'Open Feedback (path)', + 'required' => false, + 'attr' => ['placeholder' => 'forumphp2025/2025-10-09/5394'], + ]) + ->add('blogPostUrl', UrlType::class, [ + 'label' => 'URL du blog', + 'required' => false, + 'default_protocol' => 'https', + 'attr' => ['placeholder' => 'https://'], + ]) + ->add('interviewUrl', UrlType::class, [ + 'label' => 'URL de l\'interview', + 'required' => false, + 'default_protocol' => 'https', + 'attr' => ['placeholder' => 'https://'], + ]) + ->add('languageCode', ChoiceType::class, [ + 'label' => 'Langue', + 'required' => false, + 'choices' => array_flip(Talk::getLanguageLabelsByKey()), + ]) + ->add('tweets', TextareaType::class, [ + 'label' => 'Tweets', + 'required' => false, + ]) + ->add('submittedOn', DateTimeType::class, [ + 'label' => 'Date de soumission', + ]) + ->add('publishedOn', DateTimeType::class, [ + 'label' => 'Date de publication', + 'required' => false, + ]) + ->add('speakers', ChoiceType::class, [ + 'mapped' => false, + 'multiple' => true, + 'choices' => $allSpeakers, + 'required' => false, + 'data' => $speakers, + 'choice_label' => fn(Speaker $speaker) => $speaker->getLabel(), + 'choice_value' => fn(?Speaker $speaker) => $speaker?->getId(), + 'choice_name' => 'id', + ]) + ->add('save', SubmitType::class) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefault('data_class', Talk::class); + $resolver->setDefault('event', EventType::class); + + parent::configureOptions($resolver); + } +} diff --git a/sources/AppBundle/Event/Model/Repository/TalkRepository.php b/sources/AppBundle/Event/Model/Repository/TalkRepository.php index da4b3c28e..513127fa3 100644 --- a/sources/AppBundle/Event/Model/Repository/TalkRepository.php +++ b/sources/AppBundle/Event/Model/Repository/TalkRepository.php @@ -459,6 +459,14 @@ public static function initMetadata(SerializerFactoryInterface $serializerFactor 'unserialize' => ['unSerializeUseFormat' => false], ], ]) + ->addField([ + 'columnName' => 'date_publication', + 'fieldName' => 'publishedOn', + 'type' => 'datetime', + 'serializer_options' => [ + 'unserialize' => ['unSerializeUseFormat' => false], + ], + ]) ->addField([ 'columnName' => 'titre', 'fieldName' => 'title', diff --git a/sources/AppBundle/Event/Model/Repository/TalkToSpeakersRepository.php b/sources/AppBundle/Event/Model/Repository/TalkToSpeakersRepository.php index 8e91648ea..765cf351f 100644 --- a/sources/AppBundle/Event/Model/Repository/TalkToSpeakersRepository.php +++ b/sources/AppBundle/Event/Model/Repository/TalkToSpeakersRepository.php @@ -50,7 +50,7 @@ public function replaceSpeakers(Talk $talk, array $speakers): void { $this->startTransaction(); try { - $delete = $this->getPreparedQuery('DELETE FROM afup_conferenciers_sessions WHERE talk_id = :talk'); + $delete = $this->getPreparedQuery('DELETE FROM afup_conferenciers_sessions WHERE session_id = :talk'); $delete->setParams(['talk' => $talk->getId()])->execute(); $insert = $this->getPreparedQuery('INSERT INTO afup_conferenciers_sessions (conferencier_id, session_id) VALUES (:speaker, :talk)'); diff --git a/sources/AppBundle/Event/Model/Talk.php b/sources/AppBundle/Event/Model/Talk.php index 1a21bc7aa..df57ca4ea 100644 --- a/sources/AppBundle/Event/Model/Talk.php +++ b/sources/AppBundle/Event/Model/Talk.php @@ -36,7 +36,8 @@ class Talk implements NotifyPropertyInterface #[Assert\GreaterThan(0)] private ?int $forumId = null; - private ?\DateTime $submittedOn = null; + private \DateTime $submittedOn; + private ?\DateTime $publishedOn = null; #[Assert\NotBlank] private string $title = ''; @@ -96,6 +97,12 @@ class Talk implements NotifyPropertyInterface */ private array $votes = []; + public function __construct() + { + $this->submittedOn = new \DateTime(); + $this->languageCode = self::LANGUAGE_CODE_FR; + } + public function getId(): ?int { return $this->id; @@ -132,6 +139,18 @@ public function setSubmittedOn(\DateTime $submittedOn): self return $this; } + public function getPublishedOn(): ?\DateTime + { + return $this->publishedOn; + } + + public function setPublishedOn(?\DateTime $publishedOn): self + { + $this->propertyChanged('publishedOn', $this->publishedOn, $publishedOn); + $this->publishedOn = $publishedOn; + return $this; + } + public function getTitle(): string { return $this->title; @@ -355,6 +374,7 @@ public function getOpenfeedbackPath(): ?string public function setOpenfeedbackPath(?string $openfeedbackPath): self { + $this->propertyChanged('openfeedbackPath', $this->openfeedbackPath, $openfeedbackPath); $this->openfeedbackPath = $openfeedbackPath; return $this; @@ -544,6 +564,7 @@ public function getTweets(): ?string public function setTweets(?string $tweets): self { + $this->propertyChanged('tweets', $this->tweets, $tweets); $this->tweets = $tweets; return $this; diff --git a/sources/AppBundle/Slack/MessageFactory.php b/sources/AppBundle/Slack/MessageFactory.php index 0183b334f..754dcccfb 100644 --- a/sources/AppBundle/Slack/MessageFactory.php +++ b/sources/AppBundle/Slack/MessageFactory.php @@ -79,7 +79,7 @@ public function createMessageForTalk(Talk $talk, Event $event): Message $attachment = new Attachment(); $attachment ->setTitle('Nouvelle proposition sur le CFP - ' . $event->getTitle()) - ->setTitleLink('https://afup.org/pages/administration/index.php?' . http_build_query(['page' => 'forum_sessions', 'id_forum' => $event->getId()])) + ->setTitleLink('https://afup.org/admin/talk/?' . http_build_query(['id' => $event->getId()])) ->setFallback(sprintf( 'Nouvelle proposition intitulée "%s". Type %s - Public %s', $talk->getTitle(), @@ -263,7 +263,7 @@ public function createMessageForCfpStats(Event $event, TalkRepository $talkRepos $attachment = new Attachment(); $attachment ->setTitle(sprintf('Total des réponses au CFP du %s', $event->getTitle())) - ->setTitleLink('https://afup.org/pages/administration/index.php?page=forum_sessions') + ->setTitleLink('https://afup.org/admin/talk/') ; foreach ($this->prepareCfpStatsFields($talkRepository, $talkToSpeakersRepository, $event) as $field) { diff --git a/templates/admin/speaker/edit.html.twig b/templates/admin/speaker/edit.html.twig index a027d3aa7..e2c5fa357 100644 --- a/templates/admin/speaker/edit.html.twig +++ b/templates/admin/speaker/edit.html.twig @@ -67,7 +67,7 @@
- + diff --git a/templates/admin/talk/add.html.twig b/templates/admin/talk/add.html.twig new file mode 100644 index 000000000..cb3703347 --- /dev/null +++ b/templates/admin/talk/add.html.twig @@ -0,0 +1,11 @@ +{% extends 'admin/base_with_header.html.twig' %} + +{% form_theme form 'form_theme_admin.html.twig' %} + + +{% block content %} +

Ajouter une conférence pour le {{ event.title }}

+ + {% include '/admin/talk/form.html.twig' %} +{% endblock %} + diff --git a/templates/admin/talk/edit.html.twig b/templates/admin/talk/edit.html.twig new file mode 100644 index 000000000..84e68d26b --- /dev/null +++ b/templates/admin/talk/edit.html.twig @@ -0,0 +1,15 @@ +{% extends 'admin/base_with_header.html.twig' %} + +{% form_theme form 'form_theme_admin.html.twig' %} + + +{% block content %} +

Modifier la conférence pour le {{ event.title }}

+ + {% include '/admin/talk/form.html.twig' %} +{% endblock %} + diff --git a/templates/admin/talk/form.html.twig b/templates/admin/talk/form.html.twig new file mode 100644 index 000000000..8e1adcda9 --- /dev/null +++ b/templates/admin/talk/form.html.twig @@ -0,0 +1,45 @@ +
+ {{ form_start(form) }} +
+

Présentation

+ {{ form_row(form.title) }} + {{ form_row(form.abstract, {attr: {class: 'tinymce'}}) }} + {{ form_row(form.staffNotes) }} + {{ form_row(form.type) }} + {{ form_row(form.skill) }} + {{ form_row(form.withWorkshop) }} + {{ form_row(form.workshopAbstract) }} + {{ form_row(form.needsMentoring) }} + {{ form_row(form.codeOfConduct) }} + {{ form_row(form.hasAllowedToSharingWithLocalOffices) }} +
+
+

Conférencier(s)

+ {{ form_row(form.speakers) }} +
+
+

Informations complémentaires

+ {{ form_row(form.submittedOn) }} + {{ form_row(form.publishedOn) }} + {{ form_row(form.joindinId) }} + {{ form_row(form.youtubeId) }} + {{ form_row(form.slidesUrl) }} + {{ form_row(form.openfeedbackPath) }} + {{ form_row(form.blogPostUrl) }} + {{ form_row(form.interviewUrl) }} + {{ form_row(form.languageCode) }} + {{ form_row(form.tweets) }} +
+
+
+
+
+ {{ form_row(form.save, {attr: {class: "ui primary button"}, label: "Soumettre"}) }} +
+
+
+
+

* indique un champ obligatoire

+
+ {{ form_end(form) }} +
\ No newline at end of file diff --git a/templates/admin/talk/index.html.twig b/templates/admin/talk/index.html.twig index 1f55fa5b8..35152a976 100644 --- a/templates/admin/talk/index.html.twig +++ b/templates/admin/talk/index.html.twig @@ -6,7 +6,7 @@ {% include 'admin/event/change_event.html.twig' with {form: event_select_form} only %}