Passed
Push — master ( 7e6742...fd303e )
by
unknown
28:00 queued 14s
created

CourseController::createCourse()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 44
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

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