src/Controller/Front/LiveController.php line 361

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Front;
  3. use App\Entity\Course;
  4. use App\Entity\Live;
  5. use App\Entity\ModuleParticipation;
  6. use App\Entity\Program;
  7. use App\Entity\Quiz;
  8. use App\Entity\Module;
  9. use App\Form\ProgramType;
  10. use App\Helper\ControllerHelper;
  11. use App\Repository\CourseRepository;
  12. use App\Repository\JitsiParameterRepository;
  13. use App\Repository\LiveRepository;
  14. use App\Repository\ModuleItemRepository;
  15. use App\Repository\ModuleParticipationRepository;
  16. use App\Repository\ProgramRepository;
  17. use App\Repository\QuizRepository;
  18. use App\Service\HelperService;
  19. use DateInterval;
  20. use DateTime;
  21. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  22. use Symfony\Component\HttpFoundation\Request;
  23. use Symfony\Component\HttpFoundation\Response;
  24. use Symfony\Component\Routing\Annotation\Route;
  25. use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
  26. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  27. use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
  28. use Symfony\Component\HttpFoundation\JsonResponse;
  29. use Jose\Component\KeyManagement\JWKFactory;
  30. use Jose\Component\Core\AlgorithmManager;
  31. use Jose\Component\Signature\Algorithm\RS256;
  32. use Jose\Component\Signature\JWSBuilder;
  33. use Jose\Component\Signature\Serializer\CompactSerializer;
  34. /**
  35. * Require ROLE_EMPLOYEE for all the actions of this controller
  36. *
  37. * @IsGranted("ROLE_EMPLOYEE")
  38. *
  39. * @Route("/live")
  40. */
  41. class LiveController extends AbstractController
  42. {
  43. use ControllerHelper;
  44. /**
  45. * @Route("/{id}/meeting", name="app_front_live_meet_page")
  46. * @Route("/{id}/{module_slug}/meeting", name="app_front_live_module_meet_page")
  47. * @ParamConverter("module", options={"mapping": {"module_slug": "slug"}})
  48. */
  49. public function index(Request $request, JitsiParameterRepository $jitsiParameterRepository, ModuleParticipationRepository $moduleParticipationRepository, ModuleItemRepository $moduleItemRepository, CourseRepository $courseRepository, QuizRepository $quizRepository, LiveRepository $liveRepository, Live $live, HelperService $helperService, ?Module $module = null): Response
  50. {
  51. $currentUser = $this->getUser();
  52. if ($live === null) throw $this->createAccessDeniedException("Accès non autorisé");
  53. if ($module === null) $module = $this->getActiveModule($live, $currentUser);
  54. $program = new Program();
  55. $form = $this->createForm(ProgramType::class, $program);
  56. $form->handleRequest($request);
  57. $jitsiParameter = $jitsiParameterRepository->findOneBy(['isActive' => true]);
  58. // $module = $this->getActiveModule($live);
  59. if ($jitsiParameter === null || $module === null) {
  60. throw $this->createAccessDeniedException("Impossible de demarrer la conférence. Veuillez contacter l'administrateur !");
  61. }
  62. $isModerator = (($live->getCoaches()->count() > 0 && $live->getCoaches()->contains($currentUser)) || $this->isGranted('ROLE_INTEGRATOR') || $this->isGranted('ROLE_ADMIN'));
  63. // $module = $this->getActiveModule($live);
  64. $_program = $this->getActiveProgram($module, true, $currentUser);
  65. $moduleParticipation = $moduleParticipationRepository->findOneBy(['program' => $_program, 'module' => $module, 'live' => $live, 'createdBy' => $currentUser]);
  66. if ($moduleParticipation === null) {
  67. $moduleParticipation = new ModuleParticipation();
  68. $moduleParticipation->setModule($module);
  69. $moduleParticipation->setLive($live);
  70. $moduleParticipation->setProgram($_program);
  71. $moduleParticipationRepository->add($moduleParticipation, true);
  72. }
  73. $startDate = clone $live->getStartAt();
  74. $endDate = clone $live->getEndAt();
  75. // $liveStartAt = $live->getStartAt()->format('d/m/Y');
  76. // $liveEndAt = $live->getEndAt()->format('d/m/Y');
  77. $liveStartAt = ($startDate !== null) ? $startDate : new DateTime();
  78. $liveEndAt = ($endDate !== null) ? $endDate->add(new DateInterval('P1D')) : $startDate->add(new DateInterval('P1D'));
  79. $liveStartAt->setTime(0, 0, 0);
  80. $liveEndAt->setTime(23, 59, 59);
  81. $nbf = $liveStartAt->format('U');
  82. $exp = $liveEndAt->format('U');
  83. $items = $moduleItemRepository->findItems($module);
  84. $keys = [];
  85. $keys = array_keys(array_column($items, 'live_id'), $live->getId());
  86. $currentItemKey = isset($keys[0]) ? $keys[0] : 0;
  87. $currentItemAsArray = $items[$currentItemKey];
  88. $prevItemAsArray = (isset($items[$currentItemKey - 1])) ? $items[$currentItemKey - 1] : null;
  89. $nextItemAsArray = (isset($items[$currentItemKey + 1])) ? $items[$currentItemKey + 1] : null;
  90. $prevItem = null;
  91. $nextItem = null;
  92. if ($prevItemAsArray !== null && isset($prevItemAsArray['type'])) {
  93. // $prevItem = ($prevItemAsArray['type'] === 'course') ? $courseRepository->findOneById($prevItemAsArray['course_id']) : $quizRepository->findOneById($prevItemAsArray['quiz_id']);
  94. switch ($prevItemAsArray['type']) {
  95. case 'course':
  96. $prevItem = $courseRepository->findOneById($prevItemAsArray['course_id']);
  97. break;
  98. case 'quiz':
  99. $prevItem = $quizRepository->findOneById($prevItemAsArray['quiz_id']);
  100. break;
  101. default:
  102. $prevItem = $liveRepository->findOneById($prevItemAsArray['live_id']);
  103. break;
  104. }
  105. // $prevItem = $quizRepository->findOneById($prevItemAsArray[$prevItemAsArray['type'].'_id']);
  106. }
  107. if ($nextItemAsArray !== null && isset($nextItemAsArray['type'])) {
  108. // $nextItem = ($nextItemAsArray['type'] === 'course') ? $courseRepository->findOneById($nextItemAsArray['course_id']) : $quizRepository->findOneById($nextItemAsArray['quiz_id']);
  109. switch ($nextItemAsArray['type']) {
  110. case 'course':
  111. $nextItem = $courseRepository->findOneById($nextItemAsArray['course_id']);
  112. break;
  113. case 'quiz':
  114. $nextItem = $quizRepository->findOneById($nextItemAsArray['quiz_id']);
  115. break;
  116. default:
  117. $nextItem = $liveRepository->findOneById($nextItemAsArray['live_id']);
  118. break;
  119. }
  120. // $nextItem = $courseRepository->findOneById($nextItemAsArray[$nextItemAsArray['type'].'_id']);
  121. }
  122. $prevItemType = ($prevItem !== null) ? (($prevItem instanceof Course) ? 'course' : (($prevItem instanceof Quiz) ? 'quiz' : 'live')) : null;
  123. $nextItemType = ($nextItem !== null) ? (($nextItem instanceof Course) ? 'course' : (($nextItem instanceof Quiz) ? 'quiz' : 'live')) : null;
  124. // Jaas Token generation
  125. $token = $helperService->getJaasToken($currentUser, $jitsiParameter, $isModerator, $nbf, $exp);
  126. $isQuizzAlreadyStarted = false;
  127. if ($prevItemType === 'quiz' || $nextItemType === 'quiz') {
  128. $moduleParticipation = ($prevItemType === 'quiz') ? $moduleParticipationRepository->findOneBy(['program' => $program, 'module' => $module, 'quiz' => $prevItem, 'createdBy' => $currentUser]) : $moduleParticipationRepository->findOneBy(['module' => $module, 'quiz' => $nextItem, 'createdBy' => $currentUser]);
  129. $isQuizzAlreadyStarted = ($moduleParticipation !== null);
  130. }
  131. return $this->render('front/pages/live/index.html.twig', [
  132. 'program' => $program,
  133. 'live' => $live,
  134. 'form' => $form,
  135. 'jitsiParameter' => $jitsiParameter,
  136. 'isModerator' => $isModerator,
  137. 'nbf' => $nbf,
  138. 'exp' => $exp,
  139. 'module' => $module,
  140. 'prevItem' => $prevItem,
  141. 'prevItemType' => $prevItemType,
  142. 'nextItem' => $nextItem,
  143. 'nextItemType' => $nextItemType,
  144. 'token' => $token,
  145. 'isJaas' => $jitsiParameter->isIsJaas(),
  146. 'canAccess' => $liveStartAt <= (new DateTime())->setTime(0,0,0) && $liveEndAt >= (new DateTime())->setTime(0,0,0),
  147. 'isQuizzAlreadyStarted' => $isQuizzAlreadyStarted
  148. ]);
  149. }
  150. /**
  151. * @Route("/{slug}/meeting-cofilive", name="app_front_cofi_live_meet_page")
  152. * @ParamConverter("live", options={"mapping": {"slug": "slug"}})
  153. */
  154. public function cofilive(Request $request, JitsiParameterRepository $jitsiParameterRepository, LiveRepository $liveRepository, Live $live): Response
  155. {
  156. if ($live === null) throw $this->createAccessDeniedException("Accès non autorisé");
  157. $program = new Program();
  158. $form = $this->createForm(ProgramType::class, $program);
  159. $form->handleRequest($request);
  160. $jitsiParameter = $jitsiParameterRepository->findOneBy(['isActive' => true]);
  161. // $module = $this->getActiveModule($live);
  162. if ($jitsiParameter === null) {
  163. throw $this->createAccessDeniedException("Impossible de demarrer la conférence. Veuillez contacter l'administrateur !");
  164. }
  165. $isModerator = (($live->getCoaches()->count() > 0 && $live->getCoaches()->contains($this->getUser())) || $this->isGranted('ROLE_INTEGRATOR') || $this->isGranted('ROLE_ADMIN'));
  166. $startDate = clone $live->getStartAt();
  167. $endDate = clone $live->getEndAt();
  168. $liveStartAt = ($startDate !== null) ? $startDate : new DateTime();
  169. $liveEndAt = ($endDate !== null) ? $endDate->add(new DateInterval('P1D')) : $startDate->add(new DateInterval('P1D'));
  170. $liveStartAt->setTime(0, 0, 0);
  171. $liveEndAt->setTime(23, 59, 59);
  172. $nbf = $liveStartAt->format('U');
  173. $exp = $liveEndAt->format('U');
  174. $jwk = JWKFactory::createFromKeyFile($this->getParameter('kernel.project_dir').'/jitsi/Cofina.pk');
  175. /**
  176. * Setup the algoritm used to sign the token.
  177. * @var \Jose\Component\Core\AlgorithmManager $algorithm
  178. */
  179. $algorithm = new AlgorithmManager([
  180. new RS256()
  181. ]);
  182. /**
  183. * The builder will create and sign the token.
  184. * @var \Jose\Component\Signature\JWSBuilder $jwsBuilder
  185. */
  186. $jwsBuilder = new JWSBuilder($algorithm);
  187. $currentUser = $this->getUser();
  188. /**
  189. * Must setup JaaS payload!
  190. * Change the claims below or using the variables from above!
  191. */
  192. $payload = json_encode([
  193. 'iss' => 'chat',
  194. 'aud' => 'jitsi',
  195. 'exp' => (int)$exp,
  196. 'nbf' => (int)$nbf,
  197. 'room'=> '*',
  198. 'sub' => $jitsiParameter->getAppId(),
  199. 'context' => [
  200. 'user' => [
  201. 'moderator' => $isModerator ? "true" : "false",
  202. 'email' => $currentUser->getEmail(),
  203. 'name' => $currentUser->getFullName(),
  204. 'avatar' => '/assets/front/img/LOGO COFINA ACADEMY 1.png',
  205. 'id' => $currentUser->getId()
  206. ],
  207. 'features' => [
  208. 'recording' => "true",
  209. 'livestreaming' => "true",
  210. 'transcription' => "true",
  211. 'outbound-call' => "false"
  212. ]
  213. ]
  214. ]);
  215. /**
  216. * Create a JSON Web Signature (https://tools.ietf.org/html/rfc7515)
  217. * using the payload created above and the api key specified for the kid claim.
  218. * 'alg' (RS256) and 'typ' claims are also needed.
  219. */
  220. $jws = $jwsBuilder
  221. ->create()
  222. ->withPayload($payload)
  223. ->addSignature($jwk, [
  224. 'alg' => 'RS256',
  225. 'kid' => $jitsiParameter->getAppSecret(),
  226. 'typ' => 'JWT'
  227. ])
  228. ->build();
  229. /**
  230. * We use the serializer to base64 encode into the final token.
  231. * @var \Jose\Component\Signature\Serializer\CompactSerializer $serializer
  232. */
  233. $serializer = new CompactSerializer();
  234. $token = $serializer->serialize($jws, 0);
  235. //dd(, (new DateTime())->setTime(0,0,0));
  236. //dd((new DateTime())->setTime(0,0,0));
  237. //dd($liveStartAt <= (new DateTime())->setTime(0,0,0) && $liveEndAt >= (new DateTime())->setTime(0,0,0));
  238. return $this->render('front/pages/live/index.html.twig', [
  239. 'program' => $program,
  240. 'live' => $live,
  241. 'form' => $form,
  242. 'jitsiParameter' => $jitsiParameter,
  243. 'isModerator' => $isModerator,
  244. 'nbf' => $nbf,
  245. 'exp' => $exp,
  246. 'module' => null,
  247. 'prevItem' => null,
  248. 'prevItemType' => null,
  249. 'nextItem' => null,
  250. 'nextItemType' => null,
  251. 'token' => $token,
  252. 'isJaas' => $jitsiParameter->isIsJaas(),
  253. 'canAccess' => $liveStartAt <= (new DateTime())->setTime(0,0,0) && $liveEndAt >= (new DateTime())->setTime(0,0,0)
  254. ]);
  255. }
  256. /**
  257. * @Route("/{profil}/page", name="app_front_lives_page")
  258. */
  259. public function live(Request $request, LiveRepository $liveRepository): Response
  260. {
  261. // {
  262. // id: 'a',
  263. // start: '2023-02-03 02:30:00',
  264. // url: "javascript:void(0)",
  265. // link: "{{ url('app_front_homepage') }}",
  266. // classNames: "text-center fw-bold w-100",
  267. // title: "Academy UPB",
  268. // backgroundColor: "transparent",
  269. // borderColor: "transparent",
  270. // textColor: "#000",
  271. // imgUrl: `{{ asset("assets/front/img/users.jpg") }}`,
  272. // imgBackgroundColor: function (){
  273. // const palette = getPalette(this.imgUrl)
  274. // return `repeating-linear-gradient( -45deg, rgb(${palette[0]}) 0 50px, rgb(${palette[1]}) 20px 90px);`
  275. // },
  276. // coachName: "Test",
  277. // coachImg: "{{ asset("assets/front/img/users.jpg") }}"
  278. // }
  279. $lives = $liveRepository->findViewLive($this->getUser());
  280. $liveDate = [];
  281. foreach ($lives as $key => $live) {
  282. $data ['id'] = $live->getId();
  283. $data ['start'] = $live->getStartAt()->format('Y-m-d H:i:s');
  284. $data ['end'] = $live->getEndAt()->format('Y-m-d H:i:s');
  285. //$data ['url'] = $this->generateUrl('app_front_live_meet_page', ['id' => $live->getId()], UrlGeneratorInterface::ABSOLUTE_URL);;
  286. $data ['classNames'] = 'text-center fw-bold w-100';
  287. $data ['title'] = $live->getTitle();
  288. $data ['backgroundColor'] = 'transparent';
  289. $data ['borderColor'] = 'transparent';
  290. $data ['textColor'] = '#000';
  291. $data ['imgUrl'] = ($live->getCover() !== null) ? '/files/images/'.$live->getCover()->getFileName() : '';
  292. $data ['imgBackgroundColor'] = '';
  293. $data ['coachName'] = (!$live->getCoaches()->isEmpty() ? $live->getCoaches()->first()->getFullname() : '');
  294. $data ['coachImg'] = (!$live->getCoaches()->isEmpty() && $live->getCoaches()->first()->getPhoto() !== null ? '/files/images/'.$live->getCoaches()->first()->getPhoto()->getFileName() : '');
  295. $_modules = [];
  296. foreach($live->getModules() as $_module) {
  297. $_modules[] = array('id' => $_module->getId(), 'name' => $_module->getName(), 'slug' => $_module->getSlug(), 'cover' => $_module->getCover());
  298. }
  299. $data['modules'] = $_modules;
  300. $data['slug'] = $live->getSlug();
  301. $liveDate [] = $data;
  302. }
  303. // dump($liveDate); die;
  304. $futureLives = $liveRepository->findFutureLives($this->getUser());
  305. return $this->render('front/pages/live/live.html.twig', [
  306. 'future_lives' => $futureLives,
  307. 'live_data' => $liveDate,
  308. 'lives' => $lives,
  309. ]);
  310. }
  311. /**
  312. * @Route("/{profil}/has-running-live", name="app_front_has_running_live", methods={"GET"})
  313. */
  314. public function hasRunningLive(Request $request, LiveRepository $liveRepository): Response
  315. {
  316. if(!$this->getUser()) {
  317. return null;
  318. }
  319. $lives = $liveRepository->hasCurrentLive($this->getUser());
  320. //dd($lives);
  321. return new JsonResponse(array('runningLive' => count($lives)));
  322. }
  323. }