<?php
namespace App\Controller\Admin;
use App\Entity\Module;
use App\Entity\ModuleInscription;
use App\Entity\ModuleItem;
use App\Entity\ModuleParticipation;
use App\Entity\ModuleView;
use App\Entity\User;
use App\Form\ModuleInscriptionType;
use App\Form\ModuleType;
use App\Helper\ControllerHelper;
use App\Message\Notification;
use App\Repository\ModuleInscriptionRepository;
use App\Repository\ModuleItemRepository;
use App\Repository\ModuleParticipationRepository;
use App\Repository\UserModuleParticipationRepository;
use App\Repository\ModuleRepository;
use App\Repository\ModuleViewRepository;
use App\Repository\LiveViewRepository;
use App\Repository\CourseViewRepository;
use App\Repository\QuizViewRepository;
use App\Repository\UserRepository;
use App\Service\HelperService;
use App\Service\PushNotification;
use App\Utils\Constants;
use DateTime;
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Persistence\ManagerRegistry;
use Exception;
use Kreait\Firebase\Contract\Messaging;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\String\Slugger\SluggerInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mercure\HubInterface;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\Router;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
/**
* @Route("/dashboard")
*/
class ModuleController extends AbstractController
{
use ControllerHelper;
private $slugger;
private $helperService;
private $pushNotification;
private $messaging;
private $hub;
private $bus;
public function __construct(SluggerInterface $slugger, HelperService $helperService, PushNotification $pushNotification, Messaging $messaging, HubInterface $hub, MessageBusInterface $bus)
{
$this->slugger = $slugger;
$this->helperService = $helperService;
$this->pushNotification = $pushNotification;
$this->messaging = $messaging;
$this->hub = $hub;
$this->bus = $bus;
}
/**
* Require ROLE_ADMIN or ROLE_INTEGRATOR for this action
*
* @Security("is_granted('ROLE_ADMIN') or is_granted('ROLE_INTEGRATOR')")
*
* @Route("/{profil}/{id}/modifier-module", name="app_module_edit", methods={"GET", "POST"})
*/
public function edit(Request $request, Module $module, ModuleRepository $moduleRepository, ModuleItemRepository $moduleItemRepository, ManagerRegistry $doctrine, String $profil): Response
{
// if (!$this->isGranted('ROLE_ADMIN') && !$this->isGranted('ROLE_INTEGRATOR')) throw $this->createNotFoundException("La page demandée n'existe pas");
$form = $this->createForm(ModuleType::class, $module);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$quiz = $module->getQuiz();
$quizAdded = $quiz->getInsertDiff();
$quizRemoved = $quiz->getDeleteDiff();
$courses = $module->getCourses();
$coursesAdded = $courses->getInsertDiff();
$coursesRemoved = $courses->getDeleteDiff();
$moduleRepository->add($module, true);
foreach ($coursesAdded as $course) {
// $moduleItem = $moduleItemRepository->findOneBy(['module' => $module, 'course' => $course]);
// if ($moduleItem === null) {
$moduleItem = new ModuleItem();
$moduleItem->setModule($module);
$moduleItem->setCourse($course);
$moduleItem->setType('course');
$moduleItemRepository->add($moduleItem, true);
// }
}
foreach ($coursesRemoved as $course) {
$moduleItem = $moduleItemRepository->findOneBy(['module' => $module, 'course' => $course]);
if ($moduleItem !== null) {
$moduleItemRepository->remove($moduleItem, true);
}
}
foreach ($quizAdded as $quiz) {
// $moduleItem = $moduleItemRepository->findOneBy(['module' => $module, 'quiz' => $quiz]);
// if ($moduleItem === null) {
$moduleItem = new ModuleItem();
$moduleItem->setModule($module);
$moduleItem->setQuiz($quiz);
$moduleItem->setType('quiz');
$moduleItemRepository->add($moduleItem, true);
// }
}
foreach ($quizRemoved as $quiz) {
$moduleItem = $moduleItemRepository->findOneBy(['module' => $module, 'quiz' => $quiz]);
if ($moduleItem !== null) {
$moduleItemRepository->remove($moduleItem, true);
}
}
$this->addFlash("module_updated", "Le module ".$module->getLabel()." a été mis à jour");
return $this->redirectToRoute('app_front_module_page', ['profil' => $profil], Response::HTTP_SEE_OTHER);
}
// return $this->renderForm('admin/module/edit.html.twig', [
return $this->renderForm('front/pages/dashboard/modules/create_module.html.twig', [
'module' => $module,
'form' => $form,
'profil' => $profil
]);
}
/**
* Require ROLE_ADMIN or ROLE_INTEGRATOR for this action
*
* @Security("is_granted('ROLE_ADMIN') or is_granted('ROLE_INTEGRATOR')")
*
* @Route("/{profil}/{id}/supprimer-module", name="app_module_delete", methods={"POST", "GET"})
*/
public function delete(Module $module, ModuleRepository $moduleRepository, String $profil): Response
{
// if (!$this->isGranted('ROLE_ADMIN') && !$this->isGranted('ROLE_INTEGRATOR')) throw $this->createNotFoundException("La page demandée n'existe pas");
$title = $module->getLabel();
try {
// if ($this->isCsrfTokenValid('delete'.$module->getId(), $request->request->get('_token'))) {
$moduleRepository->remove($module, true);
// }
$this->addFlash("module_deleted", "Le module ".$title." a été supprimé");
} catch (ForeignKeyConstraintViolationException $e) {
$this->addFlash('module_deletion_error', "Impossible de supprimer le module ".$title.". Il est lié à d'autres éléments");
}
return $this->redirectToRoute('app_front_module_page', ['profil' => $profil], Response::HTTP_SEE_OTHER);
}
/**
* @Route("/modules/{slug}/item-order", name="module_item_order")
* @param Request $request
* @return JsonResponse
*/
public function moduleOrder(Request $request, ModuleItemRepository $moduleItemRepository, Module $module)
{
$itemId = (int) $request->get('id');
$type = $request->get('type');
$order = (int) $request->get('order');
if ($type !== null && $itemId !== null) {
$moduleItem = $moduleItemRepository->findItemByTypeAndId($module, $type, $itemId);
if ($moduleItem !== null) {
$moduleItem->setItemOrder($order);
$moduleItem->setUpdatedAt(new DateTime());
$moduleItemRepository->add($moduleItem, true);
return $this->json("OK OK");
}
return $this->json("OK");
}
return $this->json("KO");
}
/**
* Require ROLE_ADMIN or ROLE_INTEGRATOR or ROLE_ADVISE or ROLE_TUTOR or ROLE_COACH for this action
*
* @Security("is_granted('ROLE_ADMIN') or is_granted('ROLE_INTEGRATOR') or is_granted('ROLE_ADVISE') or is_granted('ROLE_TUTOR') or is_granted('ROLE_COACH')")
*
* @Route("/{profil}/{id}/participants-module", name="app_dashboard_module_participant_page", methods={"GET", "POST"})
*/
public function participant(Request $request, Module $module, ModuleParticipationRepository $moduleParticipationRepository, UserRepository $userRepository, ModuleRepository $moduleRepository, String $profil): Response
{
$session = $request->getSession();
if ($request->query->get('page') === null) $session->remove('module_participant_search_key');
$page = (int)$request->query->get('page', 1);
if ($page <= 0) throw $this->createNotFoundException("La page demandée n'existe pas");
// Search form
$searchKey = $session->has('module_participant_search_key') ? $session->get('module_participant_search_key') : null;
$form = $this->createFormBuilder()
->add('searchKey', TextType::class, [
'label' => 'Rechercher: ',
'label_attr' => ['class' => 'text-grey'],
'attr' => [
'style' => 'border: 1px solid transparent !important'
],
'required' => false,
'data' => $session->has('module_participant_search_key') ? $session->get('module_participant_search_key') : ''
])
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$searchKey = $form->get('searchKey')->getData();
$session->remove('module_participant_search_key');
if ($searchKey !== null) $session->set('module_participant_search_key', $searchKey);
}
// $moduleParticipants = $moduleParticipationRepository->findModuleParticipations($module, $this->getUser(), $page, Constants::PAGINATION_LIMIT, $searchKey);
$moduleParticipants = $moduleParticipationRepository->_findParticipations($module, $this->getUser(), $page, Constants::PAGINATION_LIMIT, $searchKey);
$moduleParticipantCount = $moduleParticipationRepository->_findParticipations($module, $this->getUser(), null, null, $searchKey);
// $moduleParticipants = $userRepository->findModuleParticipants($module, $this->getUser(), $this->helperService->getUserCurrentRole(), $page, Constants::PAGINATION_LIMIT);
// $moduleParticipantCount = $moduleParticipationRepository->getModuleParticipationsCount($module, $this->getUser(), $searchKey);
// $moduleParticipantCount = $userRepository->getModuleParticipantCount($module, $this->getUser(), $this->helperService->getUserCurrentRole());
return $this->renderForm('front/pages/dashboard/modules/module-participant.html.twig', [
'module' => $module,
'module_participants' => $moduleParticipants,
'module_participation_count' => isset($moduleParticipantCount['unionCount']) ? $moduleParticipantCount['unionCount'] : 0,
'limit' => Constants::PAGINATION_LIMIT,
'page' => $page,
'form' => $form
]);
}
/**
* Require ROLE_ADMIN or ROLE_INTEGRATOR or ROLE_ADVISE or ROLE_TUTOR or ROLE_COACH for this action
*
* @Security("is_granted('ROLE_ADMIN') or is_granted('ROLE_INTEGRATOR') or is_granted('ROLE_ADVISE') or is_granted('ROLE_TUTOR') or is_granted('ROLE_COACH')")
*
* @Route("/{profil}/{id}/modules/inscription-participant", name="app_dashboard_add_module_participant_page", methods={"GET", "POST"})
*/
public function addParticipant(Request $request, Module $module, ModuleInscriptionRepository $moduleInscriptionRepository, MailerInterface $mailer, String $profil): Response
{
$moduleInscription = new ModuleInscription();
$form = $this->createForm(ModuleInscriptionType::class, $moduleInscription, ['module' => $module]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$toAddresses = [];
$count = 0;
$participants = $form->get('users')->getData();
foreach ($participants as $participant) {
$_moduleInscription = $moduleInscriptionRepository->findOneBy(['module' => $module, 'user' => $participant]);
if ($_moduleInscription === null) {
$moduleInscription = new ModuleInscription();
$moduleInscription->setModule($module);
$moduleInscription->setUser($participant);
$moduleInscriptionRepository->add($moduleInscription, true);
$toAddresses [] = $participant->getEmail();
$count++;
}
}
if (count($toAddresses) > 0) {
$url = 'https:'.$this->generateUrl('app_front_library_module_details_page', ['slug' => $module->getSlug()], UrlGeneratorInterface::NETWORK_PATH);
$mail = (new TemplatedEmail())
->from(new Address($this->getParameter('cofina_sender_mail'), 'Cofina Academy'))
->to(...$toAddresses)
->subject('Inscription au Module')
->htmlTemplate('front/pages/dashboard/modules/inscription-mail.html.twig')
->context([
'name' => $module->getName(),
'startAt' => $module->getStartAt(),
'endAt' => $module->getEndAt(),
'library_homepage_url' => $url
])
;
try {
$mailer->send($mail);
} catch (TransportExceptionInterface $e) {
}
}
try {
$mailer->send($mail);
$this->bus->dispatch(new Notification($module->getId(), 'Module', 'module_participation', $module->getCreatedBy()->getId()));
} catch (Exception $e) {
}
$this->addFlash('module_participants_added', $count.' participant(s) ajouté(s) au module');
return $this->redirectToRoute('app_dashboard_module_participant_page', ['id' => $module->getId(), 'profil' => $profil], Response::HTTP_SEE_OTHER);
}
return $this->renderForm('front/pages/dashboard/modules/add-module-participant.html.twig', [
'module' => $module,
'form' => $form
]);
}
/**
* Require ROLE_ADMIN or ROLE_INTEGRATOR or ROLE_ADVISE or ROLE_TUTOR or ROLE_COACH for this action
*
* @Security("is_granted('ROLE_ADMIN') or is_granted('ROLE_INTEGRATOR') or is_granted('ROLE_ADVISE') or is_granted('ROLE_TUTOR') or is_granted('ROLE_COACH')")
*
* @Route("/{profil}/{id}/participants-module/exporter", name="app_dashboard_module_export_participant_page", methods={"GET", "POST"})
* @throws Exception
*/
public function exportParticipant(Module $module, UserRepository $userRepository, ModuleParticipationRepository $moduleParticipationRepository, String $profil){
//$moduleParticipants = $userRepository->findModuleParticipants($module, $this->getUser(), $this->helperService->getUserCurrentRole());
$moduleParticipants = $moduleParticipationRepository->findModuleParticipations($module, $this->getUser());
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$title = $this->formatTitleForExport($module->getName());
$sheet->setTitle($title);
$sheet->setCellValue('A1', 'Liste de participants')
->setCellValue('B1', 'Email');
// if ($role === 'ROLE_ADVISE' || $role === 'ROLE_TUTOR'){
$sheet->setCellValue('C1', 'Filiale');
// }
$row = 2;
foreach ($moduleParticipants as $participant){
$sheet->setCellValue("A{$row}", $participant->getCreatedBy()->getFullName())
->setCellValue("B{$row}", $participant->getCreatedBy()->getEmail());
// if (($role === 'ROLE_ADVISE' || $role === 'ROLE_TUTOR')){
$sheet->setCellValue("C{$row}", ($participant->getCreatedBy()->getSubsidiaryCompany() !== null) ? $participant->getCreatedBy()->getSubsidiaryCompany()->getName() : "");
// }
$row++;
}
$writer = new Xlsx($spreadsheet);
$fileName = $title.".xlsx";
$temp_file = tempnam(sys_get_temp_dir(), $fileName);
$writer->save($temp_file);
return $this->file($temp_file, $fileName, ResponseHeaderBag::DISPOSITION_INLINE);
}
/**
* Require ROLE_ADMIN for this action
*
* @Security("is_granted('ROLE_ADMIN')")
*
* @Route("/{profil}/{participation_id}/supprimer-participation-module", name="app_module_participation_delete", methods={"GET", "POST"})
* @Route("/{profil}/{inscription_id}/supprimer-inscription-module", name="app_module_inscription_delete", methods={"GET", "POST"})
* @ParamConverter("moduleParticipation", isOptional="true", options={"mapping": {"participation_id": "id"}})
* @ParamConverter("moduleInscription", isOptional="true", options={"mapping": {"inscription_id": "id"}})
* @throws Exception
*/
public function deleteModuleParticipant(
Request $request,
ModuleParticipationRepository $moduleParticipationRepository,
UserModuleParticipationRepository $userModuleParticipationRepository,
LiveViewRepository $liveViewRepository,
QuizViewRepository $quizViewRepository,
CourseViewRepository $courseViewRepository,
?ModuleParticipation $moduleParticipation,
?ModuleInscription $moduleInscription,
String $profil
) {
if ($moduleParticipation === null && $moduleInscription === null) return $this->redirect($request->headers->get('referer'));
$participant = ($moduleParticipation !== null) ? $moduleParticipation->getCreatedBy() : $moduleInscription->getUser();
$module = ($moduleParticipation !== null) ? $moduleParticipation->getModule() : $moduleInscription->getModule();
$userModuleParticipations = $userModuleParticipationRepository->findBy(array('module' => $module, 'createdBy' => $participant));
foreach($userModuleParticipations as $userModuleParticipation) {
$userModuleParticipationRepository->remove($userModuleParticipation, true);
}
$moduleParticipations = $moduleParticipationRepository->findBy(array('module' => $module, 'createdBy' => $participant));
foreach($moduleParticipations as $moduleParticipation) {
if($moduleParticipation->getQuiz()) {
$quizViews = $quizViewRepository->findBy(array('quiz' => $moduleParticipation->getQuiz(), 'createdBy' => $participant));
foreach($quizViews as $quizView) {
$quizViewRepository->remove($quizView, true);
}
}
if($moduleParticipation->getLive()) {
$liveViews = $liveViewRepository->findBy(array('live' => $moduleParticipation->getLive(), 'createdBy' => $participant));
foreach($liveViews as $liveView) {
$liveViewRepository->remove($liveView, true);
}
}
if($moduleParticipation->getCourse()) {
$courseViews = $courseViewRepository->findBy(array('course' => $moduleParticipation->getCourse(), 'createdBy' => $participant));
foreach($courseViews as $courseView) {
$courseViewRepository->remove($courseView, true);
}
}
$moduleParticipationRepository->remove($moduleParticipation, true);
}
$this->addFlash("module_participation_deleted", "La participation de ".$participant->getLastname()." ".$participant->getFirstname()." a été supprimée.");
return $this->redirectToRoute('app_dashboard_module_participant_page', ['profil' => $profil, 'id' => $module->getId()], Response::HTTP_SEE_OTHER);
}
/**
* Require ROLE_ADMIN or ROLE_INTEGRATOR or ROLE_ADVISE or ROLE_TUTOR or ROLE_COACH for this action
*
* @Security("is_granted('ROLE_ADMIN') or is_granted('ROLE_INTEGRATOR') or is_granted('ROLE_ADVISE') or is_granted('ROLE_TUTOR') or is_granted('ROLE_COACH')")
*
* @Route("/{profil}/{slug}/modules/send-notification", name="app_dashboard_module_send_notification", methods={"GET", "POST"})
*/
public function sendNotification(Module $module, UserRepository $userRepository, String $profil): Response
{
// $programs = $module->getPrograms();
// $topics = [];
// $deviceTokens = [];
// $users = [];
// if (!$programs->isEmpty()) {
// foreach ($programs as $program) {
// $topic = $this->slugger->slug(strtolower('program_'.$program->getLabel().'_user_to_notified_id'))->toString();
// $topics [] = $topic;
// $users = $userRepository->findSubscribers($program->getSubsidiaryCompanies());
// $users = array_merge($users, $program->getUsers()->toArray());
// }
// $moduleInscriptions = $module->getModuleInscriptions();
// foreach ($moduleInscriptions as $moduleInscription) {
// $user = $moduleInscription->getUser();
// if (!in_array($user, $users)) $users [] = $user;
// }
// if (!empty($users)) $notification = $this->helperService->createNotification($module, [], 'new_module');
// $indexToRemove = array_search($this->getUser(), $users);
// if ($indexToRemove !== false) unset($users[$indexToRemove]);
// foreach ($users as $user) {
// $deviceTokens = $user->getDeviceTokens();
// $topics = array_map(function($item) use ($user) {
// return str_replace('user-to-notified-id', $user->getId(), $item);
// }, $topics);
// if ($deviceTokens !== null && !empty($deviceTokens)) {
// $this->messaging->subscribeToTopics($topics, $deviceTokens);
// }
// $this->pushNotification->sendNotification($module->getCreatedBy(), $user, $topics, 'new_module', $module, false, $notification);
// $this->pushNotification->sendNotification($module->getCreatedBy(), $user, $topics, 'new_module', $module, true);
// }
// } else $topics [] = Constants::DEFAULT_TOPIC;
try {
/** @var User $user */
$user = $this->getUser();
$this->bus->dispatch(new Notification($module->getId(), 'Module', 'new_module', $user->getId()));
} catch (Exception $e) {
}
$flashMessage = "Notification envoyé";
$this->addFlash("new_module_push_notification", $flashMessage);
return $this->redirectToRoute('app_front_module_page', ['profil' => $profil], Response::HTTP_SEE_OTHER);
}
}