Passed
Push — master ( 512efb...54663e )
by Angel Fernando Quiroz
10:33 queued 14s
created

CourseController::checkEnrollments()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

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