Passed
Pull Request — master (#5485)
by Angel Fernando Quiroz
07:54
created

CourseController::cidReset()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
c 0
b 0
f 0
nc 1
nop 2
dl 0
loc 11
rs 10
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
declare(strict_types=1);
6
7
namespace Chamilo\CoreBundle\Controller;
8
9
use Chamilo\CoreBundle\Entity\Course;
10
use Chamilo\CoreBundle\Entity\CourseRelUser;
11
use Chamilo\CoreBundle\Entity\ExtraField;
12
use Chamilo\CoreBundle\Entity\Session;
13
use Chamilo\CoreBundle\Entity\SessionRelUser;
14
use Chamilo\CoreBundle\Entity\Tag;
15
use Chamilo\CoreBundle\Entity\Tool;
16
use Chamilo\CoreBundle\Entity\User;
17
use Chamilo\CoreBundle\EventListener\CidReqListener;
18
use Chamilo\CoreBundle\Framework\Container;
19
use Chamilo\CoreBundle\Repository\CourseCategoryRepository;
20
use Chamilo\CoreBundle\Repository\ExtraFieldValuesRepository;
21
use Chamilo\CoreBundle\Repository\LanguageRepository;
22
use Chamilo\CoreBundle\Repository\LegalRepository;
23
use Chamilo\CoreBundle\Repository\Node\CourseRepository;
24
use Chamilo\CoreBundle\Repository\Node\IllustrationRepository;
25
use Chamilo\CoreBundle\Repository\TagRepository;
26
use Chamilo\CoreBundle\Security\Authorization\Voter\CourseVoter;
27
use Chamilo\CoreBundle\Service\CourseService;
28
use Chamilo\CoreBundle\ServiceHelper\AccessUrlHelper;
29
use Chamilo\CoreBundle\ServiceHelper\UserHelper;
30
use Chamilo\CoreBundle\Settings\SettingsManager;
31
use Chamilo\CoreBundle\Tool\ToolChain;
32
use Chamilo\CourseBundle\Controller\ToolBaseController;
33
use Chamilo\CourseBundle\Entity\CCourseDescription;
34
use Chamilo\CourseBundle\Entity\CTool;
35
use Chamilo\CourseBundle\Entity\CToolIntro;
36
use Chamilo\CourseBundle\Repository\CCourseDescriptionRepository;
37
use Chamilo\CourseBundle\Repository\CShortcutRepository;
38
use Chamilo\CourseBundle\Repository\CToolRepository;
39
use Chamilo\CourseBundle\Settings\SettingsCourseManager;
40
use Chamilo\CourseBundle\Settings\SettingsFormFactory;
41
use CourseManager;
42
use Database;
43
use Display;
44
use Doctrine\ORM\EntityManagerInterface;
45
use Event;
46
use Exception;
47
use Exercise;
48
use ExtraFieldValue;
49
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
50
use Symfony\Component\HttpFoundation\JsonResponse;
51
use Symfony\Component\HttpFoundation\RedirectResponse;
52
use Symfony\Component\HttpFoundation\Request;
53
use Symfony\Component\HttpFoundation\Response;
54
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
55
use Symfony\Component\Routing\Attribute\Route;
56
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
57
use Symfony\Component\Serializer\SerializerInterface;
58
use Symfony\Component\Validator\Exception\ValidatorException;
59
use Symfony\Contracts\Translation\TranslatorInterface;
60
use UserManager;
61
62
/**
63
 * @author Julio Montoya <[email protected]>
64
 */
65
#[Route('/course')]
66
class CourseController extends ToolBaseController
67
{
68
    public function __construct(
69
        private readonly EntityManagerInterface $em,
70
        private readonly SerializerInterface $serializer,
71
        private readonly UserHelper $userHelper,
72
    ) {}
73
74
    #[Route('/cidReset', methods: ['GET'])]
75
    public function cidReset(
76
        Request $request,
77
        TokenStorageInterface $tokenStorage,
78
    ): Response {
79
        CidReqListener::cleanSessionHandler(
80
            $request,
81
            $tokenStorage->getToken()
82
        );
83
84
        return new Response('', Response::HTTP_NO_CONTENT);
85
    }
86
87
    #[Route('/{cid}/checkLegal.json', name: 'chamilo_core_course_check_legal_json')]
88
    public function checkTermsAndConditionJson(
89
        Request $request,
90
        LegalRepository $legalTermsRepo,
91
        LanguageRepository $languageRepository,
92
        ExtraFieldValuesRepository $extraFieldValuesRepository,
93
        SettingsManager $settingsManager
94
    ): Response {
95
        $user = $this->userHelper->getCurrent();
96
        $course = $this->getCourse();
97
        $responseData = [
98
            'redirect' => false,
99
            'url' => '#',
100
        ];
101
102
        if ($user && $user->hasRole('ROLE_STUDENT')
103
            && 'true' === $settingsManager->getSetting('allow_terms_conditions')
104
            && 'course' === $settingsManager->getSetting('load_term_conditions_section')
105
        ) {
106
            $termAndConditionStatus = false;
107
            $extraValue = $extraFieldValuesRepository->findLegalAcceptByItemId($user->getId());
108
            if (!empty($extraValue['value'])) {
109
                $result = $extraValue['value'];
110
                $userConditions = explode(':', $result);
111
                $version = $userConditions[0];
112
                $langId = (int) $userConditions[1];
113
                $realVersion = $legalTermsRepo->getLastVersion($langId);
114
                $termAndConditionStatus = ($version >= $realVersion);
115
            }
116
117
            if (false === $termAndConditionStatus) {
118
                $request->getSession()->set('term_and_condition', ['user_id' => $user->getId()]);
119
            } else {
120
                $request->getSession()->remove('term_and_condition');
121
            }
122
123
            $termsAndCondition = $request->getSession()->get('term_and_condition');
124
            if (null !== $termsAndCondition) {
125
                $redirect = true;
126
                $allow = 'true' === Container::getSettingsManager()
127
                    ->getSetting('course.allow_public_course_with_no_terms_conditions')
128
                ;
129
130
                if (true === $allow
131
                    && null !== $course->getVisibility()
132
                    && Course::OPEN_WORLD === $course->getVisibility()
133
                ) {
134
                    $redirect = false;
135
                }
136
                if ($redirect && !$this->isGranted('ROLE_ADMIN')) {
137
                    $url = '/main/auth/inscription.php';
138
                    $responseData = [
139
                        'redirect' => true,
140
                        'url' => $url,
141
                    ];
142
                }
143
            }
144
        }
145
146
        return new JsonResponse($responseData);
147
    }
148
149
    #[Route('/{cid}/home.json', name: 'chamilo_core_course_home_json')]
150
    public function indexJson(
151
        Request $request,
152
        CShortcutRepository $shortcutRepository,
153
        EntityManagerInterface $em,
154
    ): Response {
155
        $requestData = json_decode($request->getContent(), true);
156
        // Sort behaviour
157
        if (!empty($requestData) && isset($requestData['toolItem'])) {
158
            $index = $requestData['index'];
159
            $toolItem = $requestData['toolItem'];
160
            $toolId = (int) $toolItem['iid'];
161
162
            /** @var CTool $cTool */
163
            $cTool = $em->find(CTool::class, $toolId);
164
165
            if ($cTool) {
166
                $cTool->setPosition($index + 1);
167
                $em->persist($cTool);
168
                $em->flush();
169
            }
170
        }
171
172
        $course = $this->getCourse();
173
        $sessionId = $this->getSessionId();
174
        $isInASession = $sessionId > 0;
175
176
        if (null === $course) {
177
            throw $this->createAccessDeniedException();
178
        }
179
180
        if (empty($sessionId)) {
181
            $this->denyAccessUnlessGranted(CourseVoter::VIEW, $course);
182
        }
183
184
        $sessionHandler = $request->getSession();
185
186
        $userId = 0;
187
188
        $user = $this->userHelper->getCurrent();
189
        if (null !== $user) {
190
            $userId = $user->getId();
191
        }
192
193
        $courseCode = $course->getCode();
194
        $courseId = $course->getId();
195
196
        if ($user && $user->hasRole('ROLE_INVITEE')) {
197
            $isSubscribed = CourseManager::is_user_subscribed_in_course(
198
                $userId,
199
                $courseCode,
200
                $isInASession,
201
                $sessionId
202
            );
203
204
            if (!$isSubscribed) {
205
                throw $this->createAccessDeniedException();
206
            }
207
        }
208
209
        $isSpecialCourse = CourseManager::isSpecialCourse($courseId);
210
211
        if ($user && $isSpecialCourse && (isset($_GET['autoreg']) && 1 === (int) $_GET['autoreg'])
212
            && CourseManager::subscribeUser($userId, $courseId, STUDENT)
213
        ) {
214
            $sessionHandler->set('is_allowed_in_course', true);
215
        }
216
217
        $logInfo = [
218
            'tool' => 'course-main',
219
        ];
220
        Event::registerLog($logInfo);
221
222
        // Deleting the objects
223
        $sessionHandler->remove('toolgroup');
224
        $sessionHandler->remove('_gid');
225
        $sessionHandler->remove('oLP');
226
        $sessionHandler->remove('lpobject');
227
228
        api_remove_in_gradebook();
229
        Exercise::cleanSessionVariables();
230
231
        $shortcuts = [];
232
        if (null !== $user) {
233
            $shortcutQuery = $shortcutRepository->getResources($course->getResourceNode());
234
            $shortcuts = $shortcutQuery->getQuery()->getResult();
235
        }
236
        $responseData = [
237
            'shortcuts' => $shortcuts,
238
            'diagram' => '',
239
        ];
240
241
        $json = $this->serializer->serialize(
242
            $responseData,
243
            'json',
244
            [
245
                'groups' => ['course:read', 'ctool:read', 'tool:read', 'cshortcut:read'],
246
            ]
247
        );
248
249
        return new Response(
250
            $json,
251
            Response::HTTP_OK,
252
            [
253
                'Content-type' => 'application/json',
254
            ]
255
        );
256
    }
257
258
    /**
259
     * Redirects the page to a tool, following the tools settings.
260
     */
261
    #[Route('/{cid}/tool/{toolName}', name: 'chamilo_core_course_redirect_tool')]
262
    public function redirectTool(
263
        Request $request,
264
        string $toolName,
265
        CToolRepository $repo,
266
        ToolChain $toolChain
267
    ): RedirectResponse {
268
        /** @var CTool|null $tool */
269
        $tool = $repo->findOneBy([
270
            'title' => $toolName,
271
        ]);
272
273
        if (null === $tool) {
274
            throw new NotFoundHttpException($this->trans('Tool not found'));
275
        }
276
277
        $tool = $toolChain->getToolFromName($tool->getTool()->getTitle());
278
        $link = $tool->getLink();
279
280
        if (null === $this->getCourse()) {
281
            throw new NotFoundHttpException($this->trans('Course not found'));
282
        }
283
        $optionalParams = '';
284
285
        $optionalParams = $request->query->get('cert') ? '&cert='.$request->query->get('cert') : '';
286
287
        if (strpos($link, 'nodeId')) {
288
            $nodeId = (string) $this->getCourse()->getResourceNode()->getId();
289
            $link = str_replace(':nodeId', $nodeId, $link);
290
        }
291
292
        $url = $link.'?'.$this->getCourseUrlQuery().$optionalParams;
293
294
        return $this->redirect($url);
295
    }
296
297
    /*public function redirectToShortCut(string $toolName, CToolRepository $repo, ToolChain $toolChain): RedirectResponse
298
    {
299
        $tool = $repo->findOneBy([
300
            'name' => $toolName,
301
        ]);
302
303
        if (null === $tool) {
304
            throw new NotFoundHttpException($this->trans('Tool not found'));
305
        }
306
307
        $tool = $toolChain->getToolFromName($tool->getTool()->getTitle());
308
        $link = $tool->getLink();
309
310
        if (strpos($link, 'nodeId')) {
311
            $nodeId = (string) $this->getCourse()->getResourceNode()->getId();
312
            $link = str_replace(':nodeId', $nodeId, $link);
313
        }
314
315
        $url = $link.'?'.$this->getCourseUrlQuery();
316
317
        return $this->redirect($url);
318
    }*/
319
320
    /**
321
     * Edit configuration with given namespace.
322
     */
323
    #[Route('/{course}/settings/{namespace}', name: 'chamilo_core_course_settings')]
324
    public function updateSettings(
325
        Request $request,
326
        #[MapEntity(expr: 'repository.find(cid)')]
327
        Course $course,
328
        string $namespace,
329
        SettingsCourseManager $manager,
330
        SettingsFormFactory $formFactory
331
    ): Response {
332
        $this->denyAccessUnlessGranted(CourseVoter::VIEW, $course);
333
334
        $schemaAlias = $manager->convertNameSpaceToService($namespace);
335
        $settings = $manager->load($namespace);
336
337
        $form = $formFactory->create($schemaAlias);
338
339
        $form->setData($settings);
340
        $form->handleRequest($request);
341
342
        if ($form->isSubmitted() && $form->isValid()) {
343
            $messageType = 'success';
344
345
            try {
346
                $manager->setCourse($course);
347
                $manager->save($form->getData());
348
                $message = $this->trans('Update');
349
            } catch (ValidatorException $validatorException) {
350
                $message = $this->trans($validatorException->getMessage());
351
                $messageType = 'error';
352
            }
353
            $this->addFlash($messageType, $message);
354
355
            if ($request->headers->has('referer')) {
356
                return $this->redirect($request->headers->get('referer'));
357
            }
358
        }
359
360
        $schemas = $manager->getSchemas();
361
362
        return $this->render(
363
            '@ChamiloCore/Course/settings.html.twig',
364
            [
365
                'course' => $course,
366
                'schemas' => $schemas,
367
                'settings' => $settings,
368
                'form' => $form,
369
            ]
370
        );
371
    }
372
373
    #[Route('/{id}/about', name: 'chamilo_core_course_about')]
374
    public function about(
375
        Course $course,
376
        IllustrationRepository $illustrationRepository,
377
        CCourseDescriptionRepository $courseDescriptionRepository,
378
        EntityManagerInterface $em
379
    ): Response {
380
        $courseId = $course->getId();
381
382
        $user = $this->userHelper->getCurrent();
383
384
        $fieldsRepo = $em->getRepository(ExtraField::class);
385
386
        /** @var TagRepository $tagRepo */
387
        $tagRepo = $em->getRepository(Tag::class);
388
389
        $courseDescriptions = $courseDescriptionRepository->getResourcesByCourse($course)->getQuery()->getResult();
390
391
        $courseValues = new ExtraFieldValue('course');
392
393
        $urlCourse = api_get_path(WEB_PATH).sprintf('course/%s/about', $courseId);
394
        $courseTeachers = $course->getTeachersSubscriptions();
395
        $teachersData = [];
396
397
        foreach ($courseTeachers as $teacherSubscription) {
398
            $teacher = $teacherSubscription->getUser();
399
            $userData = [
400
                'complete_name' => UserManager::formatUserFullName($teacher),
401
                'image' => $illustrationRepository->getIllustrationUrl($teacher),
402
                'diploma' => $teacher->getDiplomas(),
403
                'openarea' => $teacher->getOpenarea(),
404
            ];
405
406
            $teachersData[] = $userData;
407
        }
408
409
        /** @var ExtraField $tagField */
410
        $tagField = $fieldsRepo->findOneBy([
411
            'itemType' => ExtraField::COURSE_FIELD_TYPE,
412
            'variable' => 'tags',
413
        ]);
414
415
        $courseTags = [];
416
        if (null !== $tagField) {
417
            $courseTags = $tagRepo->getTagsByItem($tagField, $courseId);
418
        }
419
420
        $courseDescription = $courseObjectives = $courseTopics = $courseMethodology = '';
421
        $courseMaterial = $courseResources = $courseAssessment = '';
422
        $courseCustom = [];
423
        foreach ($courseDescriptions as $descriptionTool) {
424
            switch ($descriptionTool->getDescriptionType()) {
425
                case CCourseDescription::TYPE_DESCRIPTION:
426
                    $courseDescription = $descriptionTool->getContent();
427
428
                    break;
429
430
                case CCourseDescription::TYPE_OBJECTIVES:
431
                    $courseObjectives = $descriptionTool;
432
433
                    break;
434
435
                case CCourseDescription::TYPE_TOPICS:
436
                    $courseTopics = $descriptionTool;
437
438
                    break;
439
440
                case CCourseDescription::TYPE_METHODOLOGY:
441
                    $courseMethodology = $descriptionTool;
442
443
                    break;
444
445
                case CCourseDescription::TYPE_COURSE_MATERIAL:
446
                    $courseMaterial = $descriptionTool;
447
448
                    break;
449
450
                case CCourseDescription::TYPE_RESOURCES:
451
                    $courseResources = $descriptionTool;
452
453
                    break;
454
455
                case CCourseDescription::TYPE_ASSESSMENT:
456
                    $courseAssessment = $descriptionTool;
457
458
                    break;
459
460
                case CCourseDescription::TYPE_CUSTOM:
461
                    $courseCustom[] = $descriptionTool;
462
463
                    break;
464
            }
465
        }
466
467
        $topics = [
468
            'objectives' => $courseObjectives,
469
            'topics' => $courseTopics,
470
            'methodology' => $courseMethodology,
471
            'material' => $courseMaterial,
472
            'resources' => $courseResources,
473
            'assessment' => $courseAssessment,
474
            'custom' => array_reverse($courseCustom),
475
        ];
476
477
        $subscriptionUser = false;
478
479
        if ($user) {
480
            $subscriptionUser = CourseManager::is_user_subscribed_in_course($user->getId(), $course->getCode());
481
        }
482
483
        /*$allowSubscribe = false;
484
        if ($course->getSubscribe() || api_is_platform_admin()) {
485
            $allowSubscribe = true;
486
        }
487
        $plugin = \BuyCoursesPlugin::create();
488
        $checker = $plugin->isEnabled();
489
        $courseIsPremium = null;
490
        if ($checker) {
491
            $courseIsPremium = $plugin->getItemByProduct(
492
                $courseId,
493
                \BuyCoursesPlugin::PRODUCT_TYPE_COURSE
494
            );
495
        }*/
496
497
        $image = Container::getIllustrationRepository()->getIllustrationUrl($course, 'course_picture_medium');
498
499
        $params = [
500
            'course' => $course,
501
            'description' => $courseDescription,
502
            'image' => $image,
503
            'syllabus' => $topics,
504
            'tags' => $courseTags,
505
            'teachers' => $teachersData,
506
            'extra_fields' => $courseValues->getAllValuesForAnItem(
507
                $course->getId(),
508
                null,
509
                true
510
            ),
511
            'subscription' => $subscriptionUser,
512
            'url' => '',
513
            'is_premium' => '',
514
            'token' => '',
515
        ];
516
517
        $metaInfo = '<meta property="og:url" content="'.$urlCourse.'" />';
518
        $metaInfo .= '<meta property="og:type" content="website" />';
519
        $metaInfo .= '<meta property="og:title" content="'.$course->getTitle().'" />';
520
        $metaInfo .= '<meta property="og:description" content="'.strip_tags($courseDescription).'" />';
521
        $metaInfo .= '<meta property="og:image" content="'.$image.'" />';
522
523
        $htmlHeadXtra[] = $metaInfo;
524
        $htmlHeadXtra[] = api_get_asset('readmore-js/readmore.js');
525
526
        return $this->render('@ChamiloCore/Course/about.html.twig', $params);
527
    }
528
529
    #[Route('/{id}/welcome', name: 'chamilo_core_course_welcome')]
530
    public function welcome(Course $course): Response
531
    {
532
        return $this->render('@ChamiloCore/Course/welcome.html.twig', [
533
            'course' => $course,
534
        ]);
535
    }
536
537
    private function findIntroOfCourse(Course $course): ?CTool
538
    {
539
        $qb = $this->em->createQueryBuilder();
540
541
        $query = $qb->select('ct')
542
            ->from(CTool::class, 'ct')
543
            ->where('ct.course = :c_id')
544
            ->andWhere('ct.title = :title')
545
            ->andWhere(
546
                $qb->expr()->orX(
547
                    $qb->expr()->eq('ct.session', ':session_id'),
548
                    $qb->expr()->isNull('ct.session')
549
                )
550
            )
551
            ->setParameters([
552
                'c_id' => $course->getId(),
553
                'title' => 'course_homepage',
554
                'session_id' => 0,
555
            ])
556
            ->getQuery()
557
        ;
558
559
        return $query->getOneOrNullResult();
560
    }
561
562
    #[Route('/{id}/getToolIntro', name: 'chamilo_core_course_gettoolintro')]
563
    public function getToolIntro(Request $request, Course $course, EntityManagerInterface $em): Response
564
    {
565
        $sessionId = (int) $request->get('sid');
566
567
        // $session = $this->getSession();
568
        $responseData = [];
569
        $ctoolRepo = $em->getRepository(CTool::class);
570
        $sessionRepo = $em->getRepository(Session::class);
571
        $createInSession = false;
572
573
        $session = null;
574
575
        if (!empty($sessionId)) {
576
            $session = $sessionRepo->find($sessionId);
577
        }
578
579
        $ctool = $this->findIntroOfCourse($course);
580
581
        if ($session) {
582
            $ctoolSession = $ctoolRepo->findOneBy(['title' => 'course_homepage', 'course' => $course, 'session' => $session]);
583
584
            if (!$ctoolSession) {
585
                $createInSession = true;
586
            } else {
587
                $ctool = $ctoolSession;
588
            }
589
        }
590
591
        if ($ctool) {
592
            $ctoolintroRepo = $em->getRepository(CToolIntro::class);
593
594
            /** @var CToolIntro $ctoolintro */
595
            $ctoolintro = $ctoolintroRepo->findOneBy(['courseTool' => $ctool]);
596
            if ($ctoolintro) {
597
                $responseData = [
598
                    'iid' => $ctoolintro->getIid(),
599
                    'introText' => $ctoolintro->getIntroText(),
600
                    'createInSession' => $createInSession,
601
                    'cToolId' => $ctool->getIid(),
602
                ];
603
            }
604
            $responseData['c_tool'] = [
605
                'iid' => $ctool->getIid(),
606
                'title' => $ctool->getTitle(),
607
            ];
608
        }
609
610
        return new JsonResponse($responseData);
611
    }
612
613
    #[Route('/{id}/addToolIntro', name: 'chamilo_core_course_addtoolintro')]
614
    public function addToolIntro(Request $request, Course $course, EntityManagerInterface $em): Response
615
    {
616
        $data = $request->getContent();
617
        $data = json_decode($data);
618
        $ctoolintroId = $data->iid;
619
        $sessionId = $data->sid ?? 0;
620
621
        $sessionRepo = $em->getRepository(Session::class);
622
        $session = null;
623
        if (!empty($sessionId)) {
624
            $session = $sessionRepo->find($sessionId);
625
        }
626
627
        $ctool = $em->getRepository(CTool::class);
628
        $check = $ctool->findOneBy(['title' => 'course_homepage', 'course' => $course, 'session' => $session]);
629
        if (!$check) {
630
            $toolRepo = $em->getRepository(Tool::class);
631
            $toolEntity = $toolRepo->findOneBy(['title' => 'course_homepage']);
632
            $courseTool = (new CTool())
633
                ->setTool($toolEntity)
634
                ->setTitle('course_homepage')
635
                ->setCourse($course)
636
                ->setPosition(1)
637
                ->setVisibility(true)
638
                ->setParent($course)
639
                ->setCreator($course->getCreator())
640
                ->setSession($session)
641
                ->addCourseLink($course)
642
            ;
643
            $em->persist($courseTool);
644
            $em->flush();
645
            if ($courseTool && !empty($ctoolintroId)) {
646
                $ctoolintroRepo = Container::getToolIntroRepository();
647
648
                /** @var CToolIntro $ctoolintro */
649
                $ctoolintro = $ctoolintroRepo->find($ctoolintroId);
650
                $ctoolintro->setCourseTool($courseTool);
651
                $ctoolintroRepo->update($ctoolintro);
652
            }
653
        }
654
        $responseData = [];
655
        $json = $this->serializer->serialize(
656
            $responseData,
657
            'json',
658
            [
659
                'groups' => ['course:read', 'ctool:read', 'tool:read', 'cshortcut:read'],
660
            ]
661
        );
662
663
        return new JsonResponse($responseData);
664
    }
665
666
    #[Route('/check-enrollments', name: 'chamilo_core_check_enrollments', methods: ['GET'])]
667
    public function checkEnrollments(EntityManagerInterface $em, SettingsManager $settingsManager): JsonResponse
668
    {
669
        $user = $this->userHelper->getCurrent();
670
671
        if (!$user) {
672
            return new JsonResponse(['error' => 'User not found'], Response::HTTP_UNAUTHORIZED);
673
        }
674
675
        $isEnrolledInCourses = $this->isUserEnrolledInAnyCourse($user, $em);
676
        $isEnrolledInSessions = $this->isUserEnrolledInAnySession($user, $em);
677
678
        if (!$isEnrolledInCourses && !$isEnrolledInSessions) {
679
            $defaultMenuEntry = $settingsManager->getSetting('platform.default_menu_entry_for_course_or_session');
680
            $isEnrolledInCourses = 'my_courses' === $defaultMenuEntry;
681
            $isEnrolledInSessions = 'my_sessions' === $defaultMenuEntry;
682
        }
683
684
        return new JsonResponse([
685
            'isEnrolledInCourses' => $isEnrolledInCourses,
686
            'isEnrolledInSessions' => $isEnrolledInSessions,
687
        ]);
688
    }
689
690
    #[Route('/categories', name: 'chamilo_core_course_form_lists')]
691
    public function getCategories(
692
        SettingsManager $settingsManager,
693
        AccessUrlHelper $accessUrlHelper,
694
        CourseCategoryRepository $courseCategoriesRepo
695
    ): JsonResponse {
696
        $allowBaseCourseCategory = 'true' === $settingsManager->getSetting('course.allow_base_course_category');
697
        $accessUrlId = $accessUrlHelper->getCurrent()->getId();
698
699
        $categories = $courseCategoriesRepo->findAllInAccessUrl(
700
            $accessUrlId,
701
            $allowBaseCourseCategory
702
        );
703
704
        $data = [];
705
        $categoryToAvoid = '';
706
        if (!$this->isGranted('ROLE_ADMIN')) {
707
            $categoryToAvoid = $settingsManager->getSetting('course.course_category_code_to_use_as_model');
708
        }
709
710
        foreach ($categories as $category) {
711
            $categoryCode = $category->getCode();
712
            if (!empty($categoryToAvoid) && $categoryToAvoid == $categoryCode) {
713
                continue;
714
            }
715
            $data[] = ['id' => $category->getId(), 'name' => $category->__toString()];
716
        }
717
718
        return new JsonResponse($data);
719
    }
720
721
    #[Route('/search_templates', name: 'chamilo_core_course_search_templates')]
722
    public function searchCourseTemplates(
723
        Request $request,
724
        AccessUrlHelper $accessUrlHelper,
725
        CourseRepository $courseRepository
726
    ): JsonResponse {
727
        $searchTerm = $request->query->get('search', '');
728
        $accessUrl = $accessUrlHelper->getCurrent();
729
730
        $user = $this->userHelper->getCurrent();
731
732
        $courseList = $courseRepository->getCoursesInfoByUser($user, $accessUrl, 1, $searchTerm);
733
        $results = ['items' => []];
734
        foreach ($courseList as $course) {
735
            $title = $course['title'];
736
            $results['items'][] = [
737
                'id' => $course['id'],
738
                'name' => $title.' ('.$course['code'].') ',
739
            ];
740
        }
741
742
        return new JsonResponse($results);
743
    }
744
745
    #[Route('/create', name: 'chamilo_core_course_create')]
746
    public function createCourse(
747
        Request $request,
748
        TranslatorInterface $translator,
749
        CourseService $courseService
750
    ): JsonResponse {
751
        $courseData = json_decode($request->getContent(), true);
752
753
        $title = $courseData['name'] ?? null;
754
        $wantedCode = $courseData['code'] ?? null;
755
        $courseLanguage = $courseData['language']['id'] ?? null;
756
        $categoryCode = $courseData['category'] ?? null;
757
        $exemplaryContent = $courseData['fillDemoContent'] ?? false;
758
        $template = $courseData['template'] ?? '';
759
760
        $params = [
761
            'title' => $title,
762
            'wanted_code' => $wantedCode,
763
            'course_language' => $courseLanguage,
764
            'exemplary_content' => $exemplaryContent,
765
            'course_template' => $template,
766
        ];
767
768
        if ($categoryCode) {
769
            $params['course_categories'] = $categoryCode;
770
        }
771
772
        try {
773
            $course = $courseService->createCourse($params);
774
            if ($course) {
775
                return new JsonResponse([
776
                    'success' => true,
777
                    'message' => $translator->trans('Course created successfully.'),
778
                    'courseId' => $course->getId(),
779
                ]);
780
            }
781
        } catch (Exception $e) {
782
            return new JsonResponse([
783
                'success' => false,
784
                'message' => $translator->trans($e->getMessage()),
785
            ], Response::HTTP_BAD_REQUEST);
786
        }
787
788
        return new JsonResponse(['success' => false, 'message' => $translator->trans('An error occurred while creating the course.')]);
789
    }
790
791
    private function autoLaunch(): void
792
    {
793
        $autoLaunchWarning = '';
794
        $showAutoLaunchLpWarning = false;
795
        $course_id = api_get_course_int_id();
796
        $lpAutoLaunch = api_get_course_setting('enable_lp_auto_launch');
797
        $session_id = api_get_session_id();
798
        $allowAutoLaunchForCourseAdmins =
799
            api_is_platform_admin()
800
            || api_is_allowed_to_edit(true, true)
801
            || api_is_coach();
802
803
        if (!empty($lpAutoLaunch)) {
804
            if (2 === $lpAutoLaunch) {
805
                // LP list
806
                if ($allowAutoLaunchForCourseAdmins) {
807
                    $showAutoLaunchLpWarning = true;
808
                } else {
809
                    $session_key = 'lp_autolaunch_'.$session_id.'_'.$course_id.'_'.api_get_user_id();
810
                    if (!isset($_SESSION[$session_key])) {
811
                        // Redirecting to the LP
812
                        $url = api_get_path(WEB_CODE_PATH).'lp/lp_controller.php?'.api_get_cidreq();
813
                        $_SESSION[$session_key] = true;
814
                        header(sprintf('Location: %s', $url));
815
816
                        exit;
817
                    }
818
                }
819
            } else {
820
                $lp_table = Database::get_course_table(TABLE_LP_MAIN);
821
                $condition = '';
822
                if (!empty($session_id)) {
823
                    $condition = api_get_session_condition($session_id);
824
                    $sql = "SELECT id FROM {$lp_table}
825
                            WHERE c_id = {$course_id} AND autolaunch = 1 {$condition}
826
                            LIMIT 1";
827
                    $result = Database::query($sql);
828
                    // If we found nothing in the session we just called the session_id =  0 autolaunch
829
                    if (0 === Database::num_rows($result)) {
830
                        $condition = '';
831
                    }
832
                }
833
834
                $sql = "SELECT iid FROM {$lp_table}
835
                        WHERE c_id = {$course_id} AND autolaunch = 1 {$condition}
836
                        LIMIT 1";
837
                $result = Database::query($sql);
838
                if (Database::num_rows($result) > 0) {
839
                    $lp_data = Database::fetch_array($result);
840
                    if (!empty($lp_data['iid'])) {
841
                        if ($allowAutoLaunchForCourseAdmins) {
842
                            $showAutoLaunchLpWarning = true;
843
                        } else {
844
                            $session_key = 'lp_autolaunch_'.$session_id.'_'.api_get_course_int_id().'_'.api_get_user_id();
845
                            if (!isset($_SESSION[$session_key])) {
846
                                // Redirecting to the LP
847
                                $url = api_get_path(WEB_CODE_PATH).
848
                                    'lp/lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.$lp_data['iid'];
849
850
                                $_SESSION[$session_key] = true;
851
                                header(sprintf('Location: %s', $url));
852
853
                                exit;
854
                            }
855
                        }
856
                    }
857
                }
858
            }
859
        }
860
861
        if ($showAutoLaunchLpWarning) {
862
            $autoLaunchWarning = get_lang(
863
                'The learning path auto-launch setting is ON. When learners enter this course, they will be automatically redirected to the learning path marked as auto-launch.'
864
            );
865
        }
866
867
        $forumAutoLaunch = (int) api_get_course_setting('enable_forum_auto_launch');
868
        if (1 === $forumAutoLaunch) {
869
            if ($allowAutoLaunchForCourseAdmins) {
870
                if (empty($autoLaunchWarning)) {
871
                    $autoLaunchWarning = get_lang(
872
                        "The forum's auto-launch setting is on. Students will be redirected to the forum tool when entering this course."
873
                    );
874
                }
875
            } else {
876
                $url = api_get_path(WEB_CODE_PATH).'forum/index.php?'.api_get_cidreq();
877
                header(sprintf('Location: %s', $url));
878
879
                exit;
880
            }
881
        }
882
883
        if ('true' === api_get_setting('exercise.allow_exercise_auto_launch')) {
884
            $exerciseAutoLaunch = (int) api_get_course_setting('enable_exercise_auto_launch');
885
            if (2 === $exerciseAutoLaunch) {
886
                if ($allowAutoLaunchForCourseAdmins) {
887
                    if (empty($autoLaunchWarning)) {
888
                        $autoLaunchWarning = get_lang(
889
                            'TheExerciseAutoLaunchSettingIsONStudentsWillBeRedirectToTheExerciseList'
890
                        );
891
                    }
892
                } else {
893
                    // Redirecting to the document
894
                    $url = api_get_path(WEB_CODE_PATH).'exercise/exercise.php?'.api_get_cidreq();
895
                    header(sprintf('Location: %s', $url));
896
897
                    exit;
898
                }
899
            } elseif (1 === $exerciseAutoLaunch) {
900
                if ($allowAutoLaunchForCourseAdmins) {
901
                    if (empty($autoLaunchWarning)) {
902
                        $autoLaunchWarning = get_lang(
903
                            'TheExerciseAutoLaunchSettingIsONStudentsWillBeRedirectToAnSpecificExercise'
904
                        );
905
                    }
906
                } else {
907
                    // Redirecting to an exercise
908
                    $table = Database::get_course_table(TABLE_QUIZ_TEST);
909
                    $condition = '';
910
                    if (!empty($session_id)) {
911
                        $condition = api_get_session_condition($session_id);
912
                        $sql = "SELECT iid FROM {$table}
913
                                WHERE c_id = {$course_id} AND autolaunch = 1 {$condition}
914
                                LIMIT 1";
915
                        $result = Database::query($sql);
916
                        // If we found nothing in the session we just called the session_id = 0 autolaunch
917
                        if (0 === Database::num_rows($result)) {
918
                            $condition = '';
919
                        }
920
                    }
921
922
                    $sql = "SELECT iid FROM {$table}
923
                            WHERE c_id = {$course_id} AND autolaunch = 1 {$condition}
924
                            LIMIT 1";
925
                    $result = Database::query($sql);
926
                    if (Database::num_rows($result) > 0) {
927
                        $row = Database::fetch_array($result);
928
                        $exerciseId = $row['iid'];
929
                        $url = api_get_path(WEB_CODE_PATH).
930
                            'exercise/overview.php?exerciseId='.$exerciseId.'&'.api_get_cidreq();
931
                        header(sprintf('Location: %s', $url));
932
933
                        exit;
934
                    }
935
                }
936
            }
937
        }
938
939
        $documentAutoLaunch = (int) api_get_course_setting('enable_document_auto_launch');
940
        if (1 === $documentAutoLaunch) {
941
            if ($allowAutoLaunchForCourseAdmins) {
942
                if (empty($autoLaunchWarning)) {
943
                    $autoLaunchWarning = get_lang(
944
                        'The document auto-launch feature configuration is enabled. Learners will be automatically redirected to document tool.'
945
                    );
946
                }
947
            } else {
948
                // Redirecting to the document
949
                $url = api_get_path(WEB_CODE_PATH).'document/document.php?'.api_get_cidreq();
950
                header("Location: $url");
951
952
                exit;
953
            }
954
        }
955
956
        /*  SWITCH TO A DIFFERENT HOMEPAGE VIEW
957
         the setting homepage_view is adjustable through
958
         the platform administration section */
959
        if (!empty($autoLaunchWarning)) {
960
            $this->addFlash(
961
                'warning',
962
                Display::return_message(
963
                    $autoLaunchWarning,
964
                    'warning'
965
                )
966
            );
967
        }
968
    }
969
970
    // Implement the real logic to check course enrollment
971
    private function isUserEnrolledInAnyCourse(User $user, EntityManagerInterface $em): bool
972
    {
973
        $enrollmentCount = $em
974
            ->getRepository(CourseRelUser::class)
975
            ->count(['user' => $user])
976
        ;
977
978
        return $enrollmentCount > 0;
979
    }
980
981
    // Implement the real logic to check session enrollment
982
    private function isUserEnrolledInAnySession(User $user, EntityManagerInterface $em): bool
983
    {
984
        $enrollmentCount = $em->getRepository(SessionRelUser::class)
985
            ->count(['user' => $user])
986
        ;
987
988
        return $enrollmentCount > 0;
989
    }
990
}
991