From 4bf0964bf581223a9710f78ea7f642d373bcc928 Mon Sep 17 00:00:00 2001 From: Elorfin Date: Mon, 1 Mar 2021 09:18:28 +0100 Subject: [PATCH] [Cursus] adds presence certificates --- .../cursus/Controller/CourseController.php | 18 ++++++----- .../Controller/EventPresenceController.php | 28 +++++++++++++++++ .../PostInstall/LoadTemplateData.php | 31 ++++++++++++++++--- .../Installation/AdditionalInstaller.php | 2 ++ .../Installation/Updater/Updater130005.php | 26 ++++++++++++++++ .../cursus/Manager/EventPresenceManager.php | 27 ++++++++++++++++ src/plugin/cursus/Resources/config/config.yml | 13 ++++++++ .../Resources/config/services/updater.yml | 6 ++++ .../modules/event/components/participants.jsx | 22 +++++++++++-- .../Resources/translations/cursus.en.json | 3 +- .../Resources/translations/cursus.fr.json | 3 +- .../Resources/translations/template.en.json | 2 ++ .../Resources/translations/template.fr.json | 2 ++ 13 files changed, 168 insertions(+), 15 deletions(-) create mode 100644 src/plugin/cursus/Installation/Updater/Updater130005.php diff --git a/src/plugin/cursus/Controller/CourseController.php b/src/plugin/cursus/Controller/CourseController.php index 7aeba9cda08..b3a4dcb8443 100644 --- a/src/plugin/cursus/Controller/CourseController.php +++ b/src/plugin/cursus/Controller/CourseController.php @@ -90,19 +90,23 @@ public function getOptions() protected function getDefaultHiddenFilters() { + $filters = []; if (!$this->authorization->isGranted('ROLE_ADMIN')) { /** @var User $user */ $user = $this->tokenStorage->getToken()->getUser(); - return [ - 'hidden' => $this->checkToolAccess('EDIT'), - 'organizations' => array_map(function (Organization $organization) { - return $organization->getUuid(); - }, $user->getOrganizations()), - ]; + // filter by organizations + $filters['organizations'] = array_map(function (Organization $organization) { + return $organization->getUuid(); + }, $user->getOrganizations()); + + // hide hidden trainings for non admin + if (!$this->checkToolAccess('EDIT')) { + $filters['hidden'] = false; + } } - return []; + return $filters; } /** diff --git a/src/plugin/cursus/Controller/EventPresenceController.php b/src/plugin/cursus/Controller/EventPresenceController.php index fca5de8483b..70442b81080 100644 --- a/src/plugin/cursus/Controller/EventPresenceController.php +++ b/src/plugin/cursus/Controller/EventPresenceController.php @@ -15,6 +15,7 @@ use Claroline\AppBundle\API\SerializerProvider; use Claroline\AppBundle\Controller\RequestDecoderTrait; use Claroline\AppBundle\Persistence\ObjectManager; +use Claroline\CoreBundle\Entity\User; use Claroline\CoreBundle\Library\Normalizer\TextNormalizer; use Claroline\CoreBundle\Security\PermissionCheckerTrait; use Claroline\CursusBundle\Entity\Event; @@ -124,4 +125,31 @@ public function downloadPdfAction(Event $event, Request $request, int $filled): 'Content-Disposition' => 'attachment; filename='.TextNormalizer::toKey($event->getName()).'-presences.pdf', ]); } + + /** + * @Route("/{id}/user/{userId}/download", name="apiv2_cursus_user_presence_download", methods={"GET"}) + * @EXT\ParamConverter("event", class="ClarolineCursusBundle:Event", options={"mapping": {"id": "uuid"}}) + * @EXT\ParamConverter("user", class="ClarolineCoreBundle:User", options={"mapping": {"userId": "uuid"}}) + */ + public function downloadUserPdfAction(Event $event, User $user, Request $request): StreamedResponse + { + $this->checkPermission('EDIT', $event, [], true); + + $domPdf = new Dompdf([ + 'isHtml5ParserEnabled' => true, + 'isRemoteEnabled' => true, + ]); + + $domPdf->loadHtml($this->manager->downloadUser($event, $request->getLocale(), $user)); + + // Render the HTML as PDF + $domPdf->render(); + + return new StreamedResponse(function () use ($domPdf) { + echo $domPdf->output(); + }, 200, [ + 'Content-Type' => 'application/pdf', + 'Content-Disposition' => 'attachment; filename='.TextNormalizer::toKey($event->getName()).'-presence.pdf', + ]); + } } diff --git a/src/plugin/cursus/DataFixtures/PostInstall/LoadTemplateData.php b/src/plugin/cursus/DataFixtures/PostInstall/LoadTemplateData.php index 84f8ed1ef9e..556afb2220d 100644 --- a/src/plugin/cursus/DataFixtures/PostInstall/LoadTemplateData.php +++ b/src/plugin/cursus/DataFixtures/PostInstall/LoadTemplateData.php @@ -68,12 +68,12 @@ public function load(ObjectManager $om) $om->persist($eventInvitationType); } - $eventPresenceType = $this->templateTypeRepo->findOneBy(['name' => 'training_event_presences']); + $eventPresencesType = $this->templateTypeRepo->findOneBy(['name' => 'training_event_presences']); $templates = $this->templateRepo->findBy(['name' => 'training_event_presences']); - if ($eventPresenceType && empty($templates)) { + if ($eventPresencesType && empty($templates)) { foreach ($this->availableLocales as $locale) { $template = new Template(); - $template->setType($eventPresenceType); + $template->setType($eventPresencesType); $template->setName('training_event_presences'); $template->setLang($locale); $template->setTitle($this->translator->trans('training_event_presences', [], 'template', $locale)); @@ -84,7 +84,30 @@ public function load(ObjectManager $om) $template->setContent($content); $om->persist($template); } - $eventPresenceType->setDefaultTemplate('training_event_presences'); + $eventPresencesType->setDefaultTemplate('training_event_presences'); + $om->persist($eventPresencesType); + } + + $eventPresenceType = $this->templateTypeRepo->findOneBy(['name' => 'training_event_presence']); + $templates = $this->templateRepo->findBy(['name' => 'training_event_presence']); + if ($eventPresenceType && empty($templates)) { + foreach ($this->availableLocales as $locale) { + $template = new Template(); + $template->setType($eventPresenceType); + $template->setName('training_event_presence'); + $template->setLang($locale); + $template->setTitle($this->translator->trans('training_event_presence', [], 'template', $locale)); + $content = '%event_name%
'; + $content .= '[%event_start% -> %event_end%]
'; + $content .= '%event_description%

'; + $content .= ''; + $template->setContent($content); + $om->persist($template); + } + $eventPresenceType->setDefaultTemplate('training_event_presence'); $om->persist($eventPresenceType); } diff --git a/src/plugin/cursus/Installation/AdditionalInstaller.php b/src/plugin/cursus/Installation/AdditionalInstaller.php index a7c3adfbb61..ce903a0686d 100644 --- a/src/plugin/cursus/Installation/AdditionalInstaller.php +++ b/src/plugin/cursus/Installation/AdditionalInstaller.php @@ -3,6 +3,7 @@ namespace Claroline\CursusBundle\Installation; use Claroline\CursusBundle\Installation\Updater\Updater130001; +use Claroline\CursusBundle\Installation\Updater\Updater130005; use Claroline\InstallationBundle\Additional\AdditionalInstaller as BaseInstaller; class AdditionalInstaller extends BaseInstaller @@ -11,6 +12,7 @@ public static function getUpdaters(): array { return [ '13.0.1' => Updater130001::class, + '13.0.5' => Updater130005::class, ]; } } diff --git a/src/plugin/cursus/Installation/Updater/Updater130005.php b/src/plugin/cursus/Installation/Updater/Updater130005.php new file mode 100644 index 00000000000..0a7195ef69c --- /dev/null +++ b/src/plugin/cursus/Installation/Updater/Updater130005.php @@ -0,0 +1,26 @@ +om = $om; + $this->dataFixtures = $dataFixtures; + } + + public function postUpdate() + { + $this->dataFixtures->load($this->om); + } +} diff --git a/src/plugin/cursus/Manager/EventPresenceManager.php b/src/plugin/cursus/Manager/EventPresenceManager.php index 4decc8944f0..605726745d4 100644 --- a/src/plugin/cursus/Manager/EventPresenceManager.php +++ b/src/plugin/cursus/Manager/EventPresenceManager.php @@ -12,6 +12,7 @@ namespace Claroline\CursusBundle\Manager; use Claroline\AppBundle\Persistence\ObjectManager; +use Claroline\CoreBundle\Entity\User; use Claroline\CoreBundle\Manager\Template\TemplateManager; use Claroline\CursusBundle\Entity\Event; use Claroline\CursusBundle\Entity\EventPresence; @@ -124,4 +125,30 @@ public function download(Event $event, string $locale, bool $filled = false): st return $this->templateManager->getTemplate('training_event_presences', $placeholders, $locale); } + + public function downloadUser(Event $event, string $locale, User $user) + { + $status = EventPresence::UNKNOWN; + $presence = $this->om->getRepository(EventPresence::class)->findOneBy([ + 'event' => $event, + 'user' => $user, + ]); + if ($presence) { + $status = $presence->getStatus(); + } + + $placeholders = [ + 'event_name' => $event->getName(), + 'event_code' => $event->getCode(), + 'event_description' => $event->getDescription(), + 'event_start' => $event->getStartDate()->format('d/m/Y H:i'), + 'event_end' => $event->getEndDate()->format('d/m/Y H:i'), + 'event_presence_status' => $this->translator->trans('presence_'.$status, [], 'cursus'), + 'user_username' => $user->getUsername(), + 'user_first_name' => $user->getFirstName(), + 'user_last_name' => $user->getLastName(), + ]; + + return $this->templateManager->getTemplate('training_event_presence', $placeholders, $locale); + } } diff --git a/src/plugin/cursus/Resources/config/config.yml b/src/plugin/cursus/Resources/config/config.yml index 0b02f872446..cbccb682cfa 100644 --- a/src/plugin/cursus/Resources/config/config.yml +++ b/src/plugin/cursus/Resources/config/config.yml @@ -101,3 +101,16 @@ plugin: - event_start - event_end - event_presences_table + + - name: training_event_presence + placeholders: + - event_name + - event_code + - event_description + - event_start + - event_end + - event_presence_status + - user_username + - user_first_name + - user_last_name + diff --git a/src/plugin/cursus/Resources/config/services/updater.yml b/src/plugin/cursus/Resources/config/services/updater.yml index 407971a798f..0c8f2d78068 100644 --- a/src/plugin/cursus/Resources/config/services/updater.yml +++ b/src/plugin/cursus/Resources/config/services/updater.yml @@ -10,3 +10,9 @@ services: - '@Claroline\CursusBundle\DataFixtures\PostInstall\LoadTemplateData' - '@logger' tags: ['claroline.platform.updater'] + + Claroline\CursusBundle\Installation\Updater\Updater130005: + arguments: + - '@Claroline\AppBundle\Persistence\ObjectManager' + - '@Claroline\CursusBundle\DataFixtures\PostInstall\LoadTemplateData' + tags: [ 'claroline.platform.updater' ] \ No newline at end of file diff --git a/src/plugin/cursus/Resources/modules/event/components/participants.jsx b/src/plugin/cursus/Resources/modules/event/components/participants.jsx index 35fd3379857..084f5cfe58e 100644 --- a/src/plugin/cursus/Resources/modules/event/components/participants.jsx +++ b/src/plugin/cursus/Resources/modules/event/components/participants.jsx @@ -6,7 +6,7 @@ import {schemeCategory20c} from 'd3-scale' import {trans} from '#/main/app/intl/translation' import {hasPermission} from '#/main/app/security' -import {CALLBACK_BUTTON, MODAL_BUTTON} from '#/main/app/buttons' +import {CALLBACK_BUTTON, DOWNLOAD_BUTTON, MODAL_BUTTON} from '#/main/app/buttons' import {AlertBlock} from '#/main/app/alert/components/alert-block' import {Routes} from '#/main/app/router/components/routes' import {ListData} from '#/main/app/content/list/containers/data' @@ -35,8 +35,17 @@ const EventUsers = (props) => type: CALLBACK_BUTTON, icon: 'fa fa-fw fa-envelope', label: trans('send_invitation', {}, 'actions'), - callback: () => props.inviteUsers(props.event.id, rows), + callback: () => props.inviteUsers(props.event.id, rows[0].user.id), displayed: hasPermission('edit', props.event) + }, { + name: 'download-presence', + type: DOWNLOAD_BUTTON, + icon: 'fa fa-fw fa-file-pdf-o', + label: trans('download_presence', {}, 'cursus'), + file: { + url: ['apiv2_cursus_user_presence_download', {id: props.event.id, userId: rows[0].user.id}] + }, + scope: ['object'] } ]} add={{ @@ -142,6 +151,15 @@ const EventPresences = (props) => modal: [MODAL_EVENT_PRESENCE, { changeStatus: (status) => props.setPresenceStatus(props.event.id, rows, status) }] + }, { + name: 'download-presence', + type: DOWNLOAD_BUTTON, + icon: 'fa fa-fw fa-file-pdf-o', + label: trans('download_presence', {}, 'cursus'), + file: { + url: ['apiv2_cursus_user_presence_download', {id: props.event.id, userId: rows[0].user.id}] + }, + scope: ['object'] } ]} /> diff --git a/src/plugin/cursus/Resources/translations/cursus.en.json b/src/plugin/cursus/Resources/translations/cursus.en.json index f442b1f4f82..30047ef93df 100644 --- a/src/plugin/cursus/Resources/translations/cursus.en.json +++ b/src/plugin/cursus/Resources/translations/cursus.en.json @@ -94,5 +94,6 @@ "export-presences-empty": "Download the attendance list (empty)", "export-presences-filled": "Download the attendance list (filled)", "no_course": "No training", - "session_info": "Session information" + "session_info": "Session information", + "download_presence": "Download the certificate of presence (.pdf)" } diff --git a/src/plugin/cursus/Resources/translations/cursus.fr.json b/src/plugin/cursus/Resources/translations/cursus.fr.json index eaae4c2865c..6da9829225c 100644 --- a/src/plugin/cursus/Resources/translations/cursus.fr.json +++ b/src/plugin/cursus/Resources/translations/cursus.fr.json @@ -94,5 +94,6 @@ "export-presences-empty": "Télécharger la liste de présences (vide)", "export-presences-filled": "Télécharger la liste de présences (remplie)", "no_course": "Aucune formation", - "session_info": "Informations sur la session" + "session_info": "Informations sur la session", + "download_presence": "Télécharger l'attestation de présence (.pdf)" } diff --git a/src/plugin/cursus/Resources/translations/template.en.json b/src/plugin/cursus/Resources/translations/template.en.json index e79f02c7621..ec70a5600ed 100644 --- a/src/plugin/cursus/Resources/translations/template.en.json +++ b/src/plugin/cursus/Resources/translations/template.en.json @@ -9,6 +9,8 @@ "training_session_invitation_desc": "Template used for the mail sent for the invitation to a training session.", "training_event_presences": "Attendance grid for a training event", "training_event_presences_help": "Template used for printing the attendance grid (empty or pre-filled) of a training event.", + "training_event_presence": "Certificate of attendance to a training event", + "training_event_presence_help": "Template used for printing the certificate of attendance of a user to a training event.", "course_code_desc": "The code of the training", "course_description_desc": "The description of the training", diff --git a/src/plugin/cursus/Resources/translations/template.fr.json b/src/plugin/cursus/Resources/translations/template.fr.json index 22aa548bf68..3a6bdc2d9ff 100644 --- a/src/plugin/cursus/Resources/translations/template.fr.json +++ b/src/plugin/cursus/Resources/translations/template.fr.json @@ -7,6 +7,8 @@ "training_event_invitation_desc": "Template utilisé pour le mail d'invitation à une séance de formation.", "training_event_presences": "Grille de présence d'une séance de formation", "training_event_presences_help": "Template utilisé pour l'impression de la grille de présence (vide ou pré-remplie) d'une séance de formation.", + "training_event_presence": "Attestation de présence à une séance de formation", + "training_event_presence_help": "Template utilisé pour l'impression l'attestation de présence d'un utilisateur à une séance de formation.", "training_session_invitation": "Invitation à une session de formation", "training_session_invitation_desc": "Template utilisé pour le mail d'invitation à une session de formation.", "training_session_confirmation": "Confirmation d'inscription à une session de formation",