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

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