Passed
Pull Request — master (#5485)
by Yannick
07:24
created

CourseController::updateSettings()   A

Complexity

Conditions 5
Paths 9

Size

Total Lines 46
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

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