Passed
Pull Request — master (#5859)
by
unknown
07:18
created

CourseController::getAutoLaunchLPId()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

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