Passed
Push — master ( f437d8...92f70a )
by Julito
10:14
created

CourseManager   F

Complexity

Total Complexity 806

Size/Duplication

Total Lines 6850
Duplicated Lines 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 3284
dl 0
loc 6850
rs 0.8
c 2
b 1
f 0
wmc 806

129 Methods

Rating   Name   Duplication   Size   Complexity  
A removeUserVisibilityToCourseInCatalogue() 0 33 5
A get_course_information() 0 8 1
B get_course_list_of_user_as_course_admin() 0 65 7
A isUserSubscribedInCourseAsDrh() 0 26 5
A getEntityManager() 0 3 1
A setEntityManager() 0 3 1
A getManager() 0 3 1
B addUserVisibilityToCourseInCatalogue() 0 50 8
A setCourseManager() 0 3 1
A getCourseSettingsManager() 0 3 1
A setCourseSettingsManager() 0 3 1
A course_code_exists() 0 9 1
F get_courses_list() 0 110 22
A get_tutor_in_course_status() 0 15 1
A getUserInCourseStatus() 0 18 2
A updateUserCourseTutor() 0 18 2
A getUserCourseInfo() 0 9 1
F create_course() 0 76 17
A get_courses_followed_by_drh() 0 17 1
A isSpecialCourse() 0 15 3
B subscribeCoursesToDrhManager() 0 48 7
A get_course_category() 0 7 1
F getCoursesFollowedByUser() 0 107 14
A deleteCoursePicture() 0 18 4
A update_course_picture() 0 38 6
A session_items_html() 0 20 2
B course_item_html_no_icon() 0 44 7
A getCountForum() 0 21 2
A addUserGroupMultiSelect() 0 22 2
A addGroupMultiSelect() 0 11 2
A getCountForumPerUser() 0 25 1
A getCourseUsers() 0 19 1
A getCourseSettings() 0 14 3
A getCourseAccessPerSessionAndUser() 0 17 2
C buildSelectOptions() 0 58 15
A getCourseGroups() 0 18 2
B separateUsersGroups() 0 26 7
A generate_course_code() 0 6 1
A getCountPostInForumPerUser() 0 25 1
A getFirstCourseAccessPerSessionAndUser() 0 18 2
A getCourseAccessPerCourseAndSession() 0 22 1
A hasCourseSetting() 0 10 1
A getCourseNameFromCode() 0 10 2
A get_course_list() 0 5 1
A saveCourseConfigurationSetting() 0 35 4
A is_course_teacher() 0 20 4
C update_course_ranking() 0 67 14
A get_teacher_list_from_course_code() 0 28 3
A get_course_id_from_original_id() 0 13 2
A get_email_of_tutor_to_session() 0 38 4
B redirectToCourse() 0 50 8
B is_user_subscribed_in_real_or_linked_course() 0 57 6
F getCourseParamsForDisplay() 0 150 16
A countActiveCourses() 0 18 3
F get_logged_user_course_html() 0 222 39
A get_course_code_from_original_id() 0 25 2
A generate_nice_next_course_code() 0 25 4
A setToolList() 0 3 1
A getCourseVisibilitySQLCondition() 0 31 5
A getToolList() 0 3 1
B userCourseSort() 0 81 9
A update_course_extra_field_value() 0 13 1
C get_student_list_from_course_code() 0 80 13
F get_user_list_from_course_code() 0 376 63
F returnCoursesWithoutCategories() 0 131 16
A count_courses() 0 23 5
A get_session_category_id_by_session_id() 0 16 2
A remove_course_ranking() 0 14 4
B returnCourses() 0 73 8
B getTeacherListFromCourseCodeToString() 0 46 7
A copy_course() 0 25 2
A fillCourse() 0 31 4
A get_details_course_description_html() 0 25 5
A copy_course_simple() 0 32 5
A email_to_tutor() 0 68 4
B getCatalogueCourseList() 0 43 7
A getCountOpenCourses() 0 16 1
A get_user_course_categories() 0 15 3
A hasPicture() 0 3 1
B is_user_subscribed_in_course() 0 65 9
A getUserCourseCategoryForCourse() 0 22 2
D get_access_link_by_user() 0 63 35
A getCourseInfoFromOriginalId() 0 15 2
A getCountExercisesFromOpenCourse() 0 18 1
A autoSubscribeToCourse() 0 32 4
A update_attribute() 0 8 1
A get_emails_of_tutors_to_course() 0 21 3
A getPicturePath() 0 11 3
F returnCoursesCategories() 0 186 26
A getCourseCategoriesFromCourseList() 0 8 1
A course_exists() 0 7 1
A save_user_legal() 0 27 3
A checkCreateCourseAccessUrlParam() 0 14 4
C delete_course() 0 179 14
A getCoursesWithoutSession() 0 25 5
A get_course_code_from_course_id() 0 11 2
A get_user_course_vote() 0 33 5
A createDefaultGradebook() 0 12 5
A get_courses_info_from_visual_code() 0 10 2
A get_special_course_list() 0 42 5
A getCourseCodeFromDirectory() 0 14 3
B is_user_accepted_legal() 0 45 7
A get_course_extra_field_value() 0 12 2
A create_course_extra_field() 0 11 1
A get_course_ranking() 0 45 5
A useTemplateAsBasisIfRequired() 0 25 6
B create_database_dump() 0 35 7
B return_hot_courses() 0 55 6
D get_courses_list_by_user_id() 0 144 21
F updateTeachers() 0 138 28
A update_attributes() 0 18 4
B get_coachs_from_course_to_string() 0 49 7
A get_count_user_list_from_course_code() 0 21 1
B get_coach_list_from_course_code() 0 41 8
A getCoursesFollowedByGroupAdmin() 0 43 5
D unsubscribe_user() 0 140 18
A get_course_by_category() 0 8 2
F subscribeUser() 0 178 21
B add_course_vote() 0 69 9
A getCourseSettingVariables() 0 63 4
C processHotCourseItem() 0 107 15
A return_most_accessed_courses() 0 14 1
A get_coachs_from_course() 0 40 5
D returnSpecialCourses() 0 121 18
B get_group_list_of_course() 0 41 6
A get_users_count_in_course() 0 59 5
A getCountRegisteredUsersWithCourseExtraField() 0 29 6
A getTeachersFromCourse() 0 43 4
A returnDescriptionButton() 0 25 3

How to fix   Complexity   

Complex Class

Complex classes like CourseManager often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use CourseManager, and based on these observations, apply Extract Interface, too.

1
<?php
2
/* For licensing terms, see /license.txt*/
3
4
use Chamilo\CoreBundle\Entity\Course;
5
use Chamilo\CoreBundle\Entity\ExtraField as EntityExtraField;
6
use Chamilo\CourseBundle\Component\CourseCopy\CourseBuilder;
7
use Chamilo\CourseBundle\Component\CourseCopy\CourseRestorer;
8
use Chamilo\CourseBundle\Manager\SettingsManager;
9
use Chamilo\CourseBundle\ToolChain;
10
use ChamiloSession as Session;
11
12
/**
13
 * Class CourseManager.
14
 *
15
 * This is the course library for Chamilo.
16
 *
17
 * All main course functions should be placed here.
18
 *
19
 * Many functions of this library deal with providing support for
20
 * virtual/linked/combined courses (this was already used in several universities
21
 * but not available in standard Chamilo).
22
 *
23
 * There are probably some places left with the wrong code.
24
 *
25
 * @package chamilo.library
26
 */
27
class CourseManager
28
{
29
    const MAX_COURSE_LENGTH_CODE = 40;
30
    /** This constant is used to show separate user names in the course
31
     * list (userportal), footer, etc */
32
    const USER_SEPARATOR = ' |';
33
    const COURSE_FIELD_TYPE_CHECKBOX = 10;
34
    public $columns = [];
35
    public static $em;
36
    public static $toolList;
37
    public static $courseSettingsManager;
38
    private static $manager;
39
40
    /**
41
     * @param \Doctrine\ORM\EntityManager
42
     */
43
    public static function setEntityManager($em)
44
    {
45
        self::$em = $em;
46
    }
47
48
    /**
49
     * @return \Doctrine\ORM\EntityManager
50
     */
51
    public static function getEntityManager()
52
    {
53
        return self::$em;
54
    }
55
56
    /**
57
     * @param $manager
58
     */
59
    public static function setCourseManager($manager)
60
    {
61
        self::$manager = $manager;
62
    }
63
64
    /**
65
     * @return SettingsManager
66
     */
67
    public static function getCourseSettingsManager()
68
    {
69
        return self::$courseSettingsManager;
70
    }
71
72
    /**
73
     * @param SettingsManager $courseSettingsManager
74
     */
75
    public static function setCourseSettingsManager($courseSettingsManager)
76
    {
77
        self::$courseSettingsManager = $courseSettingsManager;
78
    }
79
80
    /**
81
     * @return Chamilo\CoreBundle\Entity\Manager\CourseManager
82
     */
83
    public static function getManager()
84
    {
85
        return self::$manager;
86
    }
87
88
    /**
89
     * Creates a course.
90
     *
91
     * @param array $params      Columns in the main.course table.
92
     * @param int   $authorId    Optional.
93
     * @param int   $accessUrlId Optional.
94
     *
95
     * @return mixed false if the course was not created, array with the course info
96
     */
97
    public static function create_course($params, $authorId = 0, $accessUrlId = 0)
98
    {
99
        global $_configuration;
100
101
        $hook = HookCreateCourse::create();
102
103
        // Check portal limits
104
        $accessUrlId = empty($accessUrlId)
105
            ? (api_get_multiple_access_url() ? api_get_current_access_url_id() : 1)
106
            : $accessUrlId;
107
108
        $authorId = empty($authorId) ? api_get_user_id() : (int) $authorId;
109
110
        if (isset($_configuration[$accessUrlId]) && is_array($_configuration[$accessUrlId])) {
111
            $return = self::checkCreateCourseAccessUrlParam(
112
                $_configuration,
113
                $accessUrlId,
114
                'hosting_limit_courses',
115
                'PortalCoursesLimitReached'
116
            );
117
            if ($return != false) {
118
                return $return;
119
            }
120
            $return = self::checkCreateCourseAccessUrlParam(
121
                $_configuration,
122
                $accessUrlId,
123
                'hosting_limit_active_courses',
124
                'PortalActiveCoursesLimitReached'
125
            );
126
            if ($return != false) {
127
                return $return;
128
            }
129
        }
130
131
        if (empty($params['title'])) {
132
            return false;
133
        }
134
135
        if (empty($params['wanted_code'])) {
136
            $params['wanted_code'] = $params['title'];
137
            // Check whether the requested course code has already been occupied.
138
            $substring = api_substr($params['title'], 0, self::MAX_COURSE_LENGTH_CODE);
139
            if ($substring === false || empty($substring)) {
140
                return false;
141
            } else {
142
                $params['wanted_code'] = self::generate_course_code($substring);
143
            }
144
        }
145
146
        // Create the course keys
147
        $keys = AddCourse::define_course_keys($params['wanted_code']);
148
        $params['exemplary_content'] = isset($params['exemplary_content']) ? $params['exemplary_content'] : false;
149
150
        if (count($keys)) {
151
            $params['code'] = $keys['currentCourseCode'];
152
            $params['visual_code'] = $keys['currentCourseId'];
153
            $params['directory'] = $keys['currentCourseRepository'];
154
            $courseInfo = api_get_course_info($params['code']);
155
            if (empty($courseInfo)) {
156
                $courseId = AddCourse::register_course($params, $accessUrlId);
157
                $courseInfo = api_get_course_info_by_id($courseId);
158
159
                if ($hook) {
160
                    $hook->setEventData(['course_info' => $courseInfo]);
161
                    $hook->notifyCreateCourse(HOOK_EVENT_TYPE_POST);
162
                }
163
164
                if (!empty($courseInfo)) {
165
                    self::fillCourse($courseInfo, $params, $authorId);
166
167
                    return $courseInfo;
168
                }
169
            }
170
        }
171
172
        return false;
173
    }
174
175
    /**
176
     * Returns all the information of a given course code.
177
     *
178
     * @param string $course_code , the course code
179
     *
180
     * @return array with all the fields of the course table
181
     *
182
     * @deprecated Use api_get_course_info() instead
183
     *
184
     * @author Patrick Cool <[email protected]>, Ghent University
185
     * @assert ('') === false
186
     */
187
    public static function get_course_information($course_code)
188
    {
189
        return Database::fetch_array(
190
            Database::query(
191
                "SELECT *, id as real_id FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
192
                WHERE code = '".Database::escape_string($course_code)."'"
193
            ),
194
            'ASSOC'
195
        );
196
    }
197
198
    /**
199
     * Returns a list of courses. Should work with quickform syntax.
200
     *
201
     * @param int    $from               Offset (from the 7th = '6'). Optional.
202
     * @param int    $howmany            Number of results we want. Optional.
203
     * @param int    $orderby            The column we want to order it by. Optional, defaults to first column.
204
     * @param string $orderdirection     The direction of the order (ASC or DESC). Optional, defaults to ASC.
205
     * @param int    $visibility         the visibility of the course, or all by default
206
     * @param string $startwith          If defined, only return results for which the course *title* begins with this string
207
     * @param string $urlId              The Access URL ID, if using multiple URLs
208
     * @param bool   $alsoSearchCode     An extension option to indicate that we also want to search for course codes (not *only* titles)
209
     * @param array  $conditionsLike
210
     * @param array  $onlyThisCourseList
211
     *
212
     * @return array
213
     */
214
    public static function get_courses_list(
215
        $from = 0,
216
        $howmany = 0,
217
        $orderby = 1,
218
        $orderdirection = 'ASC',
219
        $visibility = -1,
220
        $startwith = '',
221
        $urlId = null,
222
        $alsoSearchCode = false,
223
        $conditionsLike = [],
224
        $onlyThisCourseList = []
225
    ) {
226
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
227
        $sql = "SELECT course.*, course.id as real_id 
228
                FROM $courseTable course ";
229
230
        if (!empty($urlId)) {
231
            $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
232
            $sql .= " INNER JOIN $table url ON (url.c_id = course.id) ";
233
        }
234
235
        $visibility = (int) $visibility;
236
237
        if (!empty($startwith)) {
238
            $sql .= "WHERE (title LIKE '".Database::escape_string($startwith)."%' ";
239
            if ($alsoSearchCode) {
240
                $sql .= "OR code LIKE '".Database::escape_string($startwith)."%' ";
241
            }
242
            $sql .= ') ';
243
            if ($visibility !== -1) {
244
                $sql .= " AND visibility = $visibility ";
245
            }
246
        } else {
247
            $sql .= 'WHERE 1 ';
248
            if ($visibility !== -1) {
249
                $sql .= " AND visibility = $visibility ";
250
            }
251
        }
252
253
        if (!empty($urlId)) {
254
            $urlId = (int) $urlId;
255
            $sql .= " AND access_url_id = $urlId";
256
        }
257
258
        if (!empty($onlyThisCourseList)) {
259
            $onlyThisCourseList = array_map('intval', $onlyThisCourseList);
260
            $onlyThisCourseList = implode("','", $onlyThisCourseList);
261
            $sql .= " AND course.id IN ('$onlyThisCourseList') ";
262
        }
263
264
        $allowedFields = [
265
            'title',
266
            'code',
267
        ];
268
269
        if (count($conditionsLike) > 0) {
270
            $sql .= ' AND ';
271
            $temp_conditions = [];
272
            foreach ($conditionsLike as $field => $value) {
273
                if (!in_array($field, $allowedFields)) {
274
                    continue;
275
                }
276
                $field = Database::escape_string($field);
277
                $value = Database::escape_string($value);
278
                $simple_like = false;
279
                if ($simple_like) {
280
                    $temp_conditions[] = $field." LIKE '$value%'";
281
                } else {
282
                    $temp_conditions[] = $field.' LIKE \'%'.$value.'%\'';
283
                }
284
            }
285
            $condition = ' AND ';
286
            if (!empty($temp_conditions)) {
287
                $sql .= implode(' '.$condition.' ', $temp_conditions);
288
            }
289
        }
290
291
        if (!empty($orderby)) {
292
            $sql .= " ORDER BY ".Database::escape_string($orderby)." ";
293
        } else {
294
            $sql .= ' ORDER BY 1 ';
295
        }
296
297
        if (!in_array($orderdirection, ['ASC', 'DESC'])) {
298
            $sql .= 'ASC';
299
        } else {
300
            $sql .= ($orderdirection == 'ASC' ? 'ASC' : 'DESC');
301
        }
302
303
        if (!empty($howmany) && is_int($howmany) and $howmany > 0) {
304
            $sql .= ' LIMIT '.Database::escape_string($howmany);
305
        } else {
306
            $sql .= ' LIMIT 1000000'; //virtually no limit
307
        }
308
        if (!empty($from)) {
309
            $from = intval($from);
310
            $sql .= ' OFFSET '.intval($from);
311
        } else {
312
            $sql .= ' OFFSET 0';
313
        }
314
315
        $data = [];
316
        $res = Database::query($sql);
317
        if (Database::num_rows($res) > 0) {
318
            while ($row = Database::fetch_array($res, 'ASSOC')) {
319
                $data[] = $row;
320
            }
321
        }
322
323
        return $data;
324
    }
325
326
    /**
327
     * Returns the status of a user in a course, which is COURSEMANAGER or STUDENT.
328
     *
329
     * @param int $userId
330
     * @param int $courseId
331
     *
332
     * @return int|bool the status of the user in that course (or false if the user is not in that course)
333
     */
334
    public static function getUserInCourseStatus($userId, $courseId)
335
    {
336
        $courseId = (int) $courseId;
337
        $userId = (int) $userId;
338
        if (empty($courseId)) {
339
            return false;
340
        }
341
342
        $result = Database::fetch_array(
343
            Database::query(
344
                "SELECT status FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
345
                WHERE
346
                    c_id  = $courseId AND
347
                    user_id = $userId"
348
            )
349
        );
350
351
        return $result['status'];
352
    }
353
354
    /**
355
     * @param int $userId
356
     * @param int $courseId
357
     *
358
     * @return mixed
359
     */
360
    public static function getUserCourseInfo($userId, $courseId)
361
    {
362
        $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
363
                WHERE
364
                    c_id  = ".intval($courseId)." AND
365
                    user_id = ".intval($userId);
366
        $result = Database::fetch_array(Database::query($sql));
367
368
        return $result;
369
    }
370
371
    /**
372
     * @param int  $userId
373
     * @param int  $courseId
374
     * @param bool $isTutor
375
     *
376
     * @return bool
377
     */
378
    public static function updateUserCourseTutor($userId, $courseId, $isTutor)
379
    {
380
        $table = Database::escape_string(TABLE_MAIN_COURSE_USER);
381
382
        $courseId = intval($courseId);
383
        $isTutor = intval($isTutor);
384
385
        $sql = "UPDATE $table SET is_tutor = '".$isTutor."'
386
			    WHERE
387
				    user_id = ".$userId." AND
388
				    c_id = ".$courseId;
389
390
        $result = Database::query($sql);
391
392
        if (Database::affected_rows($result) > 0) {
393
            return true;
394
        } else {
395
            return false;
396
        }
397
    }
398
399
    /**
400
     * @param int $userId
401
     * @param int $courseId
402
     *
403
     * @return mixed
404
     */
405
    public static function get_tutor_in_course_status($userId, $courseId)
406
    {
407
        $userId = intval($userId);
408
        $courseId = intval($courseId);
409
        $result = Database::fetch_array(
410
            Database::query(
411
                "SELECT is_tutor
412
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
413
                WHERE
414
                    c_id = $courseId AND
415
                    user_id = $userId"
416
            )
417
        );
418
419
        return $result['is_tutor'];
420
    }
421
422
    /**
423
     * Unsubscribe one or more users from a course.
424
     *
425
     * @param   mixed   user_id or an array with user ids
426
     * @param   string  course code
427
     * @param   int     session id
428
     *
429
     * @return bool
430
     *
431
     * @assert ('', '') === false
432
     */
433
    public static function unsubscribe_user($user_id, $course_code, $session_id = 0)
434
    {
435
        if (empty($user_id)) {
436
            return false;
437
        }
438
        if (!is_array($user_id)) {
439
            $user_id = [$user_id];
440
        }
441
442
        if (count($user_id) == 0) {
443
            return false;
444
        }
445
446
        if (!empty($session_id)) {
447
            $session_id = (int) $session_id;
448
        } else {
449
            $session_id = api_get_session_id();
450
        }
451
452
        if (empty($course_code)) {
453
            return false;
454
        }
455
456
        $userList = [];
457
        // Cleaning the $user_id variable
458
        if (is_array($user_id)) {
459
            $new_user_id_list = [];
460
            foreach ($user_id as $my_user_id) {
461
                $new_user_id_list[] = (int) $my_user_id;
462
            }
463
            $new_user_id_list = array_filter($new_user_id_list);
464
            $userList = $new_user_id_list;
465
            $user_ids = implode(',', $new_user_id_list);
466
        } else {
467
            $user_ids = (int) $user_id;
468
            $userList[] = $user_id;
469
        }
470
471
        $course_info = api_get_course_info($course_code);
472
        $course_id = $course_info['real_id'];
473
474
        // Unsubscribe user from all groups in the course.
475
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_GROUP_USER)."
476
                WHERE c_id = $course_id AND user_id IN (".$user_ids.")";
477
        Database::query($sql);
478
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_GROUP_TUTOR)."
479
                WHERE c_id = $course_id AND user_id IN (".$user_ids.")";
480
        Database::query($sql);
481
482
        // Erase user student publications (works) in the course - by André Boivin
483
        if (!empty($userList)) {
484
            require_once api_get_path(SYS_CODE_PATH).'work/work.lib.php';
485
            foreach ($userList as $userId) {
486
                // Getting all work from user
487
                $workList = getWorkPerUser($userId);
488
                if (!empty($workList)) {
489
                    foreach ($workList as $work) {
490
                        $work = $work['work'];
491
                        // Getting user results
492
                        if (!empty($work->user_results)) {
493
                            foreach ($work->user_results as $workSent) {
494
                                deleteWorkItem($workSent['id'], $course_info);
495
                            }
496
                        }
497
                    }
498
                }
499
            }
500
        }
501
502
        // Unsubscribe user from all blogs in the course.
503
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_BLOGS_REL_USER)." 
504
                WHERE c_id = $course_id AND user_id IN ($user_ids)";
505
        Database::query($sql);
506
507
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_BLOGS_TASKS_REL_USER)." 
508
                WHERE c_id = $course_id AND user_id IN ($user_ids)";
509
        Database::query($sql);
510
511
        // Deleting users in forum_notification and mailqueue course tables
512
        $sql = "DELETE FROM  ".Database::get_course_table(TABLE_FORUM_NOTIFICATION)."
513
                WHERE c_id = $course_id AND user_id IN ($user_ids)";
514
        Database::query($sql);
515
516
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_FORUM_MAIL_QUEUE)."
517
                WHERE c_id = $course_id AND user_id IN ($user_ids)";
518
        Database::query($sql);
519
520
        // Unsubscribe user from the course.
521
        if (!empty($session_id)) {
522
            foreach ($userList as $uid) {
523
                SessionManager::unSubscribeUserFromCourseSession($uid, $course_id, $session_id);
524
525
                // check if a user is register in the session with other course
526
                $sql = "SELECT user_id FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)."
527
                        WHERE session_id = $session_id AND user_id = $uid";
528
                $rs = Database::query($sql);
529
530
                if (Database::num_rows($rs) == 0) {
531
                    SessionManager::unsubscribe_user_from_session($uid, $session_id);
532
                }
533
            }
534
535
            Event::addEvent(
536
                LOG_UNSUBSCRIBE_USER_FROM_COURSE,
537
                LOG_COURSE_CODE,
538
                $course_code,
539
                api_get_utc_datetime(),
540
                $user_id,
541
                $course_id,
542
                $session_id
543
            );
544
        } else {
545
            $sql = "DELETE FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
546
                    WHERE
547
                        user_id IN ($user_ids) AND
548
                        relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
549
                        c_id = $course_id";
550
            Database::query($sql);
551
552
            // add event to system log
553
            $user_id = api_get_user_id();
554
555
            Event::addEvent(
556
                LOG_UNSUBSCRIBE_USER_FROM_COURSE,
557
                LOG_COURSE_CODE,
558
                $course_code,
559
                api_get_utc_datetime(),
560
                $user_id,
561
                $course_id
562
            );
563
564
            foreach ($userList as $userId) {
565
                $userInfo = api_get_user_info($userId);
566
                Event::addEvent(
567
                    LOG_UNSUBSCRIBE_USER_FROM_COURSE,
568
                    LOG_USER_OBJECT,
569
                    $userInfo,
570
                    api_get_utc_datetime(),
571
                    $user_id,
572
                    $course_id
573
                );
574
            }
575
        }
576
    }
577
578
    /**
579
     * @param string $courseCode
580
     * @param int    $status
581
     *
582
     * @return bool
583
     */
584
    public static function autoSubscribeToCourse($courseCode, $status = STUDENT)
585
    {
586
        $courseInfo = api_get_course_info($courseCode);
587
588
        if (empty($courseInfo)) {
589
            return false;
590
        }
591
592
        if (api_is_anonymous()) {
593
            return false;
594
        }
595
596
        if (in_array(
597
            $courseInfo['visibility'],
598
            [
599
                COURSE_VISIBILITY_CLOSED,
600
                COURSE_VISIBILITY_REGISTERED,
601
                COURSE_VISIBILITY_HIDDEN,
602
            ]
603
        )
604
        ) {
605
            Display::addFlash(
606
                Display::return_message(
607
                    get_lang('SubscribingNotAllowed'),
608
                    'warning'
609
                )
610
            );
611
612
            return false;
613
        }
614
615
        return self::subscribeUser(api_get_user_id(), $courseInfo['code'], $status);
616
    }
617
618
    /**
619
     * Subscribe a user to a course. No checks are performed here to see if
620
     * course subscription is allowed.
621
     *
622
     * @param int    $userId
623
     * @param string $courseCode
624
     * @param int    $status                 (STUDENT, COURSEMANAGER, COURSE_ADMIN, NORMAL_COURSE_MEMBER)
625
     * @param int    $sessionId
626
     * @param int    $userCourseCategoryId
627
     * @param bool   $checkTeacherPermission
628
     *
629
     * @return bool True on success, false on failure
630
     *
631
     * @assert ('', '') === false
632
     */
633
    public static function subscribeUser(
634
        $userId,
635
        $courseCode,
636
        $status = STUDENT,
637
        $sessionId = 0,
638
        $userCourseCategoryId = 0,
639
        $checkTeacherPermission = true
640
    ) {
641
        $userId = (int) $userId;
642
        $status = (int) $status;
643
644
        if (empty($userId) || empty($courseCode)) {
645
            return false;
646
        }
647
648
        $courseInfo = api_get_course_info($courseCode);
649
650
        if (empty($courseInfo)) {
651
            Display::addFlash(Display::return_message(get_lang('CourseDoesNotExist'), 'warning'));
652
653
            return false;
654
        }
655
656
        $userInfo = api_get_user_info($userId);
657
658
        if (empty($userInfo)) {
659
            Display::addFlash(Display::return_message(get_lang('UserDoesNotExist'), 'warning'));
660
661
            return false;
662
        }
663
664
        $courseId = $courseInfo['real_id'];
665
        $courseCode = $courseInfo['code'];
666
        $userCourseCategoryId = (int) $userCourseCategoryId;
667
668
        $sessionId = empty($sessionId) ? api_get_session_id() : (int) $sessionId;
669
        $status = $status === STUDENT || $status === COURSEMANAGER ? $status : STUDENT;
670
        $courseUserTable = Database::get_main_table(TABLE_MAIN_COURSE_USER);
671
672
        if (!empty($sessionId)) {
673
            SessionManager::subscribe_users_to_session_course(
674
                [$userId],
675
                $sessionId,
676
                $courseCode
677
            );
678
679
            // Add event to the system log
680
            Event::addEvent(
681
                LOG_SUBSCRIBE_USER_TO_COURSE,
682
                LOG_COURSE_CODE,
683
                $courseCode,
684
                api_get_utc_datetime(),
685
                api_get_user_id(),
686
                $courseId,
687
                $sessionId
688
            );
689
            Event::addEvent(
690
                LOG_SUBSCRIBE_USER_TO_COURSE,
691
                LOG_USER_OBJECT,
692
                $userInfo,
693
                api_get_utc_datetime(),
694
                api_get_user_id(),
695
                $courseId,
696
                $sessionId
697
            );
698
699
            return true;
700
        } else {
701
            // Check whether the user has not been already subscribed to the course.
702
            $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."                    
703
                    WHERE 
704
                        user_id = $userId AND 
705
                        relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND 
706
                        c_id = $courseId
707
                    ";
708
            if (Database::num_rows(Database::query($sql)) > 0) {
709
                Display::addFlash(Display::return_message(get_lang('AlreadyRegisteredToCourse'), 'warning'));
710
711
                return false;
712
            }
713
714
            if ($checkTeacherPermission && !api_is_course_admin()) {
715
                // Check in advance whether subscription is allowed or not for this course.
716
                if ((int) $courseInfo['subscribe'] === SUBSCRIBE_NOT_ALLOWED) {
717
                    Display::addFlash(Display::return_message(get_lang('SubscriptionNotAllowed'), 'warning'));
718
719
                    return false;
720
                }
721
            }
722
723
            if ($status === STUDENT) {
724
                // Check if max students per course extra field is set
725
                $extraFieldValue = new ExtraFieldValue('course');
726
                $value = $extraFieldValue->get_values_by_handler_and_field_variable($courseId, 'max_subscribed_students');
727
                if (!empty($value) && isset($value['value'])) {
728
                    $maxStudents = $value['value'];
729
                    if ($maxStudents !== '') {
730
                        $maxStudents = (int) $maxStudents;
731
                        $count = self::get_user_list_from_course_code(
732
                            $courseCode,
733
                            0,
734
                            null,
735
                            null,
736
                            STUDENT,
737
                            true,
738
                            false
739
                        );
740
741
                        if ($count >= $maxStudents) {
742
                            Display::addFlash(Display::return_message(get_lang('MaxNumberSubscribedStudentsReached'), 'warning'));
743
744
                            return false;
745
                        }
746
                    }
747
                }
748
            }
749
750
            $maxSort = api_max_sort_value('0', $userId);
751
            $params = [
752
                'c_id' => $courseId,
753
                'user_id' => $userId,
754
                'status' => $status,
755
                'sort' => $maxSort + 1,
756
                'relation_type' => 0,
757
                'user_course_cat' => (int) $userCourseCategoryId,
758
            ];
759
            $insertId = Database::insert($courseUserTable, $params);
760
761
            if ($insertId) {
762
                Display::addFlash(
763
                    Display::return_message(
764
                        sprintf(
765
                            get_lang('UserXAddedToCourseX'),
766
                            $userInfo['complete_name_with_username'],
767
                            $courseInfo['title']
768
                        )
769
                    )
770
                );
771
772
                $send = api_get_course_setting('email_alert_to_teacher_on_new_user_in_course', $courseCode);
773
774
                if ($send == 1) {
775
                    self::email_to_tutor(
776
                        $userId,
777
                        $courseInfo['real_id'],
778
                        false
779
                    );
780
                } elseif ($send == 2) {
781
                    self::email_to_tutor(
782
                        $userId,
783
                        $courseInfo['real_id'],
784
                        true
785
                    );
786
                }
787
788
                // Add event to the system log
789
                Event::addEvent(
790
                    LOG_SUBSCRIBE_USER_TO_COURSE,
791
                    LOG_COURSE_CODE,
792
                    $courseCode,
793
                    api_get_utc_datetime(),
794
                    api_get_user_id(),
795
                    $courseId
796
                );
797
798
                Event::addEvent(
799
                    LOG_SUBSCRIBE_USER_TO_COURSE,
800
                    LOG_USER_OBJECT,
801
                    $userInfo,
802
                    api_get_utc_datetime(),
803
                    api_get_user_id(),
804
                    $courseId
805
                );
806
807
                return true;
808
            }
809
810
            return false;
811
        }
812
    }
813
814
    /**
815
     * Get the course id based on the original id and field name in the
816
     * extra fields. Returns 0 if course was not found.
817
     *
818
     * @param string $original_course_id_value
819
     * @param string $original_course_id_name
820
     *
821
     * @return int Course id
822
     *
823
     * @assert ('', '') === false
824
     */
825
    public static function get_course_code_from_original_id(
826
        $original_course_id_value,
827
        $original_course_id_name
828
    ) {
829
        $t_cfv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
830
        $table_field = Database::get_main_table(TABLE_EXTRA_FIELD);
831
        $extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
832
        $original_course_id_value = Database::escape_string($original_course_id_value);
833
        $original_course_id_name = Database::escape_string($original_course_id_name);
834
835
        $sql = "SELECT item_id
836
                FROM $table_field cf
837
                INNER JOIN $t_cfv cfv
838
                ON cfv.field_id=cf.id
839
                WHERE
840
                    variable = '$original_course_id_name' AND
841
                    value = '$original_course_id_value' AND
842
                    cf.extra_field_type = $extraFieldType
843
                ";
844
        $res = Database::query($sql);
845
        $row = Database::fetch_object($res);
846
        if ($row) {
847
            return $row->item_id;
848
        } else {
849
            return 0;
850
        }
851
    }
852
853
    /**
854
     * Gets the course code from the course id. Returns null if course id was not found.
855
     *
856
     * @param int $id Course id
857
     *
858
     * @return string Course code
859
     * @assert ('') === false
860
     */
861
    public static function get_course_code_from_course_id($id)
862
    {
863
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
864
        $id = intval($id);
865
        $sql = "SELECT code FROM $table WHERE id = $id ";
866
        $res = Database::query($sql);
867
        $row = Database::fetch_object($res);
868
        if ($row) {
869
            return $row->code;
870
        } else {
871
            return null;
872
        }
873
    }
874
875
    /**
876
     * Add the user $userId visibility to the course $courseCode in the catalogue.
877
     *
878
     * @author David Nos (https://github.com/dnos)
879
     *
880
     * @param int    $userId     the id of the user
881
     * @param string $courseCode the course code
882
     * @param int    $visible    (optional) The course visibility in the catalogue to the user (1=visible, 0=invisible)
883
     *
884
     * @return bool true if added succesfully, false otherwise
885
     */
886
    public static function addUserVisibilityToCourseInCatalogue(
887
        $userId,
888
        $courseCode,
889
        $visible = 1
890
    ) {
891
        $debug = false;
892
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
893
        $courseUserTable = Database::get_main_table(TABLE_MAIN_COURSE_CATALOGUE_USER);
894
        $visible = (int) $visible;
895
        if (empty($userId) || empty($courseCode) || ($userId != strval(intval($userId)))) {
896
            return false;
897
        }
898
899
        $courseCode = Database::escape_string($courseCode);
900
        $courseInfo = api_get_course_info($courseCode);
901
        $courseId = $courseInfo['real_id'];
902
903
        // Check in advance whether the user has already been registered on the platform.
904
        $sql = "SELECT status FROM ".$userTable." WHERE user_id = $userId ";
905
        if (Database::num_rows(Database::query($sql)) == 0) {
906
            if ($debug) {
907
                error_log('The user has not been registered to the platform');
908
            }
909
910
            return false; // The user has not been registered to the platform.
911
        }
912
913
        // Check whether the user has already been registered to the course visibility in the catalogue.
914
        $sql = "SELECT * FROM $courseUserTable
915
                WHERE
916
                    user_id = $userId AND
917
                    visible = $visible AND
918
                    c_id = $courseId";
919
        if (Database::num_rows(Database::query($sql)) > 0) {
920
            if ($debug) {
921
                error_log('The user has been already registered to the course visibility in the catalogue');
922
            }
923
924
            return true; // The visibility of the user to the course in the catalogue does already exist.
925
        }
926
927
        // Register the user visibility to course in catalogue.
928
        $params = [
929
            'user_id' => $userId,
930
            'c_id' => $courseId,
931
            'visible' => $visible,
932
        ];
933
        $insertId = Database::insert($courseUserTable, $params);
934
935
        return $insertId;
936
    }
937
938
    /**
939
     * Remove the user $userId visibility to the course $courseCode in the catalogue.
940
     *
941
     * @author David Nos (https://github.com/dnos)
942
     *
943
     * @param int    $userId     the id of the user
944
     * @param string $courseCode the course code
945
     * @param int    $visible    (optional) The course visibility in the catalogue to the user (1=visible, 0=invisible)
946
     *
947
     * @return bool true if removed succesfully or register not found, false otherwise
948
     */
949
    public static function removeUserVisibilityToCourseInCatalogue(
950
        $userId,
951
        $courseCode,
952
        $visible = 1
953
    ) {
954
        $courseUserTable = Database::get_main_table(TABLE_MAIN_COURSE_CATALOGUE_USER);
955
956
        if (empty($userId) || empty($courseCode) || ($userId != strval(intval($userId)))) {
957
            return false;
958
        }
959
960
        $courseCode = Database::escape_string($courseCode);
961
        $courseInfo = api_get_course_info($courseCode);
962
        $courseId = $courseInfo['real_id'];
963
964
        // Check whether the user has already been registered to the course visibility in the catalogue.
965
        $sql = "SELECT * FROM $courseUserTable
966
                WHERE
967
                    user_id = $userId AND
968
                    visible = $visible AND
969
                    c_id = $courseId";
970
        if (Database::num_rows(Database::query($sql)) > 0) {
971
            $cond = [
972
                'user_id = ? AND c_id = ? AND visible = ? ' => [
973
                    $userId,
974
                    $courseId,
975
                    $visible,
976
                ],
977
            ];
978
979
            return Database::delete($courseUserTable, $cond);
980
        } else {
981
            return true; // Register does not exist
982
        }
983
    }
984
985
    /**
986
     * @param string $code
987
     *
988
     * @return bool if there already are one or more courses
989
     *              with the same code OR visual_code (visualcode), false otherwise
990
     */
991
    public static function course_code_exists($code)
992
    {
993
        $code = Database::escape_string($code);
994
        $sql = "SELECT COUNT(*) as number
995
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
996
                WHERE code = '$code' OR visual_code = '$code'";
997
        $result = Database::fetch_array(Database::query($sql));
998
999
        return $result['number'] > 0;
1000
    }
1001
1002
    /**
1003
     * @param int    $user_id
1004
     * @param string $startsWith Optional
1005
     *
1006
     * @return array an array with the course info of all the courses (real and virtual)
1007
     *               of which the current user is course admin
1008
     */
1009
    public static function get_course_list_of_user_as_course_admin($user_id, $startsWith = '')
1010
    {
1011
        if ($user_id != strval(intval($user_id))) {
1012
            return [];
1013
        }
1014
1015
        // Definitions database tables and variables
1016
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
1017
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1018
        $user_id = intval($user_id);
1019
        $data = [];
1020
1021
        $sql = "SELECT
1022
                    course.code,
1023
                    course.title,
1024
                    course.id,
1025
                    course.id as real_id,
1026
                    course.category_code
1027
                FROM $tbl_course_user as course_rel_user
1028
                INNER JOIN $tbl_course as course
1029
                ON course.id = course_rel_user.c_id
1030
                WHERE
1031
                    course_rel_user.user_id = $user_id AND
1032
                    course_rel_user.status = 1
1033
        ";
1034
1035
        if (api_get_multiple_access_url()) {
1036
            $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
1037
            $access_url_id = api_get_current_access_url_id();
1038
            if ($access_url_id != -1) {
1039
                $sql = "
1040
                    SELECT
1041
                        course.code,
1042
                        course.title,
1043
                        course.id,
1044
                        course.id as real_id
1045
                    FROM $tbl_course_user as course_rel_user
1046
                    INNER JOIN $tbl_course as course
1047
                    ON course.id = course_rel_user.c_id
1048
                    INNER JOIN $tbl_course_rel_access_url course_rel_url
1049
                    ON (course_rel_url.c_id = course.id)
1050
                    WHERE
1051
                        access_url_id = $access_url_id  AND
1052
                        course_rel_user.user_id = $user_id AND
1053
                        course_rel_user.status = 1
1054
                ";
1055
            }
1056
        }
1057
1058
        if (!empty($startsWith)) {
1059
            $startsWith = Database::escape_string($startsWith);
1060
1061
            $sql .= " AND (course.title LIKE '$startsWith%' OR course.code LIKE '$startsWith%')";
1062
        }
1063
1064
        $sql .= ' ORDER BY course.title';
1065
1066
        $result_nb_cours = Database::query($sql);
1067
        if (Database::num_rows($result_nb_cours) > 0) {
1068
            while ($row = Database::fetch_array($result_nb_cours, 'ASSOC')) {
1069
                $data[$row['id']] = $row;
1070
            }
1071
        }
1072
1073
        return $data;
1074
    }
1075
1076
    /**
1077
     * @param int   $userId
1078
     * @param array $courseInfo
1079
     *
1080
     * @return bool|null
1081
     */
1082
    public static function isUserSubscribedInCourseAsDrh($userId, $courseInfo)
1083
    {
1084
        $userId = intval($userId);
1085
1086
        if (!api_is_drh()) {
1087
            return false;
1088
        }
1089
1090
        if (empty($courseInfo) || empty($userId)) {
1091
            return false;
1092
        }
1093
1094
        $courseId = intval($courseInfo['real_id']);
1095
        $table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1096
1097
        $sql = "SELECT * FROM $table
1098
                WHERE
1099
                    user_id = $userId AND
1100
                    relation_type = ".COURSE_RELATION_TYPE_RRHH." AND
1101
                    c_id = $courseId";
1102
1103
        $result = Database::fetch_array(Database::query($sql));
1104
1105
        if (!empty($result)) {
1106
            // The user has been registered in this course.
1107
            return true;
1108
        }
1109
    }
1110
1111
    /**
1112
     * Check if user is subscribed inside a course.
1113
     *
1114
     * @param int    $user_id
1115
     * @param string $course_code  , if this parameter is null, it'll check for all courses
1116
     * @param bool   $in_a_session True for checking inside sessions too, by default is not checked
1117
     * @param int    $session_id
1118
     *
1119
     * @return bool $session_id true if the user is registered in the course, false otherwise
1120
     */
1121
    public static function is_user_subscribed_in_course(
1122
        $user_id,
1123
        $course_code = null,
1124
        $in_a_session = false,
1125
        $session_id = 0
1126
    ) {
1127
        $user_id = (int) $user_id;
1128
1129
        if (empty($session_id)) {
1130
            $session_id = api_get_session_id();
1131
        } else {
1132
            $session_id = (int) $session_id;
1133
        }
1134
1135
        $condition_course = '';
1136
        if (isset($course_code)) {
1137
            $courseInfo = api_get_course_info($course_code);
1138
            if (empty($courseInfo)) {
1139
                return false;
1140
            }
1141
            $courseId = $courseInfo['real_id'];
1142
            $condition_course = ' AND c_id = '.$courseId;
1143
        }
1144
1145
        $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
1146
                WHERE
1147
                    user_id = $user_id AND
1148
                    relation_type<>".COURSE_RELATION_TYPE_RRHH."
1149
                    $condition_course ";
1150
1151
        $result = Database::fetch_array(Database::query($sql));
1152
1153
        if (!empty($result)) {
1154
            // The user has been registered in this course.
1155
            return true;
1156
        }
1157
1158
        if (!$in_a_session) {
1159
            // The user has not been registered in this course.
1160
            return false;
1161
        }
1162
1163
        $tableSessionCourseUser = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
1164
        $sql = 'SELECT 1 FROM '.$tableSessionCourseUser.'
1165
            WHERE user_id = '.$user_id.' AND session_id = '.$session_id.' '.$condition_course;
1166
1167
        if (Database::num_rows(Database::query($sql)) > 0) {
1168
            return true;
1169
        }
1170
1171
        $sql = 'SELECT 1 FROM '.$tableSessionCourseUser.'
1172
            WHERE user_id = '.$user_id.' AND session_id = '.$session_id.' AND status = 2 '.$condition_course;
1173
1174
        if (Database::num_rows(Database::query($sql)) > 0) {
1175
            return true;
1176
        }
1177
1178
        $sql = 'SELECT 1 FROM '.Database::get_main_table(TABLE_MAIN_SESSION).
1179
            ' WHERE id = '.$session_id.' AND id_coach='.$user_id;
1180
1181
        if (Database::num_rows(Database::query($sql)) > 0) {
1182
            return true;
1183
        }
1184
1185
        return false;
1186
    }
1187
1188
    /**
1189
     * Is the user a teacher in the given course?
1190
     *
1191
     * @param int    $user_id     , the id (int) of the user
1192
     * @param string $course_code , the course code
1193
     *
1194
     * @return bool if the user is a teacher in the course, false otherwise
1195
     */
1196
    public static function is_course_teacher($user_id, $course_code)
1197
    {
1198
        if ($user_id != strval(intval($user_id))) {
1199
            return false;
1200
        }
1201
1202
        $courseInfo = api_get_course_info($course_code);
1203
        if (empty($courseInfo)) {
1204
            return false;
1205
        }
1206
        $courseId = $courseInfo['real_id'];
1207
        $sql = "SELECT status FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
1208
                WHERE c_id = $courseId AND user_id = $user_id ";
1209
        $result = Database::query($sql);
1210
1211
        if (Database::num_rows($result) > 0) {
1212
            return Database::result($result, 0, 'status') == 1;
1213
        }
1214
1215
        return false;
1216
    }
1217
1218
    /**
1219
     *    Is the user subscribed in the real course or linked courses?
1220
     *
1221
     * @param int the id of the user
1222
     * @param int $courseId
1223
     *
1224
     * @deprecated linked_courses definition doesn't exists
1225
     *
1226
     * @return bool if the user is registered in the real course or linked courses, false otherwise
1227
     */
1228
    public static function is_user_subscribed_in_real_or_linked_course($user_id, $courseId, $session_id = 0)
1229
    {
1230
        if ($user_id != strval(intval($user_id))) {
1231
            return false;
1232
        }
1233
1234
        $courseId = intval($courseId);
1235
        $session_id = intval($session_id);
1236
1237
        if (empty($session_id)) {
1238
            $result = Database::fetch_array(
1239
                Database::query(
1240
                    "SELECT *
1241
                    FROM ".Database::get_main_table(TABLE_MAIN_COURSE)." course
1242
                    LEFT JOIN ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." course_user
1243
                    ON course.id = course_user.c_id
1244
                    WHERE
1245
                        course_user.user_id = $user_id AND
1246
                        course_user.relation_type<>".COURSE_RELATION_TYPE_RRHH." AND
1247
                        ( course.id = $courseId)"
1248
                )
1249
            );
1250
1251
            return !empty($result);
1252
        }
1253
1254
        // From here we trust session id.
1255
        // Is he/she subscribed to the session's course?
1256
        // A user?
1257
        if (Database::num_rows(Database::query("SELECT user_id
1258
                FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)."
1259
                WHERE session_id = $session_id
1260
                AND user_id = $user_id"))
1261
        ) {
1262
            return true;
1263
        }
1264
1265
        // A course coach?
1266
        if (Database::num_rows(Database::query("SELECT user_id
1267
                FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)."
1268
                WHERE session_id = $session_id
1269
                AND user_id = $user_id AND status = 2
1270
                AND c_id = $courseId"))
1271
        ) {
1272
            return true;
1273
        }
1274
1275
        // A session coach?
1276
        if (Database::num_rows(Database::query("SELECT id_coach
1277
                FROM ".Database::get_main_table(TABLE_MAIN_SESSION)." AS session
1278
                WHERE session.id = $session_id
1279
                AND id_coach = $user_id"))
1280
        ) {
1281
            return true;
1282
        }
1283
1284
        return false;
1285
    }
1286
1287
    /**
1288
     * Return user info array of all users registered in a course
1289
     * This only returns the users that are registered in this actual course, not linked courses.
1290
     *
1291
     * @param string    $course_code
1292
     * @param int       $session_id
1293
     * @param string    $limit
1294
     * @param string    $order_by         the field to order the users by.
1295
     *                                    Valid values are 'lastname', 'firstname', 'username', 'email', 'official_code' OR a part of a SQL statement
1296
     *                                    that starts with ORDER BY ...
1297
     * @param int|null  $filter_by_status if using the session_id: 0 or 2 (student, coach),
1298
     *                                    if using session_id = 0 STUDENT or COURSEMANAGER
1299
     * @param bool|null $return_count
1300
     * @param bool      $add_reports
1301
     * @param bool      $resumed_report
1302
     * @param array     $extra_field
1303
     * @param array     $courseCodeList
1304
     * @param array     $userIdList
1305
     * @param string    $filterByActive
1306
     * @param array     $sessionIdList
1307
     * @param string    $searchByKeyword
1308
     *
1309
     * @return array|int
1310
     */
1311
    public static function get_user_list_from_course_code(
1312
        $course_code = null,
1313
        $session_id = 0,
1314
        $limit = null,
1315
        $order_by = null,
1316
        $filter_by_status = null,
1317
        $return_count = null,
1318
        $add_reports = false,
1319
        $resumed_report = false,
1320
        $extra_field = [],
1321
        $courseCodeList = [],
1322
        $userIdList = [],
1323
        $filterByActive = null,
1324
        $sessionIdList = [],
1325
        $searchByKeyword = ''
1326
    ) {
1327
        $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
1328
        $sessionTable = Database::get_main_table(TABLE_MAIN_SESSION);
1329
1330
        $session_id = (int) $session_id;
1331
        $course_code = Database::escape_string($course_code);
1332
        $courseInfo = api_get_course_info($course_code);
1333
        $courseId = 0;
1334
        if (!empty($courseInfo)) {
1335
            $courseId = $courseInfo['real_id'];
1336
        }
1337
1338
        $where = [];
1339
        if (empty($order_by)) {
1340
            $order_by = 'user.lastname, user.firstname';
1341
            if (api_is_western_name_order()) {
1342
                $order_by = 'user.firstname, user.lastname';
1343
            }
1344
        }
1345
1346
        // if the $order_by does not contain 'ORDER BY'
1347
        // we have to check if it is a valid field that can be sorted on
1348
        if (!strstr($order_by, 'ORDER BY')) {
1349
            if (!empty($order_by)) {
1350
                $order_by = 'ORDER BY '.$order_by;
1351
            } else {
1352
                $order_by = '';
1353
            }
1354
        }
1355
1356
        $filter_by_status_condition = null;
1357
1358
        if (!empty($session_id) || !empty($sessionIdList)) {
1359
            $sql = 'SELECT DISTINCT
1360
                        user.user_id,
1361
                        user.email,
1362
                        session_course_user.status as status_session,
1363
                        session_id,
1364
                        user.*,
1365
                        course.*,
1366
                        course.id AS c_id,
1367
                        session.name as session_name
1368
                    ';
1369
            if ($return_count) {
1370
                $sql = " SELECT COUNT(user.user_id) as count";
1371
            }
1372
1373
            $sessionCondition = " session_course_user.session_id = $session_id";
1374
            if (!empty($sessionIdList)) {
1375
                $sessionIdListTostring = implode("','", array_map('intval', $sessionIdList));
1376
                $sessionCondition = " session_course_user.session_id IN ('$sessionIdListTostring') ";
1377
            }
1378
1379
            $courseCondition = " course.id = $courseId";
1380
            if (!empty($courseCodeList)) {
1381
                $courseCodeListForSession = array_map(['Database', 'escape_string'], $courseCodeList);
1382
                $courseCodeListForSession = implode('","', $courseCodeListForSession);
1383
                $courseCondition = ' course.code IN ("'.$courseCodeListForSession.'")  ';
1384
            }
1385
1386
            $sql .= ' FROM '.Database::get_main_table(TABLE_MAIN_USER).' as user ';
1387
            $sql .= " LEFT JOIN ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)." as session_course_user
1388
                      ON
1389
                        user.id = session_course_user.user_id AND
1390
                        $sessionCondition
1391
                        INNER JOIN $course_table course 
1392
                        ON session_course_user.c_id = course.id AND
1393
                        $courseCondition
1394
                        INNER JOIN $sessionTable session 
1395
                        ON session_course_user.session_id = session.id
1396
                   ";
1397
            $where[] = ' session_course_user.c_id IS NOT NULL ';
1398
1399
            // 2 = coach
1400
            // 0 = student
1401
            if (isset($filter_by_status)) {
1402
                $filter_by_status = intval($filter_by_status);
1403
                $filter_by_status_condition = " session_course_user.status = $filter_by_status AND ";
1404
            }
1405
        } else {
1406
            if ($return_count) {
1407
                $sql = " SELECT COUNT(*) as count";
1408
            } else {
1409
                if (empty($course_code)) {
1410
                    $sql = 'SELECT DISTINCT
1411
                                course.title,
1412
                                course.code,
1413
                                course.id AS c_id,
1414
                                course_rel_user.status as status_rel,
1415
                                user.id as user_id,
1416
                                user.email,
1417
                                course_rel_user.is_tutor,
1418
                                user.*  ';
1419
                } else {
1420
                    $sql = 'SELECT DISTINCT
1421
                                course_rel_user.status as status_rel,
1422
                                user.id as user_id,
1423
                                user.email,
1424
                                course_rel_user.is_tutor,
1425
                                user.*  ';
1426
                }
1427
            }
1428
1429
            $sql .= " FROM ".Database::get_main_table(TABLE_MAIN_USER)." as user 
1430
                      LEFT JOIN ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." as course_rel_user
1431
                      ON 
1432
                        user.id = course_rel_user.user_id AND
1433
                        course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH."
1434
                       INNER JOIN $course_table course 
1435
                       ON course_rel_user.c_id = course.id ";
1436
1437
            if (!empty($course_code)) {
1438
                $sql .= ' AND course_rel_user.c_id = "'.$courseId.'"';
1439
            }
1440
            $where[] = ' course_rel_user.c_id IS NOT NULL ';
1441
1442
            if (isset($filter_by_status) && is_numeric($filter_by_status)) {
1443
                $filter_by_status = (int) $filter_by_status;
1444
                $filter_by_status_condition = " course_rel_user.status = $filter_by_status AND ";
1445
            }
1446
        }
1447
1448
        $multiple_access_url = api_get_multiple_access_url();
1449
        if ($multiple_access_url) {
1450
            $sql .= ' LEFT JOIN '.Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER).' au
1451
                      ON (au.user_id = user.id) ';
1452
        }
1453
1454
        $extraFieldWasAdded = false;
1455
        if ($return_count && $resumed_report) {
1456
            foreach ($extra_field as $extraField) {
1457
                $extraFieldInfo = UserManager::get_extra_field_information_by_name($extraField);
1458
                if (!empty($extraFieldInfo)) {
1459
                    $fieldValuesTable = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1460
                    $sql .= ' LEFT JOIN '.$fieldValuesTable.' as ufv
1461
                            ON (
1462
                                user.id = ufv.item_id AND
1463
                                (field_id = '.$extraFieldInfo['id'].' OR field_id IS NULL)
1464
                            )';
1465
                    $extraFieldWasAdded = true;
1466
                }
1467
            }
1468
        }
1469
1470
        $sql .= ' WHERE '.$filter_by_status_condition.' '.implode(' OR ', $where);
1471
1472
        if ($multiple_access_url) {
1473
            $current_access_url_id = api_get_current_access_url_id();
1474
            $sql .= " AND (access_url_id =  $current_access_url_id ) ";
1475
        }
1476
1477
        if ($return_count && $resumed_report && $extraFieldWasAdded) {
1478
            $sql .= ' AND field_id IS NOT NULL GROUP BY value ';
1479
        }
1480
1481
        if (!empty($courseCodeList)) {
1482
            $courseCodeList = array_map(['Database', 'escape_string'], $courseCodeList);
1483
            $courseCodeList = implode('","', $courseCodeList);
1484
            if (empty($sessionIdList)) {
1485
                $sql .= ' AND course.code IN ("'.$courseCodeList.'")';
1486
            }
1487
        }
1488
1489
        if (!empty($userIdList)) {
1490
            $userIdList = array_map('intval', $userIdList);
1491
            $userIdList = implode('","', $userIdList);
1492
            $sql .= ' AND user.id IN ("'.$userIdList.'")';
1493
        }
1494
1495
        if (isset($filterByActive)) {
1496
            $filterByActive = (int) $filterByActive;
1497
            $sql .= ' AND user.active = '.$filterByActive;
1498
        }
1499
1500
        if (!empty($searchByKeyword)) {
1501
            $searchByKeyword = Database::escape_string($searchByKeyword);
1502
            $sql .= " AND (
1503
                        user.firstname LIKE '$searchByKeyword' OR 
1504
                        user.username LIKE '$searchByKeyword' OR 
1505
                        user.lastname LIKE '$searchByKeyword'
1506
                    ) ";
1507
        }
1508
1509
        $sql .= ' '.$order_by.' '.$limit;
1510
1511
        $rs = Database::query($sql);
1512
        $users = [];
1513
1514
        $extra_fields = UserManager::get_extra_fields(
1515
            0,
1516
            100,
1517
            null,
1518
            null,
1519
            true,
1520
            true
1521
        );
1522
1523
        $counter = 1;
1524
        $count_rows = Database::num_rows($rs);
1525
1526
        if ($return_count && $resumed_report) {
1527
            return $count_rows;
1528
        }
1529
1530
        $table_user_field_value = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1531
        $tableExtraField = Database::get_main_table(TABLE_EXTRA_FIELD);
1532
        if ($count_rows) {
1533
            while ($user = Database::fetch_array($rs)) {
1534
                if ($return_count) {
1535
                    return $user['count'];
1536
                }
1537
                $report_info = [];
1538
                $user_info = $user;
1539
                $user_info['status'] = $user['status'];
1540
                if (isset($user['is_tutor'])) {
1541
                    $user_info['is_tutor'] = $user['is_tutor'];
1542
                }
1543
                if (!empty($session_id)) {
1544
                    $user_info['status_session'] = $user['status_session'];
1545
                }
1546
1547
                $sessionId = isset($user['session_id']) ? $user['session_id'] : 0;
1548
                $course_code = isset($user['code']) ? $user['code'] : null;
1549
1550
                if ($add_reports) {
1551
                    if ($resumed_report) {
1552
                        $extra = [];
1553
1554
                        if (!empty($extra_fields)) {
1555
                            foreach ($extra_fields as $extra) {
1556
                                if (in_array($extra['1'], $extra_field)) {
1557
                                    $user_data = UserManager::get_extra_user_data_by_field(
1558
                                        $user['user_id'],
1559
                                        $extra['1']
1560
                                    );
1561
                                    break;
1562
                                }
1563
                            }
1564
                        }
1565
1566
                        $row_key = '-1';
1567
                        $name = '-';
1568
1569
                        if (!empty($extra)) {
1570
                            if (!empty($user_data[$extra['1']])) {
1571
                                $row_key = $user_data[$extra['1']];
1572
                                $name = $user_data[$extra['1']];
1573
                                $users[$row_key]['extra_'.$extra['1']] = $name;
1574
                            }
1575
                        }
1576
1577
                        if (empty($users[$row_key])) {
1578
                            $users[$row_key] = [];
1579
                        }
1580
1581
                        if (!array_key_exists('training_hours', $users[$row_key])) {
1582
                            $users[$row_key]['training_hours'] = 0;
1583
                        }
1584
1585
                        $users[$row_key]['training_hours'] += Tracking::get_time_spent_on_the_course(
1586
                            $user['user_id'],
1587
                            $courseId,
1588
                            $sessionId
1589
                        );
1590
1591
                        if (!array_key_exists('count_users', $users[$row_key])) {
1592
                            $users[$row_key]['count_users'] = 0;
1593
                        }
1594
1595
                        $users[$row_key]['count_users'] += $counter;
1596
1597
                        $registered_users_with_extra_field = self::getCountRegisteredUsersWithCourseExtraField(
1598
                            $name,
1599
                            $tableExtraField,
1600
                            $table_user_field_value
1601
                        );
1602
1603
                        $users[$row_key]['count_users_registered'] = $registered_users_with_extra_field;
1604
                        $users[$row_key]['average_hours_per_user'] = $users[$row_key]['training_hours'] / $users[$row_key]['count_users'];
1605
1606
                        $category = Category:: load(
1607
                            null,
1608
                            null,
1609
                            $course_code,
1610
                            null,
1611
                            null,
1612
                            $sessionId
1613
                        );
1614
1615
                        if (!isset($users[$row_key]['count_certificates'])) {
1616
                            $users[$row_key]['count_certificates'] = 0;
1617
                        }
1618
1619
                        if (isset($category[0]) && $category[0]->is_certificate_available($user['user_id'])) {
1620
                            $users[$row_key]['count_certificates']++;
1621
                        }
1622
1623
                        foreach ($extra_fields as $extra) {
1624
                            if ($extra['1'] == 'ruc') {
1625
                                continue;
1626
                            }
1627
1628
                            if (!isset($users[$row_key][$extra['1']])) {
1629
                                $user_data = UserManager::get_extra_user_data_by_field($user['user_id'], $extra['1']);
1630
                                if (!empty($user_data[$extra['1']])) {
1631
                                    $users[$row_key][$extra['1']] = $user_data[$extra['1']];
1632
                                }
1633
                            }
1634
                        }
1635
                    } else {
1636
                        $sessionName = !empty($sessionId) ? ' - '.$user['session_name'] : '';
1637
                        $report_info['course'] = $user['title'].$sessionName;
1638
                        $report_info['user'] = api_get_person_name($user['firstname'], $user['lastname']);
1639
                        $report_info['email'] = $user['email'];
1640
                        $report_info['time'] = api_time_to_hms(
1641
                            Tracking::get_time_spent_on_the_course(
1642
                                $user['user_id'],
1643
                                empty($user['c_id']) ? $courseId : $user['c_id'],
1644
                                $sessionId
1645
                            )
1646
                        );
1647
1648
                        $category = Category:: load(
1649
                            null,
1650
                            null,
1651
                            $course_code,
1652
                            null,
1653
                            null,
1654
                            $sessionId
1655
                        );
1656
1657
                        $report_info['certificate'] = Display::label(get_lang('No'));
1658
                        if (isset($category[0]) && $category[0]->is_certificate_available($user['user_id'])) {
1659
                            $report_info['certificate'] = Display::label(get_lang('Yes'), 'success');
1660
                        }
1661
1662
                        $progress = intval(
1663
                            Tracking::get_avg_student_progress(
1664
                                $user['user_id'],
1665
                                $course_code,
1666
                                [],
1667
                                $sessionId
1668
                            )
1669
                        );
1670
                        $report_info['progress_100'] = $progress == 100 ? Display::label(get_lang('Yes'), 'success') : Display::label(get_lang('No'));
1671
                        $report_info['progress'] = $progress."%";
1672
1673
                        foreach ($extra_fields as $extra) {
1674
                            $user_data = UserManager::get_extra_user_data_by_field($user['user_id'], $extra['1']);
1675
                            $report_info[$extra['1']] = $user_data[$extra['1']];
1676
                        }
1677
                        $report_info['user_id'] = $user['user_id'];
1678
                        $users[] = $report_info;
1679
                    }
1680
                } else {
1681
                    $users[$user['user_id']] = $user_info;
1682
                }
1683
            }
1684
        }
1685
1686
        return $users;
1687
    }
1688
1689
    /**
1690
     * @param bool  $resumed_report
1691
     * @param array $extra_field
1692
     * @param array $courseCodeList
1693
     * @param array $userIdList
1694
     * @param array $sessionIdList
1695
     *
1696
     * @return array|int
1697
     */
1698
    public static function get_count_user_list_from_course_code(
1699
        $resumed_report = false,
1700
        $extra_field = [],
1701
        $courseCodeList = [],
1702
        $userIdList = [],
1703
        $sessionIdList = []
1704
    ) {
1705
        return self::get_user_list_from_course_code(
1706
            null,
1707
            0,
1708
            null,
1709
            null,
1710
            null,
1711
            true,
1712
            false,
1713
            $resumed_report,
1714
            $extra_field,
1715
            $courseCodeList,
1716
            $userIdList,
1717
            null,
1718
            $sessionIdList
1719
        );
1720
    }
1721
1722
    /**
1723
     * Gets subscribed users in a course or in a course/session.
1724
     *
1725
     * @param string $course_code
1726
     * @param int    $session_id
1727
     *
1728
     * @return int
1729
     */
1730
    public static function get_users_count_in_course(
1731
        $course_code,
1732
        $session_id = 0,
1733
        $status = null
1734
    ) {
1735
        // variable initialisation
1736
        $session_id = intval($session_id);
1737
        $course_code = Database::escape_string($course_code);
1738
        $tblUser = Database::get_main_table(TABLE_MAIN_USER);
1739
        $tblSessionCourseUser = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
1740
        $tblCourseUser = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1741
        $tblUrlUser = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1742
1743
        $courseInfo = api_get_course_info($course_code);
1744
        $courseId = $courseInfo['real_id'];
1745
1746
        $sql = "
1747
            SELECT DISTINCT count(user.id) as count  
1748
            FROM $tblUser as user
1749
        ";
1750
        $where = [];
1751
        if (!empty($session_id)) {
1752
            $sql .= "
1753
                LEFT JOIN $tblSessionCourseUser as session_course_user
1754
                    ON user.user_id = session_course_user.user_id
1755
                    AND session_course_user.c_id = $courseId
1756
                    AND session_course_user.session_id = $session_id
1757
            ";
1758
1759
            $where[] = ' session_course_user.c_id IS NOT NULL ';
1760
        } else {
1761
            $sql .= "
1762
                LEFT JOIN $tblCourseUser as course_rel_user
1763
                    ON user.user_id = course_rel_user.user_id
1764
                    AND course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH."
1765
                    AND course_rel_user.c_id = $courseId
1766
            ";
1767
            $where[] = ' course_rel_user.c_id IS NOT NULL ';
1768
        }
1769
1770
        $multiple_access_url = api_get_multiple_access_url();
1771
        if ($multiple_access_url) {
1772
            $sql .= " LEFT JOIN $tblUrlUser au ON (au.user_id = user.user_id) ";
1773
        }
1774
1775
        $sql .= ' WHERE '.implode(' OR ', $where);
1776
1777
        if ($multiple_access_url) {
1778
            $current_access_url_id = api_get_current_access_url_id();
1779
            $sql .= " AND (access_url_id =  $current_access_url_id ) ";
1780
        }
1781
        $rs = Database::query($sql);
1782
        $count = 0;
1783
        if (Database::num_rows($rs)) {
1784
            $user = Database::fetch_array($rs);
1785
            $count = $user['count'];
1786
        }
1787
1788
        return $count;
1789
    }
1790
1791
    /**
1792
     * Get a list of coaches of a course and a session.
1793
     *
1794
     * @param string $course_code
1795
     * @param int    $session_id
1796
     * @param bool   $addGeneralCoach
1797
     *
1798
     * @return array List of users
1799
     */
1800
    public static function get_coach_list_from_course_code(
1801
        $course_code,
1802
        $session_id,
1803
        $addGeneralCoach = true
1804
    ) {
1805
        if (empty($course_code) || empty($session_id)) {
1806
            return [];
1807
        }
1808
1809
        $course_code = Database::escape_string($course_code);
1810
        $courseInfo = api_get_course_info($course_code);
1811
        $courseId = $courseInfo['real_id'];
1812
        $session_id = intval($session_id);
1813
        $users = [];
1814
1815
        // We get the coach for the given course in a given session.
1816
        $sql = 'SELECT user_id FROM '.Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER).
1817
               ' WHERE session_id = '.$session_id.' AND c_id = '.$courseId.' AND status = 2';
1818
        $rs = Database::query($sql);
1819
        while ($user = Database::fetch_array($rs)) {
1820
            $userInfo = api_get_user_info($user['user_id']);
1821
            if ($userInfo) {
1822
                $users[$user['user_id']] = $userInfo;
1823
            }
1824
        }
1825
1826
        if ($addGeneralCoach) {
1827
            $table = Database::get_main_table(TABLE_MAIN_SESSION);
1828
            // We get the session coach.
1829
            $sql = "SELECT id_coach FROM $table WHERE id = $session_id";
1830
            $rs = Database::query($sql);
1831
            $session_id_coach = Database::result($rs, 0, 'id_coach');
1832
            if (is_int($session_id_coach)) {
1833
                $userInfo = api_get_user_info($session_id_coach);
1834
                if ($userInfo) {
1835
                    $users[$session_id_coach] = $userInfo;
1836
                }
1837
            }
1838
        }
1839
1840
        return $users;
1841
    }
1842
1843
    /**
1844
     *  Return user info array of all users registered in a course
1845
     *  This only returns the users that are registered in this actual course, not linked courses.
1846
     *
1847
     * @param string $course_code
1848
     * @param bool   $with_session
1849
     * @param int    $session_id
1850
     * @param string $date_from
1851
     * @param string $date_to
1852
     * @param bool   $includeInvitedUsers Whether include the invited users
1853
     * @param int    $groupId
1854
     *
1855
     * @return array with user id
1856
     */
1857
    public static function get_student_list_from_course_code(
1858
        $course_code,
1859
        $with_session = false,
1860
        $session_id = 0,
1861
        $date_from = null,
1862
        $date_to = null,
1863
        $includeInvitedUsers = true,
1864
        $groupId = 0
1865
    ) {
1866
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
1867
        $session_id = intval($session_id);
1868
        $course_code = Database::escape_string($course_code);
1869
        $courseInfo = api_get_course_info($course_code);
1870
        $courseId = $courseInfo['real_id'];
1871
        $students = [];
1872
1873
        if ($session_id == 0) {
1874
            if (empty($groupId)) {
1875
                // students directly subscribed to the course
1876
                $sql = "SELECT *
1877
                        FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." cu
1878
                        INNER JOIN $userTable u
1879
                        ON cu.user_id = u.user_id
1880
                        WHERE c_id = '$courseId' AND cu.status = ".STUDENT;
1881
1882
                if (!$includeInvitedUsers) {
1883
                    $sql .= " AND u.status != ".INVITEE;
1884
                }
1885
                $rs = Database::query($sql);
1886
                while ($student = Database::fetch_array($rs)) {
1887
                    $students[$student['user_id']] = $student;
1888
                }
1889
            } else {
1890
                $students = GroupManager::get_users(
1891
                    $groupId,
1892
                    false,
1893
                    null,
1894
                    null,
1895
                    false,
1896
                    $courseInfo['real_id']
1897
                );
1898
                $students = array_flip($students);
1899
            }
1900
        }
1901
1902
        // students subscribed to the course through a session
1903
        if ($with_session) {
1904
            $joinSession = '';
1905
            //Session creation date
1906
            if (!empty($date_from) && !empty($date_to)) {
1907
                $joinSession = "INNER JOIN ".Database::get_main_table(TABLE_MAIN_SESSION)." s";
1908
            }
1909
1910
            $sql_query = "SELECT *
1911
                          FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)." scu
1912
                          $joinSession
1913
                          INNER JOIN $userTable u ON scu.user_id = u.user_id
1914
                          WHERE scu.c_id = $courseId AND scu.status <> 2";
1915
1916
            if (!empty($date_from) && !empty($date_to)) {
1917
                $date_from = Database::escape_string($date_from);
1918
                $date_to = Database::escape_string($date_to);
1919
                $sql_query .= " AND s.access_start_date >= '$date_from' AND s.access_end_date <= '$date_to'";
1920
            }
1921
1922
            if ($session_id != 0) {
1923
                $sql_query .= ' AND scu.session_id = '.$session_id;
1924
            }
1925
1926
            if (!$includeInvitedUsers) {
1927
                $sql_query .= " AND u.status != ".INVITEE;
1928
            }
1929
1930
            $rs = Database::query($sql_query);
1931
            while ($student = Database::fetch_array($rs)) {
1932
                $students[$student['user_id']] = $student;
1933
            }
1934
        }
1935
1936
        return $students;
1937
    }
1938
1939
    /**
1940
     * Return user info array of all teacher-users registered in a course
1941
     * This only returns the users that are registered in this actual course, not linked courses.
1942
     *
1943
     * @param string $course_code
1944
     *
1945
     * @return array with user id
1946
     */
1947
    public static function get_teacher_list_from_course_code($course_code)
1948
    {
1949
        $courseInfo = api_get_course_info($course_code);
1950
        $courseId = $courseInfo['real_id'];
1951
        if (empty($courseId)) {
1952
            return false;
1953
        }
1954
1955
        $sql = "SELECT DISTINCT
1956
                    u.id as user_id,
1957
                    u.lastname,
1958
                    u.firstname,
1959
                    u.email,
1960
                    u.username,
1961
                    u.status
1962
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." cu
1963
                INNER JOIN ".Database::get_main_table(TABLE_MAIN_USER)." u
1964
                ON (cu.user_id = u.id)
1965
                WHERE
1966
                    cu.c_id = $courseId AND
1967
                    cu.status = 1 ";
1968
        $rs = Database::query($sql);
1969
        $teachers = [];
1970
        while ($teacher = Database::fetch_array($rs)) {
1971
            $teachers[$teacher['user_id']] = $teacher;
1972
        }
1973
1974
        return $teachers;
1975
    }
1976
1977
    /**
1978
     * Return user info array of all teacher-users registered in a course
1979
     * This only returns the users that are registered in this actual course, not linked courses.
1980
     *
1981
     * @param int  $courseId
1982
     * @param bool $loadAvatars
1983
     *
1984
     * @return array with user id
1985
     */
1986
    public static function getTeachersFromCourse($courseId, $loadAvatars = true)
1987
    {
1988
        $courseId = (int) $courseId;
1989
1990
        if (empty($courseId)) {
1991
            return false;
1992
        }
1993
1994
        $sql = "SELECT DISTINCT
1995
                    u.id as user_id,
1996
                    u.lastname,
1997
                    u.firstname,
1998
                    u.email,
1999
                    u.username,
2000
                    u.status
2001
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." cu
2002
                INNER JOIN ".Database::get_main_table(TABLE_MAIN_USER)." u
2003
                ON (cu.user_id = u.id)
2004
                WHERE
2005
                    cu.c_id = $courseId AND
2006
                    cu.status = 1 ";
2007
        $rs = Database::query($sql);
2008
        $listTeachers = [];
2009
        $teachers = [];
2010
        $url = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&course_id='.$courseId;
2011
        while ($teacher = Database::fetch_array($rs)) {
2012
            $teachers['id'] = $teacher['user_id'];
2013
            $teachers['lastname'] = $teacher['lastname'];
2014
            $teachers['firstname'] = $teacher['firstname'];
2015
            $teachers['email'] = $teacher['email'];
2016
            $teachers['username'] = $teacher['username'];
2017
            $teachers['status'] = $teacher['status'];
2018
            $teachers['fullname'] = api_get_person_name($teacher['firstname'], $teacher['lastname']);
2019
            $teachers['avatar'] = '';
2020
            if ($loadAvatars) {
2021
                $userPicture = UserManager::getUserPicture($teacher['user_id'], USER_IMAGE_SIZE_SMALL);
2022
                $teachers['avatar'] = $userPicture;
2023
            }
2024
            $teachers['url'] = $url.'&user_id='.$teacher['user_id'];
2025
            $listTeachers[] = $teachers;
2026
        }
2027
2028
        return $listTeachers;
2029
    }
2030
2031
    /**
2032
     * Returns a string list of teachers assigned to the given course.
2033
     *
2034
     * @param string $course_code
2035
     * @param string $separator           between teachers names
2036
     * @param bool   $add_link_to_profile Whether to add a link to the teacher's profile
2037
     * @param bool   $orderList
2038
     *
2039
     * @return string List of teachers teaching the course
2040
     */
2041
    public static function getTeacherListFromCourseCodeToString(
2042
        $course_code,
2043
        $separator = self::USER_SEPARATOR,
2044
        $add_link_to_profile = false,
2045
        $orderList = false
2046
    ) {
2047
        $teacher_list = self::get_teacher_list_from_course_code($course_code);
2048
        $html = '';
2049
        $list = [];
2050
        if (!empty($teacher_list)) {
2051
            foreach ($teacher_list as $teacher) {
2052
                $teacher_name = api_get_person_name(
2053
                    $teacher['firstname'],
2054
                    $teacher['lastname']
2055
                );
2056
                if ($add_link_to_profile) {
2057
                    $url = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$teacher['user_id'];
2058
                    $teacher_name = Display::url(
2059
                        $teacher_name,
2060
                        $url,
2061
                        [
2062
                            'class' => 'ajax',
2063
                            'data-title' => $teacher_name,
2064
                        ]
2065
                    );
2066
                }
2067
                $list[] = $teacher_name;
2068
            }
2069
2070
            if (!empty($list)) {
2071
                if ($orderList === true) {
2072
                    $html .= '<ul class="user-teacher">';
2073
                    foreach ($list as $teacher) {
2074
                        $html .= '<li>';
2075
                        $html .= Display::return_icon('teacher.png', '', null, ICON_SIZE_TINY);
2076
                        $html .= ' '.$teacher;
2077
                        $html .= '</li>';
2078
                    }
2079
                    $html .= '</ul>';
2080
                } else {
2081
                    $html .= array_to_string($list, $separator);
2082
                }
2083
            }
2084
        }
2085
2086
        return $html;
2087
    }
2088
2089
    /**
2090
     * This function returns information about coachs from a course in session.
2091
     *
2092
     * @param int $session_id
2093
     * @param int $courseId
2094
     *
2095
     * @return array containing user_id, lastname, firstname, username
2096
     */
2097
    public static function get_coachs_from_course($session_id = 0, $courseId = 0)
2098
    {
2099
        if (!empty($session_id)) {
2100
            $session_id = intval($session_id);
2101
        } else {
2102
            $session_id = api_get_session_id();
2103
        }
2104
2105
        if (!empty($courseId)) {
2106
            $courseId = intval($courseId);
2107
        } else {
2108
            $courseId = api_get_course_int_id();
2109
        }
2110
2111
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
2112
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2113
2114
        $sql = "SELECT DISTINCT 
2115
                    u.user_id,
2116
                    u.lastname,
2117
                    u.firstname,
2118
                    u.username
2119
                FROM $tbl_user u 
2120
                INNER JOIN $tbl_session_course_user scu
2121
                ON (u.user_id = scu.user_id)
2122
                WHERE
2123
                    scu.session_id = $session_id AND
2124
                    scu.c_id = $courseId AND
2125
                    scu.status = 2";
2126
        $rs = Database::query($sql);
2127
2128
        $coaches = [];
2129
        if (Database::num_rows($rs) > 0) {
2130
            while ($row = Database::fetch_array($rs)) {
2131
                $completeName = api_get_person_name($row['firstname'], $row['lastname']);
2132
                $coaches[] = $row + ['full_name' => $completeName];
2133
            }
2134
        }
2135
2136
        return $coaches;
2137
    }
2138
2139
    /**
2140
     * @param int    $session_id
2141
     * @param int    $courseId
2142
     * @param string $separator
2143
     * @param bool   $add_link_to_profile
2144
     * @param bool   $orderList
2145
     *
2146
     * @return string
2147
     */
2148
    public static function get_coachs_from_course_to_string(
2149
        $session_id = 0,
2150
        $courseId = 0,
2151
        $separator = self::USER_SEPARATOR,
2152
        $add_link_to_profile = false,
2153
        $orderList = false
2154
    ) {
2155
        $coachList = self::get_coachs_from_course($session_id, $courseId);
2156
        $course_coachs = [];
2157
        if (!empty($coachList)) {
2158
            foreach ($coachList as $coach_course) {
2159
                $coach_name = $coach_course['full_name'];
2160
                if ($add_link_to_profile) {
2161
                    $url = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$coach_course['user_id'].'&course_id='.$courseId.'&session_id='.$session_id;
2162
                    $coach_name = Display::url(
2163
                        $coach_name,
2164
                        $url,
2165
                        [
2166
                            'class' => 'ajax',
2167
                            'data-title' => $coach_name,
2168
                        ]
2169
                    );
2170
                }
2171
                $course_coachs[] = $coach_name;
2172
            }
2173
        }
2174
2175
        $html = '';
2176
        if (!empty($course_coachs)) {
2177
            if ($orderList === true) {
2178
                $html .= '<ul class="user-coachs">';
2179
                foreach ($course_coachs as $coachs) {
2180
                    $html .= Display::tag(
2181
                        'li',
2182
                        Display::return_icon(
2183
                            'teacher.png',
2184
                            get_lang('Coach'),
2185
                            null,
2186
                            ICON_SIZE_TINY
2187
                        ).' '.$coachs
2188
                    );
2189
                }
2190
                $html .= '</ul>';
2191
            } else {
2192
                $html = array_to_string($course_coachs, $separator);
2193
            }
2194
        }
2195
2196
        return $html;
2197
    }
2198
2199
    /**
2200
     * Get the list of groups from the course.
2201
     *
2202
     * @param string $course_code
2203
     * @param int    $session_id         Session ID (optional)
2204
     * @param int    $in_get_empty_group get empty groups (optional)
2205
     *
2206
     * @return array List of groups info
2207
     */
2208
    public static function get_group_list_of_course(
2209
        $course_code,
2210
        $session_id = 0,
2211
        $in_get_empty_group = 0
2212
    ) {
2213
        $course_info = api_get_course_info($course_code);
2214
2215
        if (empty($course_info)) {
2216
            return [];
2217
        }
2218
        $course_id = $course_info['real_id'];
2219
2220
        if (empty($course_id)) {
2221
            return [];
2222
        }
2223
2224
        $session_id != 0 ? $session_condition = ' WHERE g.session_id IN(1,'.intval($session_id).')' : $session_condition = ' WHERE g.session_id = 0';
2225
        if ($in_get_empty_group == 0) {
2226
            // get only groups that are not empty
2227
            $sql = "SELECT DISTINCT g.id, g.iid, g.name
2228
                    FROM ".Database::get_course_table(TABLE_GROUP)." AS g
2229
                    INNER JOIN ".Database::get_course_table(TABLE_GROUP_USER)." gu
2230
                    ON (g.id = gu.group_id AND g.c_id = $course_id AND gu.c_id = $course_id)
2231
                    $session_condition
2232
                    ORDER BY g.name";
2233
        } else {
2234
            // get all groups even if they are empty
2235
            $sql = "SELECT g.id, g.name, g.iid 
2236
                    FROM ".Database::get_course_table(TABLE_GROUP)." AS g
2237
                    $session_condition
2238
                    AND c_id = $course_id";
2239
        }
2240
2241
        $result = Database::query($sql);
2242
        $groupList = [];
2243
        while ($groupData = Database::fetch_array($result)) {
2244
            $groupData['userNb'] = GroupManager::number_of_students($groupData['id'], $course_id);
2245
            $groupList[$groupData['iid']] = $groupData;
2246
        }
2247
2248
        return $groupList;
2249
    }
2250
2251
    /**
2252
     * Delete a course
2253
     * This function deletes a whole course-area from the platform. When the
2254
     * given course is a virtual course, the database and directory will not be
2255
     * deleted.
2256
     * When the given course is a real course, also all virtual courses refering
2257
     * to the given course will be deleted.
2258
     * Considering the fact that we remove all traces of the course in the main
2259
     * database, it makes sense to remove all tracking as well (if stats databases exist)
2260
     * so that a new course created with this code would not use the remains of an older
2261
     * course.
2262
     *
2263
     * @param string $code The code of the course to delete
2264
     *
2265
     * @todo When deleting a virtual course: unsubscribe users from that virtual
2266
     * course from the groups in the real course if they are not subscribed in
2267
     * that real course.
2268
     */
2269
    public static function delete_course($code)
2270
    {
2271
        $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2272
        $table_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
2273
        $table_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2274
        $table_course_survey = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY);
2275
        $table_course_survey_question = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION);
2276
        $table_course_survey_question_option = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION_OPTION);
2277
        $table_course_rel_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2278
2279
        $table_stats_hotpots = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTPOTATOES);
2280
        $table_stats_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
2281
        $table_stats_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2282
        $table_stats_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
2283
        $table_stats_lastaccess = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
2284
        $table_stats_course_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
2285
        $table_stats_online = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ONLINE);
2286
        $table_stats_default = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DEFAULT);
2287
        $table_stats_downloads = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
2288
        $table_stats_links = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LINKS);
2289
        $table_stats_uploads = Database::get_main_table(TABLE_STATISTIC_TRACK_E_UPLOADS);
2290
2291
        if (empty($code)) {
2292
            return false;
2293
        }
2294
2295
        $course = api_get_course_info($code);
2296
2297
        if (empty($course)) {
2298
            return false;
2299
        }
2300
2301
        $codeFiltered = $course['code'];
2302
        $courseId = $course['real_id']; // int
2303
        $courseEntity = api_get_course_entity($courseId);
2304
2305
        $count = 0;
2306
        if (api_is_multiple_url_enabled()) {
2307
            $url_id = 1;
2308
            if (api_get_current_access_url_id() != -1) {
2309
                $url_id = api_get_current_access_url_id();
2310
            }
2311
            UrlManager::delete_url_rel_course($courseId, $url_id);
2312
            $count = UrlManager::getCountUrlRelCourse($courseId);
2313
        }
2314
2315
        if ($count === 0) {
2316
            self::create_database_dump($code);
2317
2318
            $course_tables = AddCourse::get_course_tables();
2319
2320
            // Cleaning group categories
2321
            $groupCategories = GroupManager::get_categories($course['code']);
2322
            if (!empty($groupCategories)) {
2323
                foreach ($groupCategories as $category) {
2324
                    GroupManager::delete_category($category['id'], $course['code']);
2325
                }
2326
            }
2327
2328
            // Cleaning groups
2329
            $groups = GroupManager::get_groups($courseId);
2330
            if (!empty($groups)) {
2331
                foreach ($groups as $group) {
2332
                    GroupManager::deleteGroup($group, $course['code']);
2333
                }
2334
            }
2335
2336
            // Cleaning c_x tables
2337
            if (!empty($courseId)) {
2338
                foreach ($course_tables as $table) {
2339
                    $table = Database::get_course_table($table);
2340
                    $sql = "DELETE FROM $table WHERE c_id = $courseId ";
2341
                    Database::query($sql);
2342
                }
2343
            }
2344
2345
            $course_dir = api_get_path(SYS_COURSE_PATH).$course['directory'];
2346
            $archive_dir = api_get_path(SYS_ARCHIVE_PATH).$course['directory'].'_'.time();
2347
            if (is_dir($course_dir)) {
2348
                rename($course_dir, $archive_dir);
2349
            }
2350
2351
            Category::deleteFromCourse($courseEntity);
2352
2353
            // Unsubscribe all users from the course
2354
            $sql = "DELETE FROM $table_course_user WHERE c_id = $courseId";
2355
            Database::query($sql);
2356
            // Delete the course from the sessions tables
2357
            $sql = "DELETE FROM $table_session_course WHERE c_id = $courseId";
2358
            Database::query($sql);
2359
            $sql = "DELETE FROM $table_session_course_user WHERE c_id = $courseId";
2360
            Database::query($sql);
2361
2362
            // Delete from Course - URL
2363
            $sql = "DELETE FROM $table_course_rel_url WHERE c_id = $courseId";
2364
            Database::query($sql);
2365
2366
            $sql = "SELECT survey_id FROM $table_course_survey WHERE course_code = '$codeFiltered'";
2367
            $result_surveys = Database::query($sql);
2368
            while ($surveys = Database::fetch_array($result_surveys)) {
2369
                $survey_id = $surveys[0]; //int
2370
                $sql = "DELETE FROM $table_course_survey_question WHERE survey_id = $survey_id";
2371
                Database::query($sql);
2372
                $sql = "DELETE FROM $table_course_survey_question_option WHERE survey_id = $survey_id";
2373
                Database::query($sql);
2374
                $sql = "DELETE FROM $table_course_survey WHERE survey_id = $survey_id";
2375
                Database::query($sql);
2376
            }
2377
2378
            // Delete the course from the stats tables
2379
            $sql = "DELETE FROM $table_stats_hotpots WHERE c_id = $courseId";
2380
            Database::query($sql);
2381
            $sql = "DELETE FROM $table_stats_attempt WHERE c_id = $courseId";
2382
            Database::query($sql);
2383
            $sql = "DELETE FROM $table_stats_exercises WHERE c_id = $courseId";
2384
            Database::query($sql);
2385
            $sql = "DELETE FROM $table_stats_access WHERE c_id = $courseId";
2386
            Database::query($sql);
2387
            $sql = "DELETE FROM $table_stats_lastaccess WHERE c_id = $courseId";
2388
            Database::query($sql);
2389
            $sql = "DELETE FROM $table_stats_course_access WHERE c_id = $courseId";
2390
            Database::query($sql);
2391
            $sql = "DELETE FROM $table_stats_online WHERE c_id = $courseId";
2392
            Database::query($sql);
2393
            // Do not delete rows from track_e_default as these include course
2394
            // creation and other important things that do not take much space
2395
            // but give information on the course history
2396
            //$sql = "DELETE FROM $table_stats_default WHERE c_id = $courseId";
2397
            //Database::query($sql);
2398
            $sql = "DELETE FROM $table_stats_downloads WHERE c_id = $courseId";
2399
            Database::query($sql);
2400
            $sql = "DELETE FROM $table_stats_links WHERE c_id = $courseId";
2401
            Database::query($sql);
2402
            $sql = "DELETE FROM $table_stats_uploads WHERE c_id = $courseId";
2403
            Database::query($sql);
2404
2405
            // Update ticket
2406
            $table = Database::get_main_table(TABLE_TICKET_TICKET);
2407
            $sql = "UPDATE $table SET course_id = NULL WHERE course_id = $courseId";
2408
            Database::query($sql);
2409
2410
            // Class
2411
            $table = Database::get_main_table(TABLE_USERGROUP_REL_COURSE);
2412
            $sql = "DELETE FROM $table
2413
                    WHERE course_id = $courseId";
2414
            Database::query($sql);
2415
2416
            // Skills
2417
            $table = Database::get_main_table(TABLE_MAIN_SKILL_REL_USER);
2418
            $argumentation = Database::escape_string(sprintf(get_lang('SkillFromCourseXDeletedSinceThen'), $course['code']));
2419
            $sql = "UPDATE $table SET course_id = NULL, session_id = NULL, argumentation = '$argumentation' 
2420
                    WHERE course_id = $courseId";
2421
            Database::query($sql);
2422
2423
            $sql = "DELETE FROM skill_rel_course WHERE c_id = $courseId";
2424
            Database::query($sql);
2425
2426
            // Deletes all groups, group-users, group-tutors information
2427
            // To prevent fK mix up on some tables
2428
            GroupManager::deleteAllGroupsFromCourse($courseId);
2429
2430
            $app_plugin = new AppPlugin();
2431
            $app_plugin->performActionsWhenDeletingItem('course', $courseId);
2432
            // Delete the course from the database
2433
            Database::getManager()->remove($courseEntity);
2434
            Database::getManager()->flush();
2435
2436
            // delete extra course fields
2437
            $extraFieldValues = new ExtraFieldValue('course');
2438
            $extraFieldValues->deleteValuesByItem($courseId);
2439
2440
            // Add event to system log
2441
            Event::addEvent(
2442
                LOG_COURSE_DELETE,
2443
                LOG_COURSE_CODE,
2444
                $code,
2445
                api_get_utc_datetime(),
2446
                api_get_user_id(),
2447
                $courseId
2448
            );
2449
        }
2450
    }
2451
2452
    /**
2453
     * Creates a file called mysql_dump.sql in the course folder.
2454
     *
2455
     * @param string $course_code The code of the course
2456
     *
2457
     * @todo Implementation for single database
2458
     */
2459
    public static function create_database_dump($course_code)
2460
    {
2461
        $sql_dump = '';
2462
        $course_code = Database::escape_string($course_code);
2463
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
2464
        $sql = "SELECT * FROM $table_course WHERE code = '$course_code'";
2465
        $res = Database::query($sql);
2466
        $course = Database::fetch_array($res);
2467
2468
        $course_tables = AddCourse::get_course_tables();
2469
2470
        if (!empty($course['id'])) {
2471
            //Cleaning c_x tables
2472
            foreach ($course_tables as $table) {
2473
                $table = Database::get_course_table($table);
2474
                $sql = "SELECT * FROM $table WHERE c_id = {$course['id']} ";
2475
                $res_table = Database::query($sql);
2476
2477
                while ($row = Database::fetch_array($res_table, 'ASSOC')) {
2478
                    $row_to_save = [];
2479
                    foreach ($row as $key => $value) {
2480
                        $row_to_save[$key] = $key."='".Database::escape_string($row[$key])."'";
2481
                    }
2482
                    $sql_dump .= "\nINSERT INTO $table SET ".implode(', ', $row_to_save).';';
2483
                }
2484
            }
2485
        }
2486
2487
        if (is_dir(api_get_path(SYS_COURSE_PATH).$course['directory'])) {
2488
            $file_name = api_get_path(SYS_COURSE_PATH).$course['directory'].'/mysql_dump.sql';
2489
            $handle = fopen($file_name, 'a+');
2490
            if ($handle !== false) {
2491
                fwrite($handle, $sql_dump);
2492
                fclose($handle);
2493
            } else {
2494
                //TODO trigger exception in a try-catch
2495
            }
2496
        }
2497
    }
2498
2499
    /**
2500
     * Sort courses for a specific user ??
2501
     *
2502
     * @param int    $user_id     User ID
2503
     * @param string $course_code Course code
2504
     *
2505
     * @return int Minimum course order
2506
     *
2507
     * @todo Review documentation
2508
     */
2509
    public static function userCourseSort($user_id, $course_code)
2510
    {
2511
        if ($user_id != strval(intval($user_id))) {
2512
            return false;
2513
        }
2514
2515
        $course_code = Database::escape_string($course_code);
2516
        $TABLECOURSE = Database::get_main_table(TABLE_MAIN_COURSE);
2517
        $TABLECOURSUSER = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2518
2519
        $course_title = Database::result(
2520
            Database::query(
2521
                "SELECT title FROM $TABLECOURSE WHERE code = '$course_code'"
2522
            ),
2523
            0,
2524
            0
2525
        );
2526
        if ($course_title === false) {
2527
            $course_title = '';
2528
        }
2529
2530
        $sql = "SELECT course.code as code, course.title as title, cu.sort as sort
2531
                FROM $TABLECOURSUSER as cu, $TABLECOURSE as course
2532
                WHERE   course.id = cu.c_id AND user_id = $user_id AND
2533
                        cu.relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
2534
                        user_course_cat = 0
2535
                ORDER BY cu.sort";
2536
        $result = Database::query($sql);
2537
2538
        $course_title_precedent = '';
2539
        $counter = 0;
2540
        $course_found = false;
2541
        $course_sort = 1;
2542
2543
        if (Database::num_rows($result) > 0) {
2544
            while ($courses = Database::fetch_array($result)) {
2545
                if ($course_title_precedent == '') {
2546
                    $course_title_precedent = $courses['title'];
2547
                }
2548
                if (api_strcasecmp($course_title_precedent, $course_title) < 0) {
2549
                    $course_found = true;
2550
                    $course_sort = $courses['sort'];
2551
                    if ($counter == 0) {
2552
                        $sql = "UPDATE $TABLECOURSUSER
2553
                                SET sort = sort+1
2554
                                WHERE
2555
                                    user_id= $user_id AND
2556
                                    relation_type <> ".COURSE_RELATION_TYPE_RRHH."
2557
                                    AND user_course_cat = 0
2558
                                    AND sort > $course_sort";
2559
                        $course_sort++;
2560
                    } else {
2561
                        $sql = "UPDATE $TABLECOURSUSER SET sort = sort+1
2562
                                WHERE
2563
                                    user_id= $user_id AND
2564
                                    relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
2565
                                    user_course_cat = 0 AND
2566
                                    sort >= $course_sort";
2567
                    }
2568
                    Database::query($sql);
2569
                    break;
2570
                } else {
2571
                    $course_title_precedent = $courses['title'];
2572
                }
2573
                $counter++;
2574
            }
2575
2576
            // We must register the course in the beginning of the list
2577
            if (!$course_found) {
2578
                $course_sort = Database::result(
2579
                    Database::query(
2580
                        'SELECT min(sort) as min_sort FROM '.$TABLECOURSUSER.' WHERE user_id = "'.$user_id.'" AND user_course_cat="0"'
2581
                    ),
2582
                    0,
2583
                    0
2584
                );
2585
                Database::query("UPDATE $TABLECOURSUSER SET sort = sort+1 WHERE user_id = $user_id AND user_course_cat = 0");
2586
            }
2587
        }
2588
2589
        return $course_sort;
2590
    }
2591
2592
    /**
2593
     * check if course exists.
2594
     *
2595
     * @param string $courseCode
2596
     *
2597
     * @return int if exists, false else
2598
     */
2599
    public static function course_exists($courseCode)
2600
    {
2601
        $courseCode = Database::escape_string($courseCode);
2602
        $sql = "SELECT 1 FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
2603
                WHERE code = '$courseCode'";
2604
2605
        return Database::num_rows(Database::query($sql));
2606
    }
2607
2608
    /**
2609
     * Send an email to tutor after the auth-suscription of a student in your course.
2610
     *
2611
     * @author Carlos Vargas <[email protected]>, Dokeos Latino
2612
     *
2613
     * @param int    $user_id            the id of the user
2614
     * @param string $courseId           the course code
2615
     * @param bool   $send_to_tutor_also
2616
     *
2617
     * @return false|null we return the message that is displayed when the action is successful
2618
     */
2619
    public static function email_to_tutor($user_id, $courseId, $send_to_tutor_also = false)
2620
    {
2621
        $user_id = (int) $user_id;
2622
        $courseId = (int) $courseId;
2623
        $information = api_get_course_info_by_id($courseId);
2624
        $course_code = $information['code'];
2625
        $student = api_get_user_info($user_id);
2626
2627
        $name_course = $information['title'];
2628
        $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." 
2629
                WHERE c_id = $courseId";
2630
2631
        // TODO: Ivan: This is a mistake, please, have a look at it. Intention here is diffcult to be guessed.
2632
        //if ($send_to_tutor_also = true)
2633
        // Proposed change:
2634
        if ($send_to_tutor_also) {
2635
            $sql .= ' AND is_tutor = 1';
2636
        } else {
2637
            $sql .= ' AND status = 1';
2638
        }
2639
2640
        $result = Database::query($sql);
2641
        while ($row = Database::fetch_array($result)) {
2642
            $tutor = api_get_user_info($row['user_id']);
2643
            $emailto = $tutor['email'];
2644
            $emailsubject = get_lang('NewUserInTheCourse').': '.$name_course;
2645
            $emailbody = get_lang('Dear').': '.api_get_person_name($tutor['firstname'], $tutor['lastname'])."\n";
2646
            $emailbody .= get_lang('MessageNewUserInTheCourse').': '.$name_course."\n";
2647
            $emailbody .= get_lang('UserName').': '.$student['username']."\n";
2648
            if (api_is_western_name_order()) {
2649
                $emailbody .= get_lang('FirstName').': '.$student['firstname']."\n";
2650
                $emailbody .= get_lang('LastName').': '.$student['lastname']."\n";
2651
            } else {
2652
                $emailbody .= get_lang('LastName').': '.$student['lastname']."\n";
2653
                $emailbody .= get_lang('FirstName').': '.$student['firstname']."\n";
2654
            }
2655
            $emailbody .= get_lang('Email').': <a href="mailto:'.$student['email'].'">'.$student['email']."</a>\n\n";
2656
            $recipient_name = api_get_person_name(
2657
                $tutor['firstname'],
2658
                $tutor['lastname'],
2659
                null,
2660
                PERSON_NAME_EMAIL_ADDRESS
2661
            );
2662
            $sender_name = api_get_person_name(
2663
                api_get_setting('administratorName'),
2664
                api_get_setting('administratorSurname'),
2665
                null,
2666
                PERSON_NAME_EMAIL_ADDRESS
2667
            );
2668
            $email_admin = api_get_setting('emailAdministrator');
2669
2670
            $additionalParameters = [
2671
                'smsType' => SmsPlugin::NEW_USER_SUBSCRIBED_COURSE,
2672
                'userId' => $tutor['user_id'],
2673
                'userUsername' => $student['username'],
2674
                'courseCode' => $course_code,
2675
            ];
2676
            api_mail_html(
2677
                $recipient_name,
2678
                $emailto,
2679
                $emailsubject,
2680
                $emailbody,
2681
                $sender_name,
2682
                $email_admin,
2683
                null,
2684
                null,
2685
                null,
2686
                $additionalParameters
2687
            );
2688
        }
2689
    }
2690
2691
    /**
2692
     * @return array
2693
     */
2694
    public static function get_special_course_list()
2695
    {
2696
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
2697
        $tbl_course_field = Database::get_main_table(TABLE_EXTRA_FIELD);
2698
        $tbl_course_field_value = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
2699
2700
        //we filter the courses from the URL
2701
        $join_access_url = $where_access_url = '';
2702
        if (api_get_multiple_access_url()) {
2703
            $access_url_id = api_get_current_access_url_id();
2704
            if ($access_url_id != -1) {
2705
                $tbl_url_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2706
                $join_access_url = "LEFT JOIN $tbl_url_course url_rel_course
2707
                                    ON url_rel_course.c_id = tcfv.item_id ";
2708
                $where_access_url = " AND access_url_id = $access_url_id ";
2709
            }
2710
        }
2711
2712
        $extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
2713
2714
        // get course list auto-register
2715
        $sql = "SELECT DISTINCT(c.id)
2716
                FROM $tbl_course_field_value tcfv
2717
                INNER JOIN $tbl_course_field tcf
2718
                ON tcfv.field_id =  tcf.id $join_access_url
2719
                INNER JOIN $courseTable c
2720
                ON (c.id = tcfv.item_id)
2721
                WHERE
2722
                    tcf.extra_field_type = $extraFieldType AND
2723
                    tcf.variable = 'special_course' AND
2724
                    tcfv.value = 1 $where_access_url";
2725
2726
        $result = Database::query($sql);
2727
        $courseList = [];
2728
2729
        if (Database::num_rows($result) > 0) {
2730
            while ($row = Database::fetch_array($result)) {
2731
                $courseList[] = $row['id'];
2732
            }
2733
        }
2734
2735
        return $courseList;
2736
    }
2737
2738
    /**
2739
     * Get the course codes that have been restricted in the catalogue, and if byUserId is set
2740
     * then the courses that the user is allowed or not to see in catalogue.
2741
     *
2742
     * @param bool $allowed  Either if the courses have some users that are or are not allowed to see in catalogue
2743
     * @param int  $byUserId if the courses are or are not allowed to see to the user
2744
     *
2745
     * @return array Course codes allowed or not to see in catalogue by some user or the user
2746
     */
2747
    public static function getCatalogueCourseList($allowed = true, $byUserId = -1)
2748
    {
2749
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
2750
        $tblCourseRelUserCatalogue = Database::get_main_table(TABLE_MAIN_COURSE_CATALOGUE_USER);
2751
        $visibility = $allowed ? 1 : 0;
2752
2753
        // Restriction by user id
2754
        $currentUserRestriction = '';
2755
        if ($byUserId > 0) {
2756
            $byUserId = (int) $byUserId;
2757
            $currentUserRestriction = " AND tcruc.user_id = $byUserId ";
2758
        }
2759
2760
        //we filter the courses from the URL
2761
        $joinAccessUrl = '';
2762
        $whereAccessUrl = '';
2763
        if (api_get_multiple_access_url()) {
2764
            $accessUrlId = api_get_current_access_url_id();
2765
            if ($accessUrlId != -1) {
2766
                $tblUrlCourse = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2767
                $joinAccessUrl = "LEFT JOIN $tblUrlCourse url_rel_course
2768
                                  ON url_rel_course.c_id = c.id ";
2769
                $whereAccessUrl = " AND access_url_id = $accessUrlId ";
2770
            }
2771
        }
2772
2773
        // get course list auto-register
2774
        $sql = "SELECT DISTINCT(c.code)
2775
                FROM $tblCourseRelUserCatalogue tcruc
2776
                INNER JOIN $courseTable c
2777
                ON (c.id = tcruc.c_id) $joinAccessUrl
2778
                WHERE tcruc.visible = $visibility $currentUserRestriction $whereAccessUrl";
2779
2780
        $result = Database::query($sql);
2781
        $courseList = [];
2782
2783
        if (Database::num_rows($result) > 0) {
2784
            while ($resultRow = Database::fetch_array($result)) {
2785
                $courseList[] = $resultRow['code'];
2786
            }
2787
        }
2788
2789
        return $courseList;
2790
    }
2791
2792
    /**
2793
     * Get list of courses for a given user.
2794
     *
2795
     * @param int   $user_id
2796
     * @param bool  $include_sessions                   Whether to include courses from session or not
2797
     * @param bool  $adminGetsAllCourses                If the user is platform admin,
2798
     *                                                  whether he gets all the courses or just his. Note: This does *not* include all sessions
2799
     * @param bool  $loadSpecialCourses
2800
     * @param array $skipCourseList                     List of course ids to skip
2801
     * @param bool  $useUserLanguageFilterIfAvailable
2802
     * @param bool  $showCoursesSessionWithDifferentKey
2803
     *
2804
     * @return array List of codes and db name
2805
     *
2806
     * @author isaac flores paz
2807
     */
2808
    public static function get_courses_list_by_user_id(
2809
        $user_id,
2810
        $include_sessions = false,
2811
        $adminGetsAllCourses = false,
2812
        $loadSpecialCourses = true,
2813
        $skipCourseList = [],
2814
        $useUserLanguageFilterIfAvailable = true,
2815
        $showCoursesSessionWithDifferentKey = false
2816
    ) {
2817
        $user_id = intval($user_id);
2818
        $urlId = api_get_current_access_url_id();
2819
        $course_list = [];
2820
        $codes = [];
2821
2822
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
2823
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2824
        $tbl_user_course_category = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
2825
        $tableCourseUrl = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2826
2827
        $languageCondition = '';
2828
        $onlyInUserLanguage = api_get_configuration_value('my_courses_show_courses_in_user_language_only');
2829
        if ($useUserLanguageFilterIfAvailable && $onlyInUserLanguage) {
2830
            $userInfo = api_get_user_info(api_get_user_id());
2831
            if (!empty($userInfo['language'])) {
2832
                $languageCondition = " AND course.course_language = '".$userInfo['language']."' ";
2833
            }
2834
        }
2835
2836
        if ($adminGetsAllCourses && UserManager::is_admin($user_id)) {
2837
            // get the whole courses list
2838
            $sql = "SELECT DISTINCT(course.code), course.id as real_id, course.title
2839
                    FROM $tbl_course course 
2840
                    INNER JOIN $tableCourseUrl url 
2841
                    ON (course.id = url.c_id)
2842
                    WHERE 
2843
                        url.access_url_id = $urlId     
2844
                        $languageCondition 
2845
                ";
2846
        } else {
2847
            $withSpecialCourses = $withoutSpecialCourses = '';
2848
2849
            if ($loadSpecialCourses) {
2850
                $specialCourseList = self::get_special_course_list();
2851
2852
                if (!empty($specialCourseList)) {
2853
                    $specialCourseToString = '"'.implode('","', $specialCourseList).'"';
2854
                    $withSpecialCourses = ' AND course.id IN ('.$specialCourseToString.')';
2855
                    $withoutSpecialCourses = ' AND course.id NOT IN ('.$specialCourseToString.')';
2856
                }
2857
2858
                if (!empty($withSpecialCourses)) {
2859
                    $sql = "SELECT DISTINCT (course.code), 
2860
                            course.id as real_id,
2861
                            course.category_code AS category,
2862
                            course.title
2863
                            FROM $tbl_course_user course_rel_user
2864
                            LEFT JOIN $tbl_course course
2865
                            ON course.id = course_rel_user.c_id
2866
                            LEFT JOIN $tbl_user_course_category user_course_category
2867
                            ON course_rel_user.user_course_cat = user_course_category.id
2868
                            INNER JOIN $tableCourseUrl url 
2869
                            ON (course.id = url.c_id)  
2870
                            WHERE url.access_url_id = $urlId 
2871
                            $withSpecialCourses
2872
                            $languageCondition                        
2873
                            GROUP BY course.code
2874
                            ORDER BY user_course_category.sort, course.title, course_rel_user.sort ASC
2875
                    ";
2876
                    $result = Database::query($sql);
2877
                    if (Database::num_rows($result) > 0) {
2878
                        while ($result_row = Database::fetch_array($result, 'ASSOC')) {
2879
                            $result_row['special_course'] = 1;
2880
                            $course_list[] = $result_row;
2881
                            $codes[] = $result_row['real_id'];
2882
                        }
2883
                    }
2884
                }
2885
            }
2886
2887
            // get course list not auto-register. Use Distinct to avoid multiple
2888
            // entries when a course is assigned to a HRD (DRH) as watcher
2889
            $sql = "SELECT 
2890
                        DISTINCT(course.code), 
2891
                        course.id as real_id, 
2892
                        course.category_code AS category,
2893
                        course.title
2894
                    FROM $tbl_course course
2895
                    INNER JOIN $tbl_course_user cru 
2896
                    ON (course.id = cru.c_id)
2897
                    INNER JOIN $tableCourseUrl url 
2898
                    ON (course.id = url.c_id) 
2899
                    WHERE 
2900
                        url.access_url_id = $urlId AND 
2901
                        cru.user_id = '$user_id' 
2902
                        $withoutSpecialCourses
2903
                        $languageCondition
2904
                    ORDER BY course.title
2905
                    ";
2906
        }
2907
        $result = Database::query($sql);
2908
2909
        if (Database::num_rows($result)) {
2910
            while ($row = Database::fetch_array($result, 'ASSOC')) {
2911
                if (!empty($skipCourseList)) {
2912
                    if (in_array($row['real_id'], $skipCourseList)) {
2913
                        continue;
2914
                    }
2915
                }
2916
                $course_list[] = $row;
2917
                $codes[] = $row['real_id'];
2918
            }
2919
        }
2920
2921
        if ($include_sessions === true) {
2922
            $sql = "SELECT DISTINCT (c.code), 
2923
                        c.id as real_id, 
2924
                        c.category_code AS category,
2925
                        s.id as session_id,
2926
                        s.name as session_name
2927
                    FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)." scu                     
2928
                    INNER JOIN $tbl_course c
2929
                    ON (scu.c_id = c.id)
2930
                    INNER JOIN ".Database::get_main_table(TABLE_MAIN_SESSION)." s
2931
                    ON (s.id = scu.session_id)
2932
                    WHERE user_id = $user_id ";
2933
            $r = Database::query($sql);
2934
            while ($row = Database::fetch_array($r, 'ASSOC')) {
2935
                if (!empty($skipCourseList)) {
2936
                    if (in_array($row['real_id'], $skipCourseList)) {
2937
                        continue;
2938
                    }
2939
                }
2940
2941
                if ($showCoursesSessionWithDifferentKey) {
2942
                    $course_list[] = $row;
2943
                } else {
2944
                    if (!in_array($row['real_id'], $codes)) {
2945
                        $course_list[] = $row;
2946
                    }
2947
                }
2948
            }
2949
        }
2950
2951
        return $course_list;
2952
    }
2953
2954
    /**
2955
     * Get course ID from a given course directory name.
2956
     *
2957
     * @param string $path Course directory (without any slash)
2958
     *
2959
     * @return string Course code, or false if not found
2960
     */
2961
    public static function getCourseCodeFromDirectory($path)
2962
    {
2963
        $path = Database::escape_string(str_replace('.', '', str_replace('/', '', $path)));
2964
        $res = Database::query("SELECT code FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
2965
                WHERE directory LIKE BINARY '$path'");
2966
        if ($res === false) {
2967
            return false;
2968
        }
2969
        if (Database::num_rows($res) != 1) {
2970
            return false;
2971
        }
2972
        $row = Database::fetch_array($res);
2973
2974
        return $row['code'];
2975
    }
2976
2977
    /**
2978
     * Get course code(s) from visual code.
2979
     *
2980
     * @deprecated
2981
     *
2982
     * @param   string  Visual code
2983
     *
2984
     * @return array List of codes for the given visual code
2985
     */
2986
    public static function get_courses_info_from_visual_code($code)
2987
    {
2988
        $result = [];
2989
        $sql_result = Database::query("SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
2990
                WHERE visual_code = '".Database::escape_string($code)."'");
2991
        while ($virtual_course = Database::fetch_array($sql_result)) {
2992
            $result[] = $virtual_course;
2993
        }
2994
2995
        return $result;
2996
    }
2997
2998
    /**
2999
     * Get emails of tutors to course.
3000
     *
3001
     * @param int $courseId
3002
     *
3003
     * @return array List of emails of tutors to course
3004
     *
3005
     * @author Carlos Vargas <[email protected]>, Dokeos Latino
3006
     * */
3007
    public static function get_emails_of_tutors_to_course($courseId)
3008
    {
3009
        $list = [];
3010
        $courseId = intval($courseId);
3011
        $res = Database::query(
3012
            "SELECT user_id 
3013
            FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
3014
            WHERE c_id = $courseId AND status = 1"
3015
        );
3016
        while ($list_users = Database::fetch_array($res)) {
3017
            $result = Database::query(
3018
                "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
3019
                WHERE user_id = ".$list_users['user_id']
3020
            );
3021
            while ($row_user = Database::fetch_array($result)) {
3022
                $name_teacher = api_get_person_name($row_user['firstname'], $row_user['lastname']);
3023
                $list[] = [$row_user['email'] => $name_teacher];
3024
            }
3025
        }
3026
3027
        return $list;
3028
    }
3029
3030
    /**
3031
     * Get coaches emails by session.
3032
     *
3033
     * @param int $session_id
3034
     * @param int $courseId
3035
     *
3036
     * @return array array(email => name_tutor)  by coach
3037
     *
3038
     * @author Carlos Vargas <[email protected]>
3039
     */
3040
    public static function get_email_of_tutor_to_session($session_id, $courseId)
3041
    {
3042
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3043
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
3044
        $coachs_emails = [];
3045
3046
        $courseId = intval($courseId);
3047
        $session_id = intval($session_id);
3048
3049
        $sql = "SELECT user_id
3050
                FROM $tbl_session_course_user
3051
                WHERE
3052
                    session_id = $session_id AND
3053
                    c_id = $courseId AND
3054
                    status = 2
3055
                ";
3056
        $rs = Database::query($sql);
3057
3058
        if (Database::num_rows($rs) > 0) {
3059
            $user_ids = [];
3060
            while ($row = Database::fetch_array($rs)) {
3061
                $user_ids[] = $row['user_id'];
3062
            }
3063
3064
            $sql = "SELECT firstname, lastname, email FROM $tbl_user
3065
                    WHERE user_id IN (".implode(",", $user_ids).")";
3066
            $rs_user = Database::query($sql);
3067
3068
            while ($row_emails = Database::fetch_array($rs_user)) {
3069
                $mail_tutor = [
3070
                    'email' => $row_emails['email'],
3071
                    'complete_name' => api_get_person_name($row_emails['firstname'], $row_emails['lastname']),
3072
                ];
3073
                $coachs_emails[] = $mail_tutor;
3074
            }
3075
        }
3076
3077
        return $coachs_emails;
3078
    }
3079
3080
    /**
3081
     * Creates a new extra field for a given course.
3082
     *
3083
     * @param string $variable    Field's internal variable name
3084
     * @param int    $fieldType   Field's type
3085
     * @param string $displayText Field's language var name
3086
     * @param string $default     Optional. The default value
3087
     *
3088
     * @return int New extra field ID
3089
     */
3090
    public static function create_course_extra_field($variable, $fieldType, $displayText, $default = '')
3091
    {
3092
        $extraField = new ExtraField('course');
3093
        $params = [
3094
            'variable' => $variable,
3095
            'field_type' => $fieldType,
3096
            'display_text' => $displayText,
3097
            'default_value' => $default,
3098
        ];
3099
3100
        return $extraField->save($params);
3101
    }
3102
3103
    /**
3104
     * Updates course attribute. Note that you need to check that your
3105
     * attribute is valid before you use this function.
3106
     *
3107
     * @param int    $id    Course id
3108
     * @param string $name  Attribute name
3109
     * @param string $value Attribute value
3110
     *
3111
     * @return Doctrine\DBAL\Driver\Statement|null True if attribute was successfully updated,
3112
     *                                             false if course was not found or attribute name is invalid
3113
     */
3114
    public static function update_attribute($id, $name, $value)
3115
    {
3116
        $id = (int) $id;
3117
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
3118
        $sql = "UPDATE $table SET $name = '".Database::escape_string($value)."'
3119
                WHERE id = $id";
3120
3121
        return Database::query($sql);
3122
    }
3123
3124
    /**
3125
     * Update course attributes. Will only update attributes with a non-empty value.
3126
     * Note that you NEED to check that your attributes are valid before using this function.
3127
     *
3128
     * @param int Course id
3129
     * @param array Associative array with field names as keys and field values as values
3130
     *
3131
     * @return Doctrine\DBAL\Driver\Statement|null True if update was successful, false otherwise
3132
     */
3133
    public static function update_attributes($id, $attributes)
3134
    {
3135
        $id = (int) $id;
3136
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
3137
        $sql = "UPDATE $table SET ";
3138
        $i = 0;
3139
        foreach ($attributes as $name => $value) {
3140
            if ($value != '') {
3141
                if ($i > 0) {
3142
                    $sql .= ", ";
3143
                }
3144
                $sql .= " $name = '".Database::escape_string($value)."'";
3145
                $i++;
3146
            }
3147
        }
3148
        $sql .= " WHERE id = $id";
3149
3150
        return Database::query($sql);
3151
    }
3152
3153
    /**
3154
     * Update an extra field value for a given course.
3155
     *
3156
     * @param string $course_code Course code
3157
     * @param string $variable    Field variable name
3158
     * @param string $value       Optional. Default field value
3159
     *
3160
     * @return bool|int An integer when register a new extra field. And boolean when update the extrafield
3161
     */
3162
    public static function update_course_extra_field_value($course_code, $variable, $value = '')
3163
    {
3164
        $courseInfo = api_get_course_info($course_code);
3165
        $courseId = $courseInfo['real_id'];
3166
3167
        $extraFieldValues = new ExtraFieldValue('course');
3168
        $params = [
3169
            'item_id' => $courseId,
3170
            'variable' => $variable,
3171
            'value' => $value,
3172
        ];
3173
3174
        return $extraFieldValues->save($params);
3175
    }
3176
3177
    /**
3178
     * @param int $sessionId
3179
     *
3180
     * @return mixed
3181
     */
3182
    public static function get_session_category_id_by_session_id($sessionId)
3183
    {
3184
        if (empty($sessionId)) {
3185
            return [];
3186
        }
3187
        $sessionId = intval($sessionId);
3188
        $sql = 'SELECT sc.id session_category
3189
                FROM '.Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY).' sc
3190
                INNER JOIN '.Database::get_main_table(TABLE_MAIN_SESSION).' s
3191
                ON sc.id = s.session_category_id 
3192
                WHERE s.id = '.$sessionId;
3193
3194
        return Database::result(
3195
            Database::query($sql),
3196
            0,
3197
            'session_category'
3198
        );
3199
    }
3200
3201
    /**
3202
     * Gets the value of a course extra field. Returns null if it was not found.
3203
     *
3204
     * @param string $variable Name of the extra field
3205
     * @param string $code     Course code
3206
     *
3207
     * @return string Value
3208
     */
3209
    public static function get_course_extra_field_value($variable, $code)
3210
    {
3211
        $courseInfo = api_get_course_info($code);
3212
        $courseId = $courseInfo['real_id'];
3213
3214
        $extraFieldValues = new ExtraFieldValue('course');
3215
        $result = $extraFieldValues->get_values_by_handler_and_field_variable($courseId, $variable);
3216
        if (!empty($result['value'])) {
3217
            return $result['value'];
3218
        }
3219
3220
        return null;
3221
    }
3222
3223
    /**
3224
     * Lists details of the course description.
3225
     *
3226
     * @param array        The course description
3227
     * @param string    The encoding
3228
     * @param bool        If true is displayed if false is hidden
3229
     *
3230
     * @return string The course description in html
3231
     */
3232
    public static function get_details_course_description_html(
3233
        $descriptions,
3234
        $fieldValues
3235
    ) {
3236
        $data = null;
3237
        $info = null;
3238
        $data['extrafield'] = $fieldValues;
3239
        if (isset($descriptions) && count($descriptions) > 0) {
3240
            foreach ($descriptions as $description) {
3241
                if ($description->description_type === '1') {
3242
                    $data['description'] = [
3243
                        'title' => Security::remove_XSS($description->title),
3244
                        'content' => Security::remove_XSS($description->content),
3245
                    ];
3246
                }
3247
            }
3248
        }
3249
        $template = new Template(null);
3250
        $essence = new Essence\Essence();
3251
        $template->assign('essence', $essence);
3252
        $template->assign('data', $data);
3253
        $layout = $template->get_template('auth/modal_description.html.twig');
3254
        $info = $template->fetch($layout);
3255
3256
        return $info;
3257
    }
3258
3259
    /**
3260
     * Returns the details of a course category.
3261
     *
3262
     * @param string $code Category code
3263
     *
3264
     * @return array Course category
3265
     */
3266
    public static function get_course_category($code)
3267
    {
3268
        $table = Database::get_main_table(TABLE_MAIN_CATEGORY);
3269
        $code = Database::escape_string($code);
3270
        $sql = "SELECT * FROM $table WHERE code = '$code'";
3271
3272
        return Database::fetch_array(Database::query($sql));
3273
    }
3274
3275
    /**
3276
     * Subscribes courses to human resource manager (Dashboard feature).
3277
     *
3278
     * @param int   $hr_manager_id Human Resource Manager id
3279
     * @param array $courses_list  Courses code
3280
     *
3281
     * @return int
3282
     */
3283
    public static function subscribeCoursesToDrhManager($hr_manager_id, $courses_list)
3284
    {
3285
        $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3286
        $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3287
3288
        $hr_manager_id = intval($hr_manager_id);
3289
        $affected_rows = 0;
3290
3291
        //Deleting assigned courses to hrm_id
3292
        if (api_is_multiple_url_enabled()) {
3293
            $sql = "SELECT s.c_id FROM $tbl_course_rel_user s
3294
                    INNER JOIN $tbl_course_rel_access_url a
3295
                    ON (a.c_id = s.c_id)
3296
                    WHERE
3297
                        user_id = $hr_manager_id AND
3298
                        relation_type = ".COURSE_RELATION_TYPE_RRHH." AND
3299
                        access_url_id = ".api_get_current_access_url_id();
3300
        } else {
3301
            $sql = "SELECT c_id FROM $tbl_course_rel_user
3302
                    WHERE user_id = $hr_manager_id AND relation_type = ".COURSE_RELATION_TYPE_RRHH;
3303
        }
3304
        $result = Database::query($sql);
3305
        if (Database::num_rows($result) > 0) {
3306
            while ($row = Database::fetch_array($result)) {
3307
                $sql = "DELETE FROM $tbl_course_rel_user
3308
                        WHERE
3309
                            c_id = {$row['c_id']} AND
3310
                            user_id = $hr_manager_id AND
3311
                            relation_type = ".COURSE_RELATION_TYPE_RRHH;
3312
                Database::query($sql);
3313
            }
3314
        }
3315
3316
        // inserting new courses list
3317
        if (is_array($courses_list)) {
3318
            foreach ($courses_list as $course_code) {
3319
                $courseInfo = api_get_course_info($course_code);
3320
                $courseId = $courseInfo['real_id'];
3321
                $sql = "INSERT IGNORE INTO $tbl_course_rel_user(c_id, user_id, status, relation_type)
3322
                        VALUES($courseId, $hr_manager_id, ".DRH.", ".COURSE_RELATION_TYPE_RRHH.")";
3323
                $result = Database::query($sql);
3324
                if (Database::affected_rows($result)) {
3325
                    $affected_rows++;
3326
                }
3327
            }
3328
        }
3329
3330
        return $affected_rows;
3331
    }
3332
3333
    /**
3334
     * get courses followed by human resources manager.
3335
     *
3336
     * @param int    $user_id
3337
     * @param int    $status
3338
     * @param int    $from
3339
     * @param int    $limit
3340
     * @param string $column
3341
     * @param string $direction
3342
     * @param bool   $getCount
3343
     *
3344
     * @return array courses
3345
     */
3346
    public static function get_courses_followed_by_drh(
3347
        $user_id,
3348
        $status = DRH,
3349
        $from = null,
3350
        $limit = null,
3351
        $column = null,
3352
        $direction = null,
3353
        $getCount = false
3354
    ) {
3355
        return self::getCoursesFollowedByUser(
3356
            $user_id,
3357
            $status,
3358
            $from,
3359
            $limit,
3360
            $column,
3361
            $direction,
3362
            $getCount
3363
        );
3364
    }
3365
3366
    /**
3367
     * get courses followed by user.
3368
     *
3369
     * @param int    $user_id
3370
     * @param int    $status
3371
     * @param int    $from
3372
     * @param int    $limit
3373
     * @param string $column
3374
     * @param string $direction
3375
     * @param bool   $getCount
3376
     * @param string $keyword
3377
     * @param int    $sessionId
3378
     * @param bool   $showAllAssignedCourses
3379
     *
3380
     * @return array courses
3381
     */
3382
    public static function getCoursesFollowedByUser(
3383
        $user_id,
3384
        $status = null,
3385
        $from = null,
3386
        $limit = null,
3387
        $column = null,
3388
        $direction = null,
3389
        $getCount = false,
3390
        $keyword = null,
3391
        $sessionId = 0,
3392
        $showAllAssignedCourses = false
3393
    ) {
3394
        // Database Table Definitions
3395
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
3396
        $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3397
        $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3398
        $sessionId = (int) $sessionId;
3399
        $user_id = (int) $user_id;
3400
        $select = "SELECT DISTINCT c.*, c.id as real_id ";
3401
3402
        if ($getCount) {
3403
            $select = "SELECT COUNT(DISTINCT c.id) as count";
3404
        }
3405
3406
        $whereConditions = '';
3407
        switch ($status) {
3408
            case COURSEMANAGER:
3409
                $whereConditions .= " AND cru.user_id = $user_id";
3410
                if (!$showAllAssignedCourses) {
3411
                    $whereConditions .= " AND cru.status = ".COURSEMANAGER;
3412
                } else {
3413
                    $whereConditions .= " AND relation_type = ".COURSE_RELATION_TYPE_COURSE_MANAGER;
3414
                }
3415
                break;
3416
            case DRH:
3417
                $whereConditions .= " AND
3418
                    cru.user_id = $user_id AND
3419
                    cru.status = ".DRH." AND
3420
                    relation_type = '".COURSE_RELATION_TYPE_RRHH."'
3421
                ";
3422
                break;
3423
        }
3424
3425
        $keywordCondition = null;
3426
        if (!empty($keyword)) {
3427
            $keyword = Database::escape_string($keyword);
3428
            $keywordCondition = " AND (c.code LIKE '%$keyword%' OR c.title LIKE '%$keyword%' ) ";
3429
        }
3430
3431
        $orderBy = null;
3432
        $extraInnerJoin = null;
3433
3434
        if (!empty($sessionId)) {
3435
            if ($status == COURSEMANAGER) {
3436
                // Teacher of course or teacher inside session
3437
                $whereConditions = " AND (cru.status = ".COURSEMANAGER." OR srcru.status = 2) ";
3438
            }
3439
            $courseList = SessionManager::get_course_list_by_session_id($sessionId);
3440
            if (!empty($courseList)) {
3441
                $courseListToString = implode("','", array_keys($courseList));
3442
                $whereConditions .= " AND c.id IN ('".$courseListToString."')";
3443
            }
3444
            $tableSessionRelCourse = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3445
            $tableSessionRelCourseRelUser = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3446
            $orderBy = ' ORDER BY position';
3447
            $extraInnerJoin = " INNER JOIN $tableSessionRelCourse src
3448
                                ON (c.id = src.c_id AND src.session_id = $sessionId)
3449
                                INNER JOIN $tableSessionRelCourseRelUser srcru 
3450
                                ON (src.session_id = srcru.session_id AND srcru.c_id = src.c_id)
3451
                            ";
3452
        }
3453
3454
        $whereConditions .= $keywordCondition;
3455
        $sql = "$select
3456
                FROM $tbl_course c
3457
                INNER JOIN $tbl_course_rel_user cru 
3458
                ON (cru.c_id = c.id)
3459
                INNER JOIN $tbl_course_rel_access_url a 
3460
                ON (a.c_id = c.id)
3461
                $extraInnerJoin
3462
                WHERE
3463
                    access_url_id = ".api_get_current_access_url_id()."
3464
                    $whereConditions
3465
                $orderBy
3466
                ";
3467
        if (isset($from) && isset($limit)) {
3468
            $from = intval($from);
3469
            $limit = intval($limit);
3470
            $sql .= " LIMIT $from, $limit";
3471
        }
3472
3473
        $result = Database::query($sql);
3474
3475
        if ($getCount) {
3476
            $row = Database::fetch_array($result);
3477
3478
            return $row['count'];
3479
        }
3480
3481
        $courses = [];
3482
        if (Database::num_rows($result) > 0) {
3483
            while ($row = Database::fetch_array($result)) {
3484
                $courses[$row['code']] = $row;
3485
            }
3486
        }
3487
3488
        return $courses;
3489
    }
3490
3491
    /**
3492
     * check if a course is special (autoregister).
3493
     *
3494
     * @param int $courseId
3495
     *
3496
     * @return bool
3497
     */
3498
    public static function isSpecialCourse($courseId)
3499
    {
3500
        $extraFieldValue = new ExtraFieldValue('course');
3501
        $result = $extraFieldValue->get_values_by_handler_and_field_variable(
3502
            $courseId,
3503
            'special_course'
3504
        );
3505
3506
        if (!empty($result)) {
3507
            if ($result['value'] == 1) {
3508
                return true;
3509
            }
3510
        }
3511
3512
        return false;
3513
    }
3514
3515
    /**
3516
     * Update course picture.
3517
     *
3518
     * @param array $courseInfo
3519
     * @param   string  File name
3520
     * @param   string  the full system name of the image
3521
     * from which course picture will be created
3522
     * @param string $cropParameters Optional string that contents "x,y,width,height" of a cropped image format
3523
     *
3524
     * @return bool Returns the resulting. In case of internal error or negative validation returns FALSE.
3525
     */
3526
    public static function update_course_picture(
3527
        $courseInfo,
3528
        $filename,
3529
        $source_file = null,
3530
        $cropParameters = null
3531
    ) {
3532
        if (empty($courseInfo)) {
3533
            return false;
3534
        }
3535
3536
        // course path
3537
        $store_path = api_get_path(SYS_COURSE_PATH).$courseInfo['path'];
3538
        // image name for courses
3539
        $course_image = $store_path.'/course-pic.png';
3540
        $course_medium_image = $store_path.'/course-pic85x85.png';
3541
3542
        if (file_exists($course_image)) {
3543
            unlink($course_image);
3544
        }
3545
        if (file_exists($course_medium_image)) {
3546
            unlink($course_medium_image);
3547
        }
3548
3549
        //Crop the image to adjust 4:3 ratio
3550
        $image = new Image($source_file);
3551
        $image->crop($cropParameters);
3552
3553
        //Resize the images in two formats
3554
        $medium = new Image($source_file);
3555
        $medium->resize(85);
3556
        $medium->send_image($course_medium_image, -1, 'png');
3557
        $normal = new Image($source_file);
3558
        $normal->resize(400);
3559
        $normal->send_image($course_image, -1, 'png');
3560
3561
        $result = $medium && $normal;
3562
3563
        return $result ? $result : false;
3564
    }
3565
3566
    /**
3567
     * Deletes the course picture.
3568
     *
3569
     * @param string $courseCode
3570
     */
3571
    public static function deleteCoursePicture($courseCode)
3572
    {
3573
        $course_info = api_get_course_info($courseCode);
3574
        // course path
3575
        $storePath = api_get_path(SYS_COURSE_PATH).$course_info['path'];
3576
        // image name for courses
3577
        $courseImage = $storePath.'/course-pic.png';
3578
        $courseMediumImage = $storePath.'/course-pic85x85.png';
3579
        $courseSmallImage = $storePath.'/course-pic32.png';
3580
3581
        if (file_exists($courseImage)) {
3582
            unlink($courseImage);
3583
        }
3584
        if (file_exists($courseMediumImage)) {
3585
            unlink($courseMediumImage);
3586
        }
3587
        if (file_exists($courseSmallImage)) {
3588
            unlink($courseSmallImage);
3589
        }
3590
    }
3591
3592
    /**
3593
     * Builds the course block in user_portal.php.
3594
     *
3595
     * @todo use Twig
3596
     *
3597
     * @param array $params
3598
     *
3599
     * @return string
3600
     */
3601
    public static function course_item_html_no_icon($params)
3602
    {
3603
        $html = '<div class="course_item">';
3604
        $html .= '<div class="row">';
3605
        $html .= '<div class="col-md-7">';
3606
3607
        $notifications = isset($params['notifications']) ? $params['notifications'] : null;
3608
3609
        $html .= '<h3>'.$params['title'].$notifications.'</h3> ';
3610
3611
        if (isset($params['description'])) {
3612
            $html .= '<p>'.$params['description'].'</p>';
3613
        }
3614
        if (!empty($params['subtitle'])) {
3615
            $html .= '<small>'.$params['subtitle'].'</small>';
3616
        }
3617
        if (!empty($params['teachers'])) {
3618
            $html .= '<h5 class="teacher">'.
3619
                Display::return_icon(
3620
                    'teacher.png',
3621
                    get_lang('Teacher'),
3622
                    [],
3623
                    ICON_SIZE_TINY
3624
                ).
3625
                $params['teachers'].'</h5>';
3626
        }
3627
        if (!empty($params['coaches'])) {
3628
            $html .= '<h5 class="teacher">'.
3629
                Display::return_icon(
3630
                    'teacher.png',
3631
                    get_lang('Coach'),
3632
                    [],
3633
                    ICON_SIZE_TINY
3634
                ).
3635
                $params['coaches'].'</h5>';
3636
        }
3637
3638
        $html .= '</div>';
3639
        $params['right_actions'] = isset($params['right_actions']) ? $params['right_actions'] : null;
3640
        $html .= '<div class="float-right course-box-actions">'.$params['right_actions'].'</div>';
3641
        $html .= '</div>';
3642
        $html .= '</div>';
3643
3644
        return $html;
3645
    }
3646
3647
    /**
3648
     * @param $params
3649
     * @param bool|false $is_sub_content
3650
     *
3651
     * @return string
3652
     */
3653
    public static function session_items_html($params, $is_sub_content = false)
3654
    {
3655
        $html = '';
3656
        $html .= '<div class="row">';
3657
        $html .= '<div class="col-md-2">';
3658
        if (!empty($params['link'])) {
3659
            $html .= '<a class="thumbnail" href="'.$params['link'].'">';
3660
            $html .= $params['icon'];
3661
            $html .= '</a>';
3662
        } else {
3663
            $html .= $params['icon'];
3664
        }
3665
        $html .= '</div>';
3666
        $html .= '<div class="col-md-10">';
3667
        $html .= $params['title'];
3668
        $html .= $params['coaches'];
3669
        $html .= '</div>';
3670
        $html .= '</div>';
3671
3672
        return $html;
3673
    }
3674
3675
    /**
3676
     * Display special courses (and only these) as several HTML divs of class userportal-course-item.
3677
     *
3678
     * Special courses are courses that stick on top of the list and are "auto-registerable"
3679
     * in the sense that any user clicking them is registered as a student
3680
     *
3681
     * @param int  $user_id                          User id
3682
     * @param bool $load_dirs                        Whether to show the document quick-loader or not
3683
     * @param bool $useUserLanguageFilterIfAvailable
3684
     *
3685
     * @return array
3686
     */
3687
    public static function returnSpecialCourses(
3688
        $user_id,
3689
        $load_dirs = false,
3690
        $useUserLanguageFilterIfAvailable = true
3691
    ) {
3692
        $user_id = intval($user_id);
3693
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
3694
        $specialCourseList = self::get_special_course_list();
3695
3696
        if (empty($specialCourseList)) {
3697
            return [];
3698
        }
3699
3700
        // Filter by language
3701
        $languageCondition = '';
3702
        $onlyInUserLanguage = api_get_configuration_value('my_courses_show_courses_in_user_language_only');
3703
        if ($useUserLanguageFilterIfAvailable && $onlyInUserLanguage) {
3704
            $userInfo = api_get_user_info(api_get_user_id());
3705
            if (!empty($userInfo['language'])) {
3706
                $languageCondition = " AND course_language = '".$userInfo['language']."' ";
3707
            }
3708
        }
3709
3710
        $sql = "SELECT
3711
                    id,
3712
                    code,
3713
                    subscribe subscr,
3714
                    unsubscribe unsubscr
3715
                FROM $table                      
3716
                WHERE 
3717
                    id IN ('".implode("','", $specialCourseList)."')
3718
                    $languageCondition
3719
                GROUP BY code";
3720
3721
        $rs_special_course = Database::query($sql);
3722
        $number_of_courses = Database::num_rows($rs_special_course);
3723
        $showCustomIcon = api_get_setting('course_images_in_courses_list');
3724
3725
        $courseList = [];
3726
        if ($number_of_courses > 0) {
3727
            while ($course = Database::fetch_array($rs_special_course)) {
3728
                $course_info = api_get_course_info($course['code']);
3729
                $courseId = $course_info['real_id'];
3730
                if ($course_info['visibility'] == COURSE_VISIBILITY_HIDDEN) {
3731
                    continue;
3732
                }
3733
3734
                $params = [];
3735
                //Param (course_code) needed to get the student info in page "My courses"
3736
                $params['course_code'] = $course['code'];
3737
                $params['code'] = $course['code'];
3738
                // Get notifications.
3739
                $course_info['id_session'] = null;
3740
                $courseUserInfo = self::getUserCourseInfo($user_id, $courseId);
3741
3742
                if (empty($courseUserInfo)) {
3743
                    $course_info['status'] = STUDENT;
3744
                } else {
3745
                    $course_info['status'] = $courseUserInfo['status'];
3746
                }
3747
                $show_notification = !api_get_configuration_value('hide_course_notification')
3748
                    ? Display::show_notification($course_info)
3749
                    : '';
3750
                $params['edit_actions'] = '';
3751
                $params['document'] = '';
3752
                if (api_is_platform_admin()) {
3753
                    $params['edit_actions'] .= api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cidReq='.$course['code'];
3754
                    if ($load_dirs) {
3755
                        $params['document'] = '<a id="document_preview_'.$courseId.'_0" class="document_preview btn btn-outline-secondary btn-sm" href="javascript:void(0);">'
3756
                           .Display::returnFontAwesomeIcon('folder-open').'</a>';
3757
                        $params['document'] .= Display::div('', ['id' => 'document_result_'.$courseId.'_0', 'class' => 'document_preview_container']);
3758
                    }
3759
                } else {
3760
                    if ($course_info['visibility'] != COURSE_VISIBILITY_CLOSED && $load_dirs) {
3761
                        $params['document'] = '<a id="document_preview_'.$courseId.'_0" class="document_preview btn btn-outline-secondary btn-sm" href="javascript:void(0);">'
3762
                           .Display::returnFontAwesomeIcon('folder-open').'</a>';
3763
                        $params['document'] .= Display::div('', ['id' => 'document_result_'.$courseId.'_0', 'class' => 'document_preview_container']);
3764
                    }
3765
                }
3766
3767
                $params['visibility'] = $course_info['visibility'];
3768
                $params['status'] = $course_info['status'];
3769
                $params['category'] = $course_info['categoryName'];
3770
                $params['category_code'] = $course_info['categoryCode'];
3771
                $params['icon'] = Display::return_icon(
3772
                    'drawing-pin.png',
3773
                    null,
3774
                    null,
3775
                    ICON_SIZE_LARGE,
3776
                    null
3777
                );
3778
3779
                if (api_get_setting('display_coursecode_in_courselist') == 'true') {
3780
                    $params['code_course'] = '('.$course_info['visual_code'].')';
3781
                }
3782
3783
                $params['title'] = $course_info['title'];
3784
                $params['title_cut'] = $course_info['title'];
3785
                $params['link'] = $course_info['course_public_url'].'?id_session=0&autoreg=1';
3786
                if (api_get_setting('display_teacher_in_courselist') === 'true') {
3787
                    $params['teachers'] = self::getTeachersFromCourse(
3788
                        $courseId,
3789
                        true
3790
                    );
3791
                }
3792
3793
                if ($showCustomIcon === 'true') {
3794
                    $params['thumbnails'] = $course_info['course_image'];
3795
                    $params['image'] = $course_info['course_image_large'];
3796
                }
3797
3798
                if ($course_info['visibility'] != COURSE_VISIBILITY_CLOSED) {
3799
                    $params['notifications'] = $show_notification;
3800
                }
3801
3802
                $params['is_special_course'] = true;
3803
                $courseList[] = $params;
3804
            }
3805
        }
3806
3807
        return $courseList;
3808
    }
3809
3810
    /**
3811
     * Display courses (without special courses) as several HTML divs
3812
     * of course categories, as class userportal-catalog-item.
3813
     *
3814
     * @uses \displayCoursesInCategory() to display the courses themselves
3815
     *
3816
     * @param int  $user_id
3817
     * @param bool $load_dirs                        Whether to show the document quick-loader or not
3818
     * @param bool $useUserLanguageFilterIfAvailable
3819
     *
3820
     * @return array
3821
     */
3822
    public static function returnCourses(
3823
        $user_id,
3824
        $load_dirs = false,
3825
        $useUserLanguageFilterIfAvailable = true
3826
    ) {
3827
        $user_id = (int) $user_id;
3828
        if (empty($user_id)) {
3829
            $user_id = api_get_user_id();
3830
        }
3831
        // Step 1: We get all the categories of the user
3832
        $table = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
3833
        $sql = "SELECT * FROM $table
3834
                WHERE user_id = '".$user_id."'
3835
                ORDER BY sort ASC";
3836
3837
        $result = Database::query($sql);
3838
        $listItems = [
3839
            'in_category' => [],
3840
            'not_category' => [],
3841
        ];
3842
        $collapsable = api_get_configuration_value('allow_user_course_category_collapsable');
3843
        $stok = Security::get_token();
3844
        while ($row = Database::fetch_array($result)) {
3845
            // We simply display the title of the category.
3846
            $courseInCategory = self::returnCoursesCategories(
3847
                $row['id'],
3848
                $load_dirs,
3849
                $user_id,
3850
                $useUserLanguageFilterIfAvailable
3851
            );
3852
3853
            $collapsed = 0;
3854
            $collapsableLink = '';
3855
            if ($collapsable) {
3856
                $url = api_get_path(WEB_CODE_PATH).
3857
                    'auth/courses.php?categoryid='.$row['id'].'&sec_token='.$stok.'&redirect=home';
3858
                $collapsed = isset($row['collapsed']) && $row['collapsed'] ? 1 : 0;
3859
                if ($collapsed === 0) {
3860
                    $collapsableLink = Display::url(
3861
                        '<i class="fa fa-folder-open"></i>',
3862
                        $url.'&action=set_collapsable&option=1'
3863
                    );
3864
                } else {
3865
                    $collapsableLink = Display::url(
3866
                        '<i class="fa fa-folder"></i>',
3867
                        $url.'&action=set_collapsable&option=0'
3868
                    );
3869
                }
3870
            }
3871
3872
            $params = [
3873
                'id_category' => $row['id'],
3874
                'title_category' => $row['title'],
3875
                'collapsed' => $collapsed,
3876
                'collapsable_link' => $collapsableLink,
3877
                'courses' => $courseInCategory,
3878
            ];
3879
            $listItems['in_category'][] = $params;
3880
        }
3881
3882
        // Step 2: We display the course without a user category.
3883
        $coursesNotCategory = self::returnCoursesCategories(
3884
            0,
3885
            $load_dirs,
3886
            $user_id,
3887
            $useUserLanguageFilterIfAvailable
3888
        );
3889
3890
        if ($coursesNotCategory) {
3891
            $listItems['not_category'] = $coursesNotCategory;
3892
        }
3893
3894
        return $listItems;
3895
    }
3896
3897
    /**
3898
     *  Display courses inside a category (without special courses) as HTML dics of
3899
     *  class userportal-course-item.
3900
     *
3901
     * @param int  $user_category_id                 User category id
3902
     * @param bool $load_dirs                        Whether to show the document quick-loader or not
3903
     * @param int  $user_id
3904
     * @param bool $useUserLanguageFilterIfAvailable
3905
     *
3906
     * @return array
3907
     */
3908
    public static function returnCoursesCategories(
3909
        $user_category_id,
3910
        $load_dirs = false,
3911
        $user_id = 0,
3912
        $useUserLanguageFilterIfAvailable = true
3913
    ) {
3914
        $user_id = $user_id ?: api_get_user_id();
3915
        $user_category_id = (int) $user_category_id;
3916
3917
        // Table definitions
3918
        $TABLECOURS = Database::get_main_table(TABLE_MAIN_COURSE);
3919
        $TABLECOURSUSER = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3920
        $TABLE_ACCESS_URL_REL_COURSE = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3921
        $current_url_id = api_get_current_access_url_id();
3922
3923
        // Get course list auto-register
3924
        $special_course_list = self::get_special_course_list();
3925
        $without_special_courses = '';
3926
        if (!empty($special_course_list)) {
3927
            $without_special_courses = ' AND course.id NOT IN ("'.implode('","', $special_course_list).'")';
3928
        }
3929
3930
        $userCategoryCondition = " (course_rel_user.user_course_cat = $user_category_id) ";
3931
        if (empty($user_category_id)) {
3932
            $userCategoryCondition = ' (course_rel_user.user_course_cat = 0 OR course_rel_user.user_course_cat IS NULL) ';
3933
        }
3934
3935
        $languageCondition = '';
3936
        $onlyInUserLanguage = api_get_configuration_value('my_courses_show_courses_in_user_language_only');
3937
        if ($useUserLanguageFilterIfAvailable && $onlyInUserLanguage) {
3938
            $userInfo = api_get_user_info(api_get_user_id());
3939
            if (!empty($userInfo['language'])) {
3940
                $languageCondition = " AND course.course_language = '".$userInfo['language']."' ";
3941
            }
3942
        }
3943
3944
        $sql = "SELECT DISTINCT
3945
                    course.id,
3946
                    course_rel_user.status status,
3947
                    course.code as course_code,
3948
                    user_course_cat,
3949
                    course_rel_user.sort
3950
                FROM $TABLECOURS course 
3951
                INNER JOIN $TABLECOURSUSER course_rel_user
3952
                ON (course.id = course_rel_user.c_id)
3953
                INNER JOIN $TABLE_ACCESS_URL_REL_COURSE url
3954
                ON (url.c_id = course.id)
3955
                WHERE
3956
                    course_rel_user.user_id = '".$user_id."' AND
3957
                    $userCategoryCondition
3958
                    $without_special_courses
3959
                    $languageCondition
3960
                ";
3961
        // If multiple URL access mode is enabled, only fetch courses
3962
        // corresponding to the current URL.
3963
        if (api_get_multiple_access_url() && $current_url_id != -1) {
3964
            $sql .= " AND access_url_id='".$current_url_id."'";
3965
        }
3966
        // Use user's classification for courses (if any).
3967
        $sql .= " ORDER BY course_rel_user.user_course_cat, course_rel_user.sort ASC";
3968
        $result = Database::query($sql);
3969
3970
        $showCustomIcon = api_get_setting('course_images_in_courses_list');
3971
        // Browse through all courses.
3972
        $courseAdded = [];
3973
        $courseList = [];
3974
        while ($row = Database::fetch_array($result)) {
3975
            $course_info = api_get_course_info_by_id($row['id']);
3976
3977
            if (isset($course_info['visibility']) &&
3978
                $course_info['visibility'] == COURSE_VISIBILITY_HIDDEN
3979
            ) {
3980
                continue;
3981
            }
3982
3983
            // Skip if already in list
3984
            if (in_array($course_info['real_id'], $courseAdded)) {
3985
                continue;
3986
            }
3987
            $course_info['id_session'] = null;
3988
            $course_info['status'] = $row['status'];
3989
            // For each course, get if there is any notification icon to show
3990
            // (something that would have changed since the user's last visit).
3991
            $showNotification = !api_get_configuration_value('hide_course_notification')
3992
                ? Display::show_notification($course_info)
3993
                : '';
3994
            $iconName = basename($course_info['course_image']);
3995
3996
            $params = [];
3997
            //Param (course_code) needed to get the student process
3998
            $params['course_code'] = $row['course_code'];
3999
            $params['code'] = $row['course_code'];
4000
4001
            if ($showCustomIcon === 'true' && $iconName != 'course.png') {
4002
                $params['thumbnails'] = $course_info['course_image'];
4003
                $params['image'] = $course_info['course_image_large'];
4004
            }
4005
4006
            $thumbnails = null;
4007
            $image = null;
4008
            if ($showCustomIcon === 'true' && $iconName != 'course.png') {
4009
                $thumbnails = $course_info['course_image'];
4010
                $image = $course_info['course_image_large'];
4011
            } else {
4012
                $image = Display::return_icon(
4013
                    'session_default.png',
4014
                    null,
4015
                    null,
4016
                    null,
4017
                    null,
4018
                    true
4019
                );
4020
            }
4021
4022
            $params['course_id'] = $course_info['real_id'];
4023
            $params['edit_actions'] = '';
4024
            $params['document'] = '';
4025
            if (api_is_platform_admin()) {
4026
                $params['edit_actions'] .= api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cidReq='.$course_info['code'];
4027
                if ($load_dirs) {
4028
                    $params['document'] = '<a id="document_preview_'.$course_info['real_id'].'_0" class="document_preview btn btn-default btn-sm" href="javascript:void(0);">'
4029
                               .Display::returnFontAwesomeIcon('folder-open').'</a>';
4030
                    $params['document'] .= Display::div(
4031
                        '',
4032
                        [
4033
                            'id' => 'document_result_'.$course_info['real_id'].'_0',
4034
                            'class' => 'document_preview_container',
4035
                        ]
4036
                    );
4037
                }
4038
            }
4039
            if ($load_dirs) {
4040
                $params['document'] = '<a id="document_preview_'.$course_info['real_id'].'_0" class="document_preview btn btn-default btn-sm" href="javascript:void(0);">'
4041
                    .Display::returnFontAwesomeIcon('folder-open').'</a>';
4042
                $params['document'] .= Display::div(
4043
                    '',
4044
                    [
4045
                        'id' => 'document_result_'.$course_info['real_id'].'_0',
4046
                        'class' => 'document_preview_container',
4047
                    ]
4048
                );
4049
            }
4050
4051
            $courseUrl = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/index.php?id_session=0';
4052
            $teachers = [];
4053
            if (api_get_setting('display_teacher_in_courselist') === 'true') {
4054
                $teachers = self::getTeachersFromCourse(
4055
                    $course_info['real_id'],
4056
                    true
4057
                );
4058
            }
4059
4060
            $params['status'] = $row['status'];
4061
            if (api_get_setting('display_coursecode_in_courselist') == 'true') {
4062
                $params['code_course'] = '('.$course_info['visual_code'].') ';
4063
            }
4064
4065
            $params['current_user_is_teacher'] = false;
4066
            /** @var array $teacher */
4067
            foreach ($teachers as $teacher) {
4068
                if ($teacher['id'] != $user_id) {
4069
                    continue;
4070
                }
4071
                $params['current_user_is_teacher'] = true;
4072
            }
4073
4074
            $params['visibility'] = $course_info['visibility'];
4075
            $params['link'] = $courseUrl;
4076
            $params['thumbnails'] = $thumbnails;
4077
            $params['image'] = $image;
4078
            $params['title'] = $course_info['title'];
4079
            $params['title_cut'] = $params['title'];
4080
            $params['category'] = $course_info['categoryName'];
4081
            $params['category_code'] = $course_info['categoryCode'];
4082
            $params['category_id'] = $course_info['categoryId'];
4083
            $params['color'] = Display::randomColor($params['category_id']);
4084
            $params['teachers'] = $teachers;
4085
4086
            if ($course_info['visibility'] != COURSE_VISIBILITY_CLOSED) {
4087
                $params['notifications'] = $showNotification;
4088
            }
4089
            $courseAdded[] = $course_info['real_id'];
4090
            $courseList[] = $params;
4091
        }
4092
4093
        return $courseList;
4094
    }
4095
4096
    /**
4097
     *  Display courses inside a category (without special courses) as HTML dics of
4098
     *  class userportal-course-item.
4099
     *
4100
     * @deprecated use self::returnCoursesCategories(0);
4101
     *
4102
     * @param int      User category id
4103
     * @param bool      Whether to show the document quick-loader or not
4104
     *
4105
     * @return array
4106
     */
4107
    public static function returnCoursesWithoutCategories($user_category_id, $load_dirs = false)
4108
    {
4109
        $user_id = api_get_user_id();
4110
        // Table definitions
4111
        $TABLECOURS = Database::get_main_table(TABLE_MAIN_COURSE);
4112
        $TABLECOURSUSER = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4113
        $TABLE_ACCESS_URL_REL_COURSE = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
4114
        $current_url_id = api_get_current_access_url_id();
4115
        $courseList = [];
4116
4117
        // Get course list auto-register
4118
        $special_course_list = self::get_special_course_list();
4119
4120
        $without_special_courses = '';
4121
        if (!empty($special_course_list)) {
4122
            $without_special_courses = ' AND course.id NOT IN ("'.implode('","', $special_course_list).'")';
4123
        }
4124
4125
        $sql = "SELECT
4126
                    course.id,
4127
                    course.title,
4128
                    course.code,
4129
                    course.subscribe subscr,
4130
                    course.unsubscribe unsubscr,
4131
                    course_rel_user.status status,
4132
                    course_rel_user.sort sort,
4133
                    course_rel_user.user_course_cat user_course_cat
4134
                FROM $TABLECOURS course 
4135
                INNER JOIN $TABLECOURSUSER course_rel_user
4136
                ON (course.id = course_rel_user.c_id)
4137
                INNER JOIN $TABLE_ACCESS_URL_REL_COURSE url
4138
                ON (url.c_id = course.id)
4139
                WHERE
4140
                    course_rel_user.user_id = $user_id AND
4141
                    course_rel_user.user_course_cat = $user_category_id
4142
                    $without_special_courses ";
4143
4144
        // If multiple URL access mode is enabled, only fetch courses
4145
        // corresponding to the current URL.
4146
        if (api_get_multiple_access_url() && $current_url_id != -1) {
4147
            $sql .= " AND url.c_id = course.id AND access_url_id = $current_url_id ";
4148
        }
4149
        // Use user's classification for courses (if any).
4150
        $sql .= " ORDER BY course_rel_user.user_course_cat, course_rel_user.sort ASC";
4151
        $result = Database::query($sql);
4152
4153
        $showCustomIcon = api_get_setting('course_images_in_courses_list');
4154
        // Browse through all courses.
4155
        while ($row = Database::fetch_array($result)) {
4156
            $course_info = api_get_course_info($row['code']);
4157
            if (isset($course_info['visibility']) &&
4158
                $course_info['visibility'] == COURSE_VISIBILITY_HIDDEN
4159
            ) {
4160
                continue;
4161
            }
4162
            $course_info['id_session'] = null;
4163
            $course_info['status'] = $row['status'];
4164
4165
            // For each course, get if there is any notification icon to show
4166
            // (something that would have changed since the user's last visit).
4167
            $showNotification = !api_get_configuration_value('hide_course_notification')
4168
                ? Display::show_notification($course_info)
4169
                : '';
4170
4171
            $thumbnails = null;
4172
            $image = null;
4173
            $iconName = basename($course_info['course_image']);
4174
            if ($showCustomIcon === 'true' && $iconName != 'course.png') {
4175
                $thumbnails = $course_info['course_image'];
4176
                $image = $course_info['course_image_large'];
4177
            } else {
4178
                $image = Display::return_icon(
4179
                    'session_default.png',
4180
                    null,
4181
                    null,
4182
                    null,
4183
                    null,
4184
                    true
4185
                );
4186
            }
4187
4188
            $params = [];
4189
            //Param (course_code) needed to get the student process
4190
            $params['course_code'] = $row['code'];
4191
            $params['edit_actions'] = '';
4192
            $params['document'] = '';
4193
            if (api_is_platform_admin()) {
4194
                $params['edit_actions'] .= api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cidReq='.$course_info['code'];
4195
                if ($load_dirs) {
4196
                    $params['document'] = '<a id="document_preview_'.$course_info['real_id'].'_0" class="document_preview btn btn-outline-secondary btn-sm" href="javascript:void(0);">'
4197
                               .Display::returnFontAwesomeIcon('folder-open').'</a>';
4198
                    $params['document'] .= Display::div('', ['id' => 'document_result_'.$course_info['real_id'].'_0', 'class' => 'document_preview_container']);
4199
                }
4200
            }
4201
            if ($load_dirs) {
4202
                $params['document'] = '<a id="document_preview_'.$course_info['real_id'].'_0" class="document_preview btn btn-outline-secondary btn-sm" href="javascript:void(0);">'
4203
                    .Display::returnFontAwesomeIcon('folder-open').'</a>';
4204
                $params['document'] .= Display::div('', ['id' => 'document_result_'.$course_info['real_id'].'_0', 'class' => 'document_preview_container']);
4205
            }
4206
4207
            $course_title_url = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/index.php?id_session=0';
4208
4209
            $teachers = [];
4210
            if (api_get_setting('display_teacher_in_courselist') === 'true') {
4211
                $teachers = self::getTeachersFromCourse(
4212
                    $course_info['real_id'],
4213
                    false
4214
                );
4215
            }
4216
            $params['status'] = $row['status'];
4217
4218
            if (api_get_setting('display_coursecode_in_courselist') == 'true') {
4219
                $params['code_course'] = '('.$course_info['visual_code'].') ';
4220
            }
4221
4222
            $params['visibility'] = $course_info['visibility'];
4223
            $params['link'] = $course_title_url;
4224
            $params['thumbnails'] = $thumbnails;
4225
            $params['image'] = $image;
4226
            $params['title'] = $course_info['title'];
4227
            $params['category'] = $course_info['categoryName'];
4228
            $params['teachers'] = $teachers;
4229
4230
            if ($course_info['visibility'] != COURSE_VISIBILITY_CLOSED) {
4231
                $params['notifications'] = $showNotification;
4232
            }
4233
4234
            $courseList[] = $params;
4235
        }
4236
4237
        return $courseList;
4238
    }
4239
4240
    /**
4241
     * Retrieves the user defined course categories.
4242
     *
4243
     * @param int $userId
4244
     *
4245
     * @return array
4246
     */
4247
    public static function get_user_course_categories($userId = 0)
4248
    {
4249
        $userId = empty($userId) ? api_get_user_id() : (int) $userId;
4250
        $table = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
4251
        $sql = "SELECT * FROM $table 
4252
                WHERE user_id = $userId
4253
                ORDER BY sort ASC
4254
                ";
4255
        $result = Database::query($sql);
4256
        $output = [];
4257
        while ($row = Database::fetch_array($result, 'ASSOC')) {
4258
            $output[$row['id']] = $row;
4259
        }
4260
4261
        return $output;
4262
    }
4263
4264
    /**
4265
     * Return an array the user_category id and title for the course $courseId for user $userId.
4266
     *
4267
     * @param $userId
4268
     * @param $courseId
4269
     *
4270
     * @return array
4271
     */
4272
    public static function getUserCourseCategoryForCourse($userId, $courseId)
4273
    {
4274
        $tblCourseRelUser = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4275
        $tblUserCategory = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
4276
        $courseId = intval($courseId);
4277
        $userId = intval($userId);
4278
4279
        $sql = "SELECT user_course_cat, title
4280
                FROM $tblCourseRelUser cru
4281
                LEFT JOIN $tblUserCategory ucc
4282
                ON cru.user_course_cat = ucc.id
4283
                WHERE
4284
                    cru.user_id = $userId AND c_id = $courseId ";
4285
4286
        $res = Database::query($sql);
4287
4288
        $data = [];
4289
        if (Database::num_rows($res) > 0) {
4290
            $data = Database::fetch_assoc($res);
4291
        }
4292
4293
        return $data;
4294
    }
4295
4296
    /**
4297
     * Get the course id based on the original id and field name in the extra fields.
4298
     * Returns 0 if course was not found.
4299
     *
4300
     * @param string $value    Original course code
4301
     * @param string $variable Original field name
4302
     *
4303
     * @return array
4304
     */
4305
    public static function getCourseInfoFromOriginalId($value, $variable)
4306
    {
4307
        $extraFieldValue = new ExtraFieldValue('course');
4308
        $result = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
4309
            $variable,
4310
            $value
4311
        );
4312
4313
        if (!empty($result)) {
4314
            $courseInfo = api_get_course_info_by_id($result['item_id']);
4315
4316
            return $courseInfo;
4317
        }
4318
4319
        return [];
4320
    }
4321
4322
    /**
4323
     * Display code for one specific course a logged in user is subscribed to.
4324
     * Shows a link to the course, what's new icons...
4325
     *
4326
     * $my_course['d'] - course directory
4327
     * $my_course['i'] - course title
4328
     * $my_course['c'] - visual course code
4329
     * $my_course['k']  - system course code
4330
     *
4331
     * @param   array       Course details
4332
     * @param   int     Session ID
4333
     * @param   string      CSS class to apply to course entry
4334
     * @param   bool     Whether the session is supposedly accessible now
4335
     * (not in the case it has passed and is in invisible/unaccessible mode)
4336
     * @param bool      Whether to show the document quick-loader or not
4337
     *
4338
     * @return string The HTML to be printed for the course entry
4339
     *
4340
     * @version 1.0.3
4341
     *
4342
     * @todo refactor into different functions for database calls | logic | display
4343
     * @todo replace single-character $my_course['d'] indices
4344
     * @todo move code for what's new icons to a separate function to clear things up
4345
     * @todo add a parameter user_id so that it is possible to show the
4346
     * courselist of other users (=generalisation).
4347
     * This will prevent having to write a new function for this.
4348
     */
4349
    public static function get_logged_user_course_html(
4350
        $course,
4351
        $session_id = 0,
4352
        $class = 'courses',
4353
        $session_accessible = true,
4354
        $load_dirs = false
4355
    ) {
4356
        $now = date('Y-m-d h:i:s');
4357
        $user_id = api_get_user_id();
4358
        $course_info = api_get_course_info_by_id($course['real_id']);
4359
        $course_visibility = (int) $course_info['visibility'];
4360
4361
        if ($course_visibility === COURSE_VISIBILITY_HIDDEN) {
4362
            return '';
4363
        }
4364
4365
        $userInCourseStatus = self::getUserInCourseStatus(
4366
            $user_id,
4367
            $course_info['real_id']
4368
        );
4369
4370
        $course_info['status'] = empty($session_id) ? $userInCourseStatus : STUDENT;
4371
        $course_info['id_session'] = $session_id;
4372
4373
        $is_coach = api_is_coach($session_id, $course_info['real_id']);
4374
4375
        // Display course entry.
4376
        // Show a hyperlink to the course, unless the course is closed and user is not course admin.
4377
        $session_url = '';
4378
        $params = [];
4379
        $params['icon'] = Display::return_icon(
4380
            'blackboard_blue.png',
4381
            null,
4382
            [],
4383
            ICON_SIZE_LARGE,
4384
            null,
4385
            true
4386
        );
4387
        $params['real_id'] = $course_info['real_id'];
4388
4389
        // Display the "what's new" icons
4390
        $notifications = '';
4391
        if (
4392
            ($course_visibility != COURSE_VISIBILITY_CLOSED && $course_visibility != COURSE_VISIBILITY_HIDDEN) ||
4393
            !api_get_configuration_value('hide_course_notification')
4394
        ) {
4395
            $notifications .= Display::show_notification($course_info);
4396
        }
4397
4398
        if ($session_accessible) {
4399
            if ($course_visibility != COURSE_VISIBILITY_CLOSED ||
4400
                $userInCourseStatus == COURSEMANAGER
4401
            ) {
4402
                if (empty($course_info['id_session'])) {
4403
                    $course_info['id_session'] = 0;
4404
                }
4405
4406
                $sessionCourseAvailable = false;
4407
                $sessionCourseStatus = api_get_session_visibility($session_id, $course_info['real_id']);
4408
4409
                if (in_array(
4410
                    $sessionCourseStatus,
4411
                    [SESSION_VISIBLE_READ_ONLY, SESSION_VISIBLE, SESSION_AVAILABLE]
4412
                )) {
4413
                    $sessionCourseAvailable = true;
4414
                }
4415
4416
                if ($userInCourseStatus === COURSEMANAGER || $sessionCourseAvailable) {
4417
                    $session_url = $course_info['course_public_url'].'?id_session='.$course_info['id_session'];
4418
                    $session_title = '<a title="'.$course_info['name'].'" href="'.$session_url.'">'.
4419
                        $course_info['name'].'</a>'.$notifications;
4420
                } else {
4421
                    $session_title = $course_info['name'];
4422
                }
4423
            } else {
4424
                $session_title =
4425
                    $course_info['name'].' '.
4426
                    Display::tag('span', get_lang('CourseClosed'), ['class' => 'item_closed']);
4427
            }
4428
        } else {
4429
            $session_title = $course_info['name'];
4430
        }
4431
4432
        $thumbnails = null;
4433
        $image = null;
4434
        $showCustomIcon = api_get_setting('course_images_in_courses_list');
4435
        $iconName = basename($course_info['course_image']);
4436
4437
        if ($showCustomIcon === 'true' && $iconName != 'course.png') {
4438
            $thumbnails = $course_info['course_image'];
4439
            $image = $course_info['course_image_large'];
4440
        } else {
4441
            $image = Display::return_icon(
4442
                'session_default.png',
4443
                null,
4444
                null,
4445
                null,
4446
                null,
4447
                true
4448
            );
4449
        }
4450
        $params['thumbnails'] = $thumbnails;
4451
        $params['image'] = $image;
4452
        $params['link'] = $session_url;
4453
        $params['title'] = $session_title;
4454
        $params['name'] = $course_info['name'];
4455
        $params['edit_actions'] = '';
4456
        $params['document'] = '';
4457
        $params['category'] = $course_info['categoryName'];
4458
4459
        if ($course_visibility != COURSE_VISIBILITY_CLOSED &&
4460
            $course_visibility != COURSE_VISIBILITY_HIDDEN
4461
        ) {
4462
            if (api_is_platform_admin()) {
4463
                $params['edit_actions'] .= api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cidReq='.$course_info['code'];
4464
                if ($load_dirs) {
4465
                    $params['document'] .= '<a 
4466
                        id="document_preview_'.$course_info['real_id'].'_'.$course_info['id_session'].'" 
4467
                        class="document_preview btn btn-outline-secondary btn-sm" 
4468
                        href="javascript:void(0);">'.
4469
                        Display::returnFontAwesomeIcon('folder-open').'</a>';
4470
                    $params['document'] .= Display::div('', [
4471
                        'id' => 'document_result_'.$course_info['real_id'].'_'.$course_info['id_session'],
4472
                        'class' => 'document_preview_container',
4473
                    ]);
4474
                }
4475
            }
4476
        }
4477
        if (api_get_setting('display_teacher_in_courselist') === 'true') {
4478
            $teacher_list = self::getTeachersFromCourse(
4479
                $course_info['real_id'],
4480
                true
4481
            );
4482
            $course_coachs = self::get_coachs_from_course(
4483
                $course_info['id_session'],
4484
                $course_info['real_id']
4485
            );
4486
            $params['teachers'] = $teacher_list;
4487
4488
            if (($course_info['status'] == STUDENT && !empty($course_info['id_session'])) ||
4489
                ($is_coach && $course_info['status'] != COURSEMANAGER)
4490
            ) {
4491
                $params['coaches'] = $course_coachs;
4492
            }
4493
        }
4494
        $special = isset($course['special_course']) ? true : false;
4495
        $params['title'] = $session_title;
4496
        $params['special'] = $special;
4497
        if (api_get_setting('display_coursecode_in_courselist') === 'true') {
4498
            $params['visual_code'] = '('.$course_info['visual_code'].')';
4499
        }
4500
        $params['extra'] = '';
4501
        $html = $params;
4502
4503
        $session_category_id = null;
4504
        if (1) {
4505
            $session = '';
4506
            $active = false;
4507
            if (!empty($course_info['id_session'])) {
4508
                $session = api_get_session_info($course_info['id_session']);
4509
                $sessionCoachName = '';
4510
                if (!empty($session['id_coach'])) {
4511
                    $coachInfo = api_get_user_info($session['id_coach']);
4512
                    $sessionCoachName = $coachInfo['complete_name'];
4513
                }
4514
4515
                $session_category_id = self::get_session_category_id_by_session_id($course_info['id_session']);
4516
4517
                if (
4518
                    $session['access_start_date'] === '0000-00-00 00:00:00' || empty($session['access_start_date']) ||
4519
                    $session['access_start_date'] === '0000-00-00'
4520
                ) {
4521
                    $session['dates'] = '';
4522
                    if (api_get_setting('show_session_coach') === 'true') {
4523
                        $session['coach'] = get_lang('GeneralCoach').': '.$sessionCoachName;
4524
                    }
4525
                    $active = true;
4526
                } else {
4527
                    $session['dates'] = ' - '.
4528
                        get_lang('From').' '.$session['access_start_date'].' '.
4529
                        get_lang('To').' '.$session['access_end_date'];
4530
                    if (api_get_setting('show_session_coach') === 'true') {
4531
                        $session['coach'] = get_lang('GeneralCoach').': '.$sessionCoachName;
4532
                    }
4533
                    $date_start = $session['access_start_date'];
4534
                    $date_end = $session['access_end_date'];
4535
                    $active = !$date_end ? ($date_start <= $now) : ($date_start <= $now && $date_end >= $now);
4536
                }
4537
            }
4538
            $user_course_category = '';
4539
            if (isset($course_info['user_course_cat'])) {
4540
                $user_course_category = $course_info['user_course_cat'];
4541
            }
4542
            $output = [
4543
                $user_course_category,
4544
                $html,
4545
                $course_info['id_session'],
4546
                $session,
4547
                'active' => $active,
4548
                'session_category_id' => $session_category_id,
4549
            ];
4550
4551
            if (Skill::isAllowed($user_id, false)) {
4552
                $em = Database::getManager();
4553
                $objUser = api_get_user_entity($user_id);
4554
                /** @var Course $objCourse */
4555
                $objCourse = $em->find('ChamiloCoreBundle:Course', $course['real_id']);
4556
                $objSession = $em->find('ChamiloCoreBundle:Session', $session_id);
4557
4558
                $skill = $em->getRepository('ChamiloCoreBundle:Skill')->getLastByUser($objUser, $objCourse, $objSession);
4559
4560
                $output['skill'] = null;
4561
                if ($skill) {
4562
                    $output['skill']['name'] = $skill->getName();
4563
                    $output['skill']['icon'] = $skill->getIcon();
4564
                }
4565
            }
4566
        } else {
4567
            $output = [$course_info['user_course_cat'], $html];
4568
        }
4569
4570
        return $output;
4571
    }
4572
4573
    /**
4574
     * @param string $source_course_code
4575
     * @param int    $source_session_id
4576
     * @param string $destination_course_code
4577
     * @param int    $destination_session_id
4578
     * @param array  $params
4579
     *
4580
     * @return bool
4581
     */
4582
    public static function copy_course(
4583
        $source_course_code,
4584
        $source_session_id,
4585
        $destination_course_code,
4586
        $destination_session_id,
4587
        $params = []
4588
    ) {
4589
        $course_info = api_get_course_info($source_course_code);
4590
4591
        if (!empty($course_info)) {
4592
            $cb = new CourseBuilder('', $course_info);
4593
            $course = $cb->build($source_session_id, $source_course_code, true);
4594
            $course_restorer = new CourseRestorer($course);
4595
            $course_restorer->skip_content = $params;
4596
            $course_restorer->restore(
4597
                $destination_course_code,
4598
                $destination_session_id,
4599
                true,
4600
                true
4601
            );
4602
4603
            return true;
4604
        }
4605
4606
        return false;
4607
    }
4608
4609
    /**
4610
     * A simpler version of the copy_course, the function creates an empty course with an autogenerated course code.
4611
     *
4612
     * @param string $new_title new course title
4613
     * @param string source course code
4614
     * @param int source session id
4615
     * @param int destination session id
4616
     * @param array $params
4617
     *
4618
     * @return array
4619
     */
4620
    public static function copy_course_simple(
4621
        $new_title,
4622
        $source_course_code,
4623
        $source_session_id = 0,
4624
        $destination_session_id = 0,
4625
        $params = []
4626
    ) {
4627
        $source_course_info = api_get_course_info($source_course_code);
4628
        if (!empty($source_course_info)) {
4629
            $new_course_code = self::generate_nice_next_course_code($source_course_code);
4630
            if ($new_course_code) {
4631
                $new_course_info = self::create_course(
4632
                    $new_title,
4633
                    $new_course_code,
4634
                    false
4635
                );
4636
                if (!empty($new_course_info['code'])) {
4637
                    $result = self::copy_course(
4638
                        $source_course_code,
4639
                        $source_session_id,
4640
                        $new_course_info['code'],
4641
                        $destination_session_id,
4642
                        $params
4643
                    );
4644
                    if ($result) {
4645
                        return $new_course_info;
4646
                    }
4647
                }
4648
            }
4649
        }
4650
4651
        return false;
4652
    }
4653
4654
    /**
4655
     * Creates a new course code based in a given code.
4656
     *
4657
     * @param string    wanted code
4658
     * <code>    $wanted_code = 'curse' if there are in the DB codes like curse1 curse2 the function will return: course3</code>
4659
     * if the course code doest not exist in the DB the same course code will be returned
4660
     *
4661
     * @return string wanted unused code
4662
     */
4663
    public static function generate_nice_next_course_code($wanted_code)
4664
    {
4665
        $course_code_ok = !self::course_code_exists($wanted_code);
4666
        if (!$course_code_ok) {
4667
            $wanted_code = self::generate_course_code($wanted_code);
4668
            $table = Database::get_main_table(TABLE_MAIN_COURSE);
4669
            $wanted_code = Database::escape_string($wanted_code);
4670
            $sql = "SELECT count(id) as count
4671
                    FROM $table
4672
                    WHERE code LIKE '$wanted_code%'";
4673
            $result = Database::query($sql);
4674
            if (Database::num_rows($result) > 0) {
4675
                $row = Database::fetch_array($result);
4676
                $count = $row['count'] + 1;
4677
                $wanted_code = $wanted_code.'_'.$count;
4678
                $result = api_get_course_info($wanted_code);
4679
                if (empty($result)) {
4680
                    return $wanted_code;
4681
                }
4682
            }
4683
4684
            return false;
4685
        }
4686
4687
        return $wanted_code;
4688
    }
4689
4690
    /**
4691
     * Gets the status of the users agreement in a course course-session.
4692
     *
4693
     * @param int    $user_id
4694
     * @param string $course_code
4695
     * @param int    $session_id
4696
     *
4697
     * @return bool
4698
     */
4699
    public static function is_user_accepted_legal($user_id, $course_code, $session_id = 0)
4700
    {
4701
        $user_id = intval($user_id);
4702
        $course_code = Database::escape_string($course_code);
4703
        $session_id = intval($session_id);
4704
4705
        $courseInfo = api_get_course_info($course_code);
4706
        $courseId = $courseInfo['real_id'];
4707
4708
        // Course legal
4709
        $enabled = api_get_plugin_setting('courselegal', 'tool_enable');
4710
4711
        if ($enabled == 'true') {
4712
            require_once api_get_path(SYS_PLUGIN_PATH).'courselegal/config.php';
4713
            $plugin = CourseLegalPlugin::create();
4714
4715
            return $plugin->isUserAcceptedLegal($user_id, $course_code, $session_id);
4716
        }
4717
4718
        if (empty($session_id)) {
4719
            $table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4720
            $sql = "SELECT legal_agreement FROM $table
4721
                    WHERE user_id = $user_id AND c_id = $courseId ";
4722
            $result = Database::query($sql);
4723
            if (Database::num_rows($result) > 0) {
4724
                $result = Database::fetch_array($result);
4725
                if ($result['legal_agreement'] == 1) {
4726
                    return true;
4727
                }
4728
            }
4729
4730
            return false;
4731
        } else {
4732
            $table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4733
            $sql = "SELECT legal_agreement FROM $table
4734
                    WHERE user_id = $user_id AND c_id = $courseId AND session_id = $session_id";
4735
            $result = Database::query($sql);
4736
            if (Database::num_rows($result) > 0) {
4737
                $result = Database::fetch_array($result);
4738
                if ($result['legal_agreement'] == 1) {
4739
                    return true;
4740
                }
4741
            }
4742
4743
            return false;
4744
        }
4745
    }
4746
4747
    /**
4748
     * Saves the user-course legal agreement.
4749
     *
4750
     * @param   int user id
4751
     * @param   string course code
4752
     * @param   int session id
4753
     *
4754
     * @return mixed
4755
     */
4756
    public static function save_user_legal($user_id, $course_code, $session_id = null)
4757
    {
4758
        // Course plugin legal
4759
        $enabled = api_get_plugin_setting('courselegal', 'tool_enable');
4760
        if ($enabled == 'true') {
4761
            require_once api_get_path(SYS_PLUGIN_PATH).'courselegal/config.php';
4762
            $plugin = CourseLegalPlugin::create();
4763
4764
            return $plugin->saveUserLegal($user_id, $course_code, $session_id);
4765
        }
4766
4767
        $user_id = intval($user_id);
4768
        $course_code = Database::escape_string($course_code);
4769
        $session_id = intval($session_id);
4770
        $courseInfo = api_get_course_info($course_code);
4771
        $courseId = $courseInfo['real_id'];
4772
4773
        if (empty($session_id)) {
4774
            $table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4775
            $sql = "UPDATE $table SET legal_agreement = '1'
4776
                    WHERE user_id = $user_id AND c_id  = $courseId ";
4777
            Database::query($sql);
4778
        } else {
4779
            $table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4780
            $sql = "UPDATE  $table SET legal_agreement = '1'
4781
                    WHERE user_id = $user_id AND c_id = $courseId AND session_id = $session_id";
4782
            Database::query($sql);
4783
        }
4784
    }
4785
4786
    /**
4787
     * @param int $user_id
4788
     * @param int $course_id
4789
     * @param int $session_id
4790
     * @param int $url_id
4791
     *
4792
     * @return bool
4793
     */
4794
    public static function get_user_course_vote($user_id, $course_id, $session_id = 0, $url_id = 0)
4795
    {
4796
        $table_user_course_vote = Database::get_main_table(TABLE_MAIN_USER_REL_COURSE_VOTE);
4797
        $session_id = !isset($session_id) ? api_get_session_id() : intval($session_id);
4798
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4799
        $user_id = intval($user_id);
4800
4801
        if (empty($user_id)) {
4802
            return false;
4803
        }
4804
4805
        $params = [
4806
            'user_id' => $user_id,
4807
            'c_id' => $course_id,
4808
            'session_id' => $session_id,
4809
            'url_id' => $url_id,
4810
        ];
4811
4812
        $result = Database::select(
4813
            'vote',
4814
            $table_user_course_vote,
4815
            [
4816
                'where' => [
4817
                    'user_id = ? AND c_id = ? AND session_id = ? AND url_id = ?' => $params,
4818
                ],
4819
            ],
4820
            'first'
4821
        );
4822
        if (!empty($result)) {
4823
            return $result['vote'];
4824
        }
4825
4826
        return false;
4827
    }
4828
4829
    /**
4830
     * @param int $course_id
4831
     * @param int $session_id
4832
     * @param int $url_id
4833
     *
4834
     * @return array
4835
     */
4836
    public static function get_course_ranking(
4837
        $course_id,
4838
        $session_id = 0,
4839
        $url_id = 0
4840
    ) {
4841
        $table_course_ranking = Database::get_main_table(TABLE_STATISTIC_TRACK_COURSE_RANKING);
4842
4843
        $session_id = empty($session_id) ? api_get_session_id() : intval($session_id);
4844
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4845
        $now = api_get_utc_datetime();
4846
4847
        $params = [
4848
            'c_id' => $course_id,
4849
            'session_id' => $session_id,
4850
            'url_id' => $url_id,
4851
            'creation_date' => $now,
4852
        ];
4853
4854
        $result = Database::select(
4855
            'c_id, accesses, total_score, users',
4856
            $table_course_ranking,
4857
            ['where' => ['c_id = ? AND session_id = ? AND url_id = ?' => $params]],
4858
            'first'
4859
        );
4860
4861
        $point_average_in_percentage = 0;
4862
        $point_average_in_star = 0;
4863
        $users_who_voted = 0;
4864
4865
        if (!empty($result['users'])) {
4866
            $users_who_voted = $result['users'];
4867
            $point_average_in_percentage = round($result['total_score'] / $result['users'] * 100 / 5, 2);
4868
            $point_average_in_star = round($result['total_score'] / $result['users'], 1);
4869
        }
4870
4871
        $result['user_vote'] = false;
4872
        if (!api_is_anonymous()) {
4873
            $result['user_vote'] = self::get_user_course_vote(api_get_user_id(), $course_id, $session_id, $url_id);
4874
        }
4875
4876
        $result['point_average'] = $point_average_in_percentage;
4877
        $result['point_average_star'] = $point_average_in_star;
4878
        $result['users_who_voted'] = $users_who_voted;
4879
4880
        return $result;
4881
    }
4882
4883
    /**
4884
     * Updates the course ranking.
4885
     *
4886
     * @param int   course id
4887
     * @param int $session_id
4888
     * @param int    url id
4889
     * @param $points_to_add
4890
     * @param bool $add_access
4891
     * @param bool $add_user
4892
     *
4893
     * @return array
4894
     */
4895
    public static function update_course_ranking(
4896
        $course_id = 0,
4897
        $session_id = 0,
4898
        $url_id = 0,
4899
        $points_to_add = null,
4900
        $add_access = true,
4901
        $add_user = true
4902
    ) {
4903
        // Course catalog stats modifications see #4191
4904
        $table_course_ranking = Database::get_main_table(TABLE_STATISTIC_TRACK_COURSE_RANKING);
4905
        $now = api_get_utc_datetime();
4906
        $course_id = empty($course_id) ? api_get_course_int_id() : intval($course_id);
4907
        $session_id = empty($session_id) ? api_get_session_id() : intval($session_id);
4908
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4909
4910
        $params = [
4911
            'c_id' => $course_id,
4912
            'session_id' => $session_id,
4913
            'url_id' => $url_id,
4914
            'creation_date' => $now,
4915
            'total_score' => 0,
4916
            'users' => 0,
4917
        ];
4918
4919
        $result = Database::select(
4920
            'id, accesses, total_score, users',
4921
            $table_course_ranking,
4922
            ['where' => ['c_id = ? AND session_id = ? AND url_id = ?' => $params]],
4923
            'first'
4924
        );
4925
4926
        // Problem here every time we load the courses/XXXX/index.php course home page we update the access
4927
        if (empty($result)) {
4928
            if ($add_access) {
4929
                $params['accesses'] = 1;
4930
            }
4931
            //The votes and users are empty
4932
            if (isset($points_to_add) && !empty($points_to_add)) {
4933
                $params['total_score'] = intval($points_to_add);
4934
            }
4935
            if ($add_user) {
4936
                $params['users'] = 1;
4937
            }
4938
            $result = Database::insert($table_course_ranking, $params);
4939
        } else {
4940
            $my_params = [];
4941
4942
            if ($add_access) {
4943
                $my_params['accesses'] = intval($result['accesses']) + 1;
4944
            }
4945
            if (isset($points_to_add) && !empty($points_to_add)) {
4946
                $my_params['total_score'] = $result['total_score'] + $points_to_add;
4947
            }
4948
            if ($add_user) {
4949
                $my_params['users'] = $result['users'] + 1;
4950
            }
4951
4952
            if (!empty($my_params)) {
4953
                $result = Database::update(
4954
                    $table_course_ranking,
4955
                    $my_params,
4956
                    ['c_id = ? AND session_id = ? AND url_id = ?' => $params]
4957
                );
4958
            }
4959
        }
4960
4961
        return $result;
4962
    }
4963
4964
    /**
4965
     * Add user vote to a course.
4966
     *
4967
     * @param   int user id
4968
     * @param   int vote [1..5]
4969
     * @param   int course id
4970
     * @param   int session id
4971
     * @param   int url id (access_url_id)
4972
     *
4973
     * @return false|string 'added', 'updated' or 'nothing'
4974
     */
4975
    public static function add_course_vote(
4976
        $user_id,
4977
        $vote,
4978
        $course_id,
4979
        $session_id = 0,
4980
        $url_id = 0
4981
    ) {
4982
        $table_user_course_vote = Database::get_main_table(TABLE_MAIN_USER_REL_COURSE_VOTE);
4983
        $course_id = empty($course_id) ? api_get_course_int_id() : intval($course_id);
4984
4985
        if (empty($course_id) || empty($user_id)) {
4986
            return false;
4987
        }
4988
4989
        if (!in_array($vote, [1, 2, 3, 4, 5])) {
4990
            return false;
4991
        }
4992
4993
        $session_id = empty($session_id) ? api_get_session_id() : intval($session_id);
4994
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4995
        $vote = intval($vote);
4996
4997
        $params = [
4998
            'user_id' => intval($user_id),
4999
            'c_id' => $course_id,
5000
            'session_id' => $session_id,
5001
            'url_id' => $url_id,
5002
            'vote' => $vote,
5003
        ];
5004
5005
        $action_done = 'nothing';
5006
        $result = Database::select(
5007
            'id, vote',
5008
            $table_user_course_vote,
5009
            ['where' => ['user_id = ? AND c_id = ? AND session_id = ? AND url_id = ?' => $params]],
5010
            'first'
5011
        );
5012
5013
        if (empty($result)) {
5014
            Database::insert($table_user_course_vote, $params);
5015
            $points_to_add = $vote;
5016
            $add_user = true;
5017
            $action_done = 'added';
5018
        } else {
5019
            $my_params = ['vote' => $vote];
5020
            $points_to_add = $vote - $result['vote'];
5021
            $add_user = false;
5022
5023
            Database::update(
5024
                $table_user_course_vote,
5025
                $my_params,
5026
                ['user_id = ? AND c_id = ? AND session_id = ? AND url_id = ?' => $params]
5027
            );
5028
            $action_done = 'updated';
5029
        }
5030
5031
        // Current points
5032
        if (!empty($points_to_add)) {
5033
            self::update_course_ranking(
5034
                $course_id,
5035
                $session_id,
5036
                $url_id,
5037
                $points_to_add,
5038
                false,
5039
                $add_user
5040
            );
5041
        }
5042
5043
        return $action_done;
5044
    }
5045
5046
    /**
5047
     * Remove course ranking + user votes.
5048
     *
5049
     * @param int $course_id
5050
     * @param int $session_id
5051
     * @param int $url_id
5052
     */
5053
    public static function remove_course_ranking($course_id, $session_id, $url_id = null)
5054
    {
5055
        $table_course_ranking = Database::get_main_table(TABLE_STATISTIC_TRACK_COURSE_RANKING);
5056
        $table_user_course_vote = Database::get_main_table(TABLE_MAIN_USER_REL_COURSE_VOTE);
5057
5058
        if (!empty($course_id) && isset($session_id)) {
5059
            $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
5060
            $params = [
5061
                'c_id' => $course_id,
5062
                'session_id' => $session_id,
5063
                'url_id' => $url_id,
5064
            ];
5065
            Database::delete($table_course_ranking, ['c_id = ? AND session_id = ? AND url_id = ?' => $params]);
5066
            Database::delete($table_user_course_vote, ['c_id = ? AND session_id = ? AND url_id = ?' => $params]);
5067
        }
5068
    }
5069
5070
    /**
5071
     * Returns an array with the hottest courses.
5072
     *
5073
     * @param int $days  number of days
5074
     * @param int $limit number of hottest courses
5075
     *
5076
     * @return array
5077
     */
5078
    public static function return_hot_courses($days = 30, $limit = 6)
5079
    {
5080
        if (api_is_invitee()) {
5081
            return [];
5082
        }
5083
5084
        $limit = intval($limit);
5085
5086
        // Getting my courses
5087
        $my_course_list = self::get_courses_list_by_user_id(api_get_user_id());
5088
5089
        $my_course_code_list = [];
5090
        foreach ($my_course_list as $course) {
5091
            $my_course_code_list[$course['real_id']] = $course['real_id'];
5092
        }
5093
5094
        if (api_is_drh()) {
5095
            $courses = self::get_courses_followed_by_drh(api_get_user_id());
5096
            foreach ($courses as $course) {
5097
                $my_course_code_list[$course['real_id']] = $course['real_id'];
5098
            }
5099
        }
5100
5101
        $table_course_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5102
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
5103
        $table_course_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
5104
        $urlId = api_get_current_access_url_id();
5105
        //$table_course_access table uses the now() and interval ...
5106
        $now = api_get_utc_datetime();
5107
        $sql = "SELECT COUNT(course_access_id) course_count, a.c_id, visibility
5108
                FROM $table_course c
5109
                INNER JOIN $table_course_access a
5110
                ON (c.id = a.c_id)
5111
                INNER JOIN $table_course_url u
5112
                ON u.c_id = c.id
5113
                WHERE
5114
                    u.access_url_id = $urlId AND
5115
                    login_course_date <= '$now' AND
5116
                    login_course_date > DATE_SUB('$now', INTERVAL $days DAY) AND
5117
                    visibility <> ".COURSE_VISIBILITY_CLOSED." AND
5118
                    visibility <> ".COURSE_VISIBILITY_HIDDEN." 
5119
                GROUP BY a.c_id
5120
                ORDER BY course_count DESC
5121
                LIMIT $limit
5122
            ";
5123
5124
        $result = Database::query($sql);
5125
        $courses = [];
5126
5127
        if (Database::num_rows($result)) {
5128
            $courses = Database::store_result($result, 'ASSOC');
5129
            $courses = self::processHotCourseItem($courses, $my_course_code_list);
5130
        }
5131
5132
        return $courses;
5133
    }
5134
5135
    /**
5136
     * @param array $courses
5137
     * @param array $my_course_code_list
5138
     *
5139
     * @return mixed
5140
     */
5141
    public static function processHotCourseItem($courses, $my_course_code_list = [])
5142
    {
5143
        $hotCourses = [];
5144
        $ajax_url = api_get_path(WEB_AJAX_PATH).'course.ajax.php?a=add_course_vote';
5145
        $stok = Security::get_existing_token();
5146
        $user_id = api_get_user_id();
5147
5148
        foreach ($courses as $courseId) {
5149
            $course_info = api_get_course_info_by_id($courseId['c_id']);
5150
            $courseCode = $course_info['code'];
5151
            $categoryCode = !empty($course_info['categoryCode']) ? $course_info['categoryCode'] : "";
5152
            $my_course = $course_info;
5153
            $my_course['go_to_course_button'] = '';
5154
            $my_course['register_button'] = '';
5155
5156
            $access_link = self::get_access_link_by_user(
5157
                api_get_user_id(),
5158
                $course_info,
5159
                $my_course_code_list
5160
            );
5161
5162
            $userRegisteredInCourse = self::is_user_subscribed_in_course($user_id, $course_info['code']);
5163
            $userRegisteredInCourseAsTeacher = self::is_course_teacher($user_id, $course_info['code']);
5164
            $userRegistered = $userRegisteredInCourse && $userRegisteredInCourseAsTeacher;
5165
            $my_course['is_registered'] = $userRegistered;
5166
            $my_course['title_cut'] = cut($course_info['title'], 45);
5167
5168
            // Course visibility
5169
            if ($access_link && in_array('register', $access_link)) {
5170
                $my_course['register_button'] = Display::url(
5171
                    get_lang('Subscribe').' '.
5172
                    Display::returnFontAwesomeIcon('sign-in'),
5173
                    api_get_path(WEB_COURSE_PATH).$course_info['path'].
5174
                     '/index.php?action=subscribe&sec_token='.$stok,
5175
                    [
5176
                        'class' => 'btn btn-success btn-sm',
5177
                        'title' => get_lang('Subscribe'),
5178
                        'aria-label' => get_lang('Subscribe'),
5179
                    ]
5180
                );
5181
            }
5182
5183
            if ($access_link && in_array('enter', $access_link) ||
5184
                $course_info['visibility'] == COURSE_VISIBILITY_OPEN_WORLD
5185
            ) {
5186
                $my_course['go_to_course_button'] = Display::url(
5187
                    get_lang('GoToCourse').' '.
5188
                    Display::returnFontAwesomeIcon('share'),
5189
                    api_get_path(WEB_COURSE_PATH).$course_info['path'].'/index.php',
5190
                    [
5191
                        'class' => 'btn btn-default btn-sm',
5192
                        'title' => get_lang('GoToCourse'),
5193
                        'aria-label' => get_lang('GoToCourse'),
5194
                    ]
5195
                );
5196
            }
5197
5198
            if ($access_link && in_array('unsubscribe', $access_link)) {
5199
                $my_course['unsubscribe_button'] = Display::url(
5200
                    get_lang('Unreg').' '.
5201
                    Display::returnFontAwesomeIcon('sign-out'),
5202
                    api_get_path(WEB_CODE_PATH).'auth/courses.php?action=unsubscribe&unsubscribe='.$courseCode
5203
                    .'&sec_token='.$stok.'&category_code='.$categoryCode,
5204
                    [
5205
                        'class' => 'btn btn-danger btn-sm',
5206
                        'title' => get_lang('Unreg'),
5207
                        'aria-label' => get_lang('Unreg'),
5208
                    ]
5209
                );
5210
            }
5211
5212
            // start buycourse validation
5213
            // display the course price and buy button if the buycourses plugin is enabled and this course is configured
5214
            $plugin = BuyCoursesPlugin::create();
5215
            $isThisCourseInSale = $plugin->buyCoursesForGridCatalogValidator(
5216
                $course_info['real_id'],
5217
                BuyCoursesPlugin::PRODUCT_TYPE_COURSE
5218
            );
5219
            if ($isThisCourseInSale) {
5220
                // set the price label
5221
                $my_course['price'] = $isThisCourseInSale['html'];
5222
                // set the Buy button instead register.
5223
                if ($isThisCourseInSale['verificator'] && !empty($my_course['register_button'])) {
5224
                    $my_course['register_button'] = $plugin->returnBuyCourseButton(
5225
                        $course_info['real_id'],
5226
                        BuyCoursesPlugin::PRODUCT_TYPE_COURSE
5227
                    );
5228
                }
5229
            }
5230
            // end buycourse validation
5231
5232
            // Description
5233
            $my_course['description_button'] = self::returnDescriptionButton($course_info);
5234
            $my_course['teachers'] = self::getTeachersFromCourse($course_info['real_id'], true);
5235
            $point_info = self::get_course_ranking($course_info['real_id'], 0);
5236
            $my_course['rating_html'] = '';
5237
            if (api_get_configuration_value('hide_course_rating') === false) {
5238
                $my_course['rating_html'] = Display::return_rating_system(
5239
                    'star_'.$course_info['real_id'],
5240
                    $ajax_url.'&course_id='.$course_info['real_id'],
5241
                    $point_info
5242
                );
5243
            }
5244
            $hotCourses[] = $my_course;
5245
        }
5246
5247
        return $hotCourses;
5248
    }
5249
5250
    /**
5251
     * @param int $limit
5252
     *
5253
     * @return array
5254
     */
5255
    public static function return_most_accessed_courses($limit = 5)
5256
    {
5257
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_COURSE_RANKING);
5258
        $params['url_id'] = api_get_current_access_url_id();
5259
5260
        $result = Database::select(
5261
            'c_id, accesses, total_score, users',
5262
            $table,
5263
            ['where' => ['url_id = ?' => $params], 'order' => 'accesses DESC', 'limit' => $limit],
5264
            'all',
5265
            true
5266
        );
5267
5268
        return $result;
5269
    }
5270
5271
    /**
5272
     * Get courses count.
5273
     *
5274
     * @param int $access_url_id Access URL ID (optional)
5275
     * @param int $visibility
5276
     *
5277
     * @return int Number of courses
5278
     */
5279
    public static function count_courses($access_url_id = null, $visibility = null)
5280
    {
5281
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
5282
        $table_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
5283
        $sql = "SELECT count(c.id) FROM $table_course c";
5284
        if (!empty($access_url_id) && $access_url_id == intval($access_url_id)) {
5285
            $sql .= ", $table_course_rel_access_url u
5286
                    WHERE c.id = u.c_id AND u.access_url_id = $access_url_id";
5287
            if (!empty($visibility)) {
5288
                $visibility = intval($visibility);
5289
                $sql .= " AND visibility = $visibility ";
5290
            }
5291
        } else {
5292
            if (!empty($visibility)) {
5293
                $visibility = intval($visibility);
5294
                $sql .= " WHERE visibility = $visibility ";
5295
            }
5296
        }
5297
5298
        $res = Database::query($sql);
5299
        $row = Database::fetch_row($res);
5300
5301
        return $row[0];
5302
    }
5303
5304
    /**
5305
     * Get active courses count.
5306
     * Active = all courses except the ones with hidden visibility.
5307
     *
5308
     * @param int $urlId Access URL ID (optional)
5309
     *
5310
     * @return int Number of courses
5311
     */
5312
    public static function countActiveCourses($urlId = null)
5313
    {
5314
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
5315
        $table_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
5316
        $sql = "SELECT count(id) FROM $table_course c";
5317
        if (!empty($urlId) && $urlId == intval($urlId)) {
5318
            $sql .= ", $table_course_rel_access_url u
5319
                    WHERE
5320
                        c.id = u.c_id AND
5321
                        u.access_url_id = $urlId AND
5322
                        visibility <> ".COURSE_VISIBILITY_HIDDEN;
5323
        } else {
5324
            $sql .= " WHERE visibility <> ".COURSE_VISIBILITY_HIDDEN;
5325
        }
5326
        $res = Database::query($sql);
5327
        $row = Database::fetch_row($res);
5328
5329
        return $row[0];
5330
    }
5331
5332
    /**
5333
     * Returns the SQL conditions to filter course only visible by the user in the catalogue.
5334
     *
5335
     * @param string $courseTableAlias Alias of the course table
5336
     * @param bool   $hideClosed       Whether to hide closed and hidden courses
5337
     *
5338
     * @return string SQL conditions
5339
     */
5340
    public static function getCourseVisibilitySQLCondition(
5341
        $courseTableAlias,
5342
        $hideClosed = false
5343
    ) {
5344
        $visibilityCondition = '';
5345
        $hidePrivate = api_get_setting('course_catalog_hide_private');
5346
        if ($hidePrivate === 'true') {
5347
            $visibilityCondition .= ' AND '.$courseTableAlias.'.visibility <> '.COURSE_VISIBILITY_REGISTERED;
5348
        }
5349
        if ($hideClosed) {
5350
            $visibilityCondition .= ' AND '.$courseTableAlias.'.visibility NOT IN ('.COURSE_VISIBILITY_CLOSED.','.COURSE_VISIBILITY_HIDDEN.')';
5351
        }
5352
5353
        // Check if course have users allowed to see it in the catalogue, then show only if current user is allowed to see it
5354
        $currentUserId = api_get_user_id();
5355
        $restrictedCourses = self::getCatalogueCourseList(true);
5356
        $allowedCoursesToCurrentUser = self::getCatalogueCourseList(true, $currentUserId);
5357
        if (!empty($restrictedCourses)) {
5358
            $visibilityCondition .= ' AND ('.$courseTableAlias.'.code NOT IN ("'.implode('","', $restrictedCourses).'")';
5359
            $visibilityCondition .= ' OR '.$courseTableAlias.'.code IN ("'.implode('","', $allowedCoursesToCurrentUser).'"))';
5360
        }
5361
5362
        // Check if course have users denied to see it in the catalogue, then show only if current user is not denied to see it
5363
        $restrictedCourses = self::getCatalogueCourseList(false);
5364
        $notAllowedCoursesToCurrentUser = self::getCatalogueCourseList(false, $currentUserId);
5365
        if (!empty($restrictedCourses)) {
5366
            $visibilityCondition .= ' AND ('.$courseTableAlias.'.code NOT IN ("'.implode('","', $restrictedCourses).'")';
5367
            $visibilityCondition .= ' OR '.$courseTableAlias.'.code NOT IN ("'.implode('","', $notAllowedCoursesToCurrentUser).'"))';
5368
        }
5369
5370
        return $visibilityCondition;
5371
    }
5372
5373
    /**
5374
     * Return a link to go to the course, validating the visibility of the
5375
     * course and the user status.
5376
     *
5377
     * @param int $uid User ID
5378
     * @param array Course details array
5379
     * @param array  List of courses to which the user is subscribed (if not provided, will be generated)
5380
     *
5381
     * @return mixed 'enter' for a link to go to the course or 'register' for a link to subscribe, or false if no access
5382
     */
5383
    public static function get_access_link_by_user($uid, $course, $user_courses = [])
5384
    {
5385
        if (empty($uid) || empty($course)) {
5386
            return false;
5387
        }
5388
5389
        if (empty($user_courses)) {
5390
            // get the array of courses to which the user is subscribed
5391
            $user_courses = self::get_courses_list_by_user_id($uid);
5392
            foreach ($user_courses as $k => $v) {
5393
                $user_courses[$k] = $v['real_id'];
5394
            }
5395
        }
5396
5397
        if (!isset($course['real_id']) && empty($course['real_id'])) {
5398
            $course = api_get_course_info($course['code']);
5399
        }
5400
5401
        if ($course['visibility'] == COURSE_VISIBILITY_HIDDEN) {
5402
            return [];
5403
        }
5404
5405
        $is_admin = api_is_platform_admin_by_id($uid);
5406
        $options = [];
5407
        // Register button
5408
        if (!api_is_anonymous($uid) &&
5409
            (
5410
            ($course['visibility'] == COURSE_VISIBILITY_OPEN_WORLD || $course['visibility'] == COURSE_VISIBILITY_OPEN_PLATFORM)
5411
                //$course['visibility'] == COURSE_VISIBILITY_REGISTERED && $course['subscribe'] == SUBSCRIBE_ALLOWED
5412
            ) &&
5413
            $course['subscribe'] == SUBSCRIBE_ALLOWED &&
5414
            (!in_array($course['real_id'], $user_courses) || empty($user_courses))
5415
        ) {
5416
            $options[] = 'register';
5417
        }
5418
5419
        // Go To Course button (only if admin, if course public or if student already subscribed)
5420
        if ($is_admin ||
5421
            $course['visibility'] == COURSE_VISIBILITY_OPEN_WORLD && empty($course['registration_code']) ||
5422
            (api_user_is_login($uid) && $course['visibility'] == COURSE_VISIBILITY_OPEN_PLATFORM && empty($course['registration_code'])) ||
5423
            (in_array($course['real_id'], $user_courses) && $course['visibility'] != COURSE_VISIBILITY_CLOSED)
5424
        ) {
5425
            $options[] = 'enter';
5426
        }
5427
5428
        if ($is_admin ||
5429
            $course['visibility'] == COURSE_VISIBILITY_OPEN_WORLD && empty($course['registration_code']) ||
5430
            (api_user_is_login($uid) && $course['visibility'] == COURSE_VISIBILITY_OPEN_PLATFORM && empty($course['registration_code'])) ||
5431
            (in_array($course['real_id'], $user_courses) && $course['visibility'] != COURSE_VISIBILITY_CLOSED)
5432
        ) {
5433
            $options[] = 'enter';
5434
        }
5435
5436
        if ($course['visibility'] != COURSE_VISIBILITY_HIDDEN &&
5437
            empty($course['registration_code']) &&
5438
            $course['unsubscribe'] == UNSUBSCRIBE_ALLOWED &&
5439
            api_user_is_login($uid) &&
5440
            in_array($course['real_id'], $user_courses)
5441
        ) {
5442
            $options[] = 'unsubscribe';
5443
        }
5444
5445
        return $options;
5446
    }
5447
5448
    /**
5449
     * @param array          $courseInfo
5450
     * @param array          $teachers
5451
     * @param bool           $deleteTeachersNotInList
5452
     * @param bool           $editTeacherInSessions
5453
     * @param bool           $deleteSessionTeacherNotInList
5454
     * @param array          $teacherBackup
5455
     * @param Monolog\Logger $logger
5456
     *
5457
     * @return false|null
5458
     */
5459
    public static function updateTeachers(
5460
        $courseInfo,
5461
        $teachers,
5462
        $deleteTeachersNotInList = true,
5463
        $editTeacherInSessions = false,
5464
        $deleteSessionTeacherNotInList = false,
5465
        $teacherBackup = [],
5466
        $logger = null
5467
    ) {
5468
        if (!is_array($teachers)) {
5469
            $teachers = [$teachers];
5470
        }
5471
5472
        if (empty($courseInfo) || !isset($courseInfo['real_id'])) {
5473
            return false;
5474
        }
5475
5476
        $teachers = array_filter($teachers);
5477
        $courseId = $courseInfo['real_id'];
5478
        $course_code = $courseInfo['code'];
5479
5480
        $course_user_table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5481
        $alreadyAddedTeachers = self::get_teacher_list_from_course_code($course_code);
5482
5483
        if ($deleteTeachersNotInList) {
5484
            // Delete only teacher relations that doesn't match the selected teachers
5485
            $cond = null;
5486
            if (count($teachers) > 0) {
5487
                foreach ($teachers as $key) {
5488
                    $key = Database::escape_string($key);
5489
                    $cond .= " AND user_id <> '".$key."'";
5490
                }
5491
            }
5492
5493
            // Recover user categories
5494
            $sql = "SELECT * FROM $course_user_table
5495
                    WHERE c_id = $courseId AND status = 1 AND relation_type = 0 ".$cond;
5496
            $result = Database::query($sql);
5497
            if (Database::num_rows($result)) {
5498
                $teachersToDelete = Database::store_result($result, 'ASSOC');
5499
                foreach ($teachersToDelete as $data) {
5500
                    $userId = $data['user_id'];
5501
                    $teacherBackup[$userId][$course_code] = $data;
5502
                }
5503
            }
5504
5505
            $sql = "DELETE FROM $course_user_table
5506
                    WHERE c_id = $courseId AND status = 1 AND relation_type = 0 ".$cond;
5507
5508
            Database::query($sql);
5509
        }
5510
5511
        if (count($teachers) > 0) {
5512
            foreach ($teachers as $userId) {
5513
                $userId = intval($userId);
5514
                // We check if the teacher is already subscribed in this course
5515
                $sql = "SELECT 1 FROM $course_user_table
5516
                        WHERE user_id = $userId AND c_id = $courseId";
5517
                $result = Database::query($sql);
5518
                if (Database::num_rows($result)) {
5519
                    $sql = "UPDATE $course_user_table 
5520
                            SET status = 1
5521
                            WHERE c_id = $courseId AND user_id = $userId ";
5522
                } else {
5523
                    $userCourseCategory = '0';
5524
                    if (isset($teacherBackup[$userId]) &&
5525
                        isset($teacherBackup[$userId][$course_code])
5526
                    ) {
5527
                        $courseUserData = $teacherBackup[$userId][$course_code];
5528
                        $userCourseCategory = $courseUserData['user_course_cat'];
5529
                        if ($logger) {
5530
                            $logger->addInfo("Recovering user_course_cat: $userCourseCategory");
5531
                        }
5532
                    }
5533
5534
                    $sql = "INSERT INTO $course_user_table SET
5535
                            c_id = $courseId,
5536
                            user_id = $userId,
5537
                            status = 1,
5538
                            is_tutor = 0,
5539
                            sort = 0,
5540
                            relation_type = 0,
5541
                            user_course_cat = $userCourseCategory
5542
                    ";
5543
                }
5544
                Database::query($sql);
5545
            }
5546
        }
5547
5548
        if ($editTeacherInSessions) {
5549
            $sessions = SessionManager::get_session_by_course($courseId);
5550
            if (!empty($sessions)) {
5551
                if ($logger) {
5552
                    $logger->addInfo("Edit teachers in sessions");
5553
                }
5554
                foreach ($sessions as $session) {
5555
                    $sessionId = $session['id'];
5556
                    // Remove old and add new
5557
                    if ($deleteSessionTeacherNotInList) {
5558
                        foreach ($teachers as $userId) {
5559
                            if ($logger) {
5560
                                $logger->addInfo("Set coach #$userId in session #$sessionId of course #$courseId ");
5561
                            }
5562
                            SessionManager::set_coach_to_course_session(
5563
                                $userId,
5564
                                $sessionId,
5565
                                $courseId
5566
                            );
5567
                        }
5568
5569
                        $teachersToDelete = [];
5570
                        if (!empty($alreadyAddedTeachers)) {
5571
                            $teachersToDelete = array_diff(array_keys($alreadyAddedTeachers), $teachers);
5572
                        }
5573
5574
                        if (!empty($teachersToDelete)) {
5575
                            foreach ($teachersToDelete as $userId) {
5576
                                if ($logger) {
5577
                                    $logger->addInfo("Delete coach #$userId in session #$sessionId of course #$courseId ");
5578
                                }
5579
                                SessionManager::set_coach_to_course_session(
5580
                                    $userId,
5581
                                    $sessionId,
5582
                                    $courseId,
5583
                                    true
5584
                                );
5585
                            }
5586
                        }
5587
                    } else {
5588
                        // Add new teachers only
5589
                        foreach ($teachers as $userId) {
5590
                            if ($logger) {
5591
                                $logger->addInfo("Add coach #$userId in session #$sessionId of course #$courseId ");
5592
                            }
5593
                            SessionManager::set_coach_to_course_session(
5594
                                $userId,
5595
                                $sessionId,
5596
                                $courseId
5597
                            );
5598
                        }
5599
                    }
5600
                }
5601
            }
5602
        }
5603
    }
5604
5605
    /**
5606
     * Course available settings variables see c_course_setting table.
5607
     *
5608
     * @param AppPlugin $appPlugin
5609
     *
5610
     * @return array
5611
     */
5612
    public static function getCourseSettingVariables(AppPlugin $appPlugin)
5613
    {
5614
        $pluginCourseSettings = $appPlugin->getAllPluginCourseSettings();
5615
        $courseSettings = [
5616
            // Get allow_learning_path_theme from table
5617
            'allow_learning_path_theme',
5618
            // Get allow_open_chat_window from table
5619
            'allow_open_chat_window',
5620
            'allow_public_certificates',
5621
            // Get allow_user_edit_agenda from table
5622
            'allow_user_edit_agenda',
5623
            // Get allow_user_edit_announcement from table
5624
            'allow_user_edit_announcement',
5625
            // Get allow_user_image_forum from table
5626
            'allow_user_image_forum',
5627
            //Get allow show user list
5628
            'allow_user_view_user_list',
5629
            // Get course_theme from table
5630
            'course_theme',
5631
            //Get allow show user list
5632
            'display_info_advance_inside_homecourse',
5633
            'documents_default_visibility',
5634
            // Get send_mail_setting (work)from table
5635
            'email_alert_manager_on_new_doc',
5636
            // Get send_mail_setting (work)from table
5637
            'email_alert_manager_on_new_quiz',
5638
            // Get send_mail_setting (dropbox) from table
5639
            'email_alert_on_new_doc_dropbox',
5640
            'email_alert_students_on_new_homework',
5641
            // Get send_mail_setting (auth)from table
5642
            'email_alert_to_teacher_on_new_user_in_course',
5643
            'enable_lp_auto_launch',
5644
            'enable_exercise_auto_launch',
5645
            'enable_document_auto_launch',
5646
            'pdf_export_watermark_text',
5647
            'show_system_folders',
5648
            'exercise_invisible_in_session',
5649
            'enable_forum_auto_launch',
5650
            'show_course_in_user_language',
5651
            'email_to_teachers_on_new_work_feedback',
5652
            'student_delete_own_publication',
5653
            'hide_forum_notifications',
5654
            'quiz_question_limit_per_day',
5655
        ];
5656
5657
        $courseModels = ExerciseLib::getScoreModels();
5658
        if (!empty($courseModels)) {
5659
            $courseSettings[] = 'score_model_id';
5660
        }
5661
5662
        $allowLPReturnLink = api_get_setting('allow_lp_return_link');
5663
        if ($allowLPReturnLink === 'true') {
5664
            $courseSettings[] = 'lp_return_link';
5665
        }
5666
5667
        if (!empty($pluginCourseSettings)) {
5668
            $courseSettings = array_merge(
5669
                $courseSettings,
5670
                $pluginCourseSettings
5671
            );
5672
        }
5673
5674
        return $courseSettings;
5675
    }
5676
5677
    /**
5678
     * @param AppPlugin    $appPlugin
5679
     * @param string       $variable
5680
     * @param string|array $value
5681
     * @param int          $courseId
5682
     *
5683
     * @return bool
5684
     */
5685
    public static function saveCourseConfigurationSetting(AppPlugin $appPlugin, $variable, $value, $courseId)
5686
    {
5687
        $settingList = self::getCourseSettingVariables($appPlugin);
5688
5689
        if (!in_array($variable, $settingList)) {
5690
            return false;
5691
        }
5692
5693
        $courseSettingTable = Database::get_course_table(TABLE_COURSE_SETTING);
5694
5695
        if (is_array($value)) {
5696
            $value = implode(',', $value);
5697
        }
5698
5699
        if (self::hasCourseSetting($variable, $courseId)) {
5700
            // Update
5701
            Database::update(
5702
                $courseSettingTable,
5703
                ['value' => $value],
5704
                ['variable = ? AND c_id = ?' => [$variable, $courseId]]
5705
            );
5706
        } else {
5707
            // Create
5708
            Database::insert(
5709
                $courseSettingTable,
5710
                [
5711
                    'title' => $variable,
5712
                    'value' => $value,
5713
                    'c_id' => $courseId,
5714
                    'variable' => $variable,
5715
                ]
5716
            );
5717
        }
5718
5719
        return true;
5720
    }
5721
5722
    /**
5723
     * Check if course setting exists.
5724
     *
5725
     * @param string $variable
5726
     * @param int    $courseId
5727
     *
5728
     * @return bool
5729
     */
5730
    public static function hasCourseSetting($variable, $courseId)
5731
    {
5732
        $courseSetting = Database::get_course_table(TABLE_COURSE_SETTING);
5733
        $courseId = intval($courseId);
5734
        $variable = Database::escape_string($variable);
5735
        $sql = "SELECT variable FROM $courseSetting
5736
                WHERE c_id = $courseId AND variable = '$variable'";
5737
        $result = Database::query($sql);
5738
5739
        return Database::num_rows($result) > 0;
5740
    }
5741
5742
    /**
5743
     * Get information from the track_e_course_access table.
5744
     *
5745
     * @param int $sessionId
5746
     * @param int $userId
5747
     * @param int $limit
5748
     *
5749
     * @return array
5750
     */
5751
    public static function getCourseAccessPerSessionAndUser($sessionId, $userId, $limit = 0)
5752
    {
5753
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5754
5755
        $sessionId = intval($sessionId);
5756
        $userId = intval($userId);
5757
5758
        $sql = "SELECT * FROM $table
5759
                WHERE session_id = $sessionId AND user_id = $userId";
5760
5761
        if (!empty($limit)) {
5762
            $limit = intval($limit);
5763
            $sql .= " LIMIT $limit";
5764
        }
5765
        $result = Database::query($sql);
5766
5767
        return Database::store_result($result);
5768
    }
5769
5770
    /**
5771
     * Get information from the track_e_course_access table.
5772
     *
5773
     * @param int    $courseId
5774
     * @param int    $sessionId
5775
     * @param string $startDate
5776
     * @param string $endDate
5777
     *
5778
     * @return array
5779
     */
5780
    public static function getCourseAccessPerCourseAndSession(
5781
        $courseId,
5782
        $sessionId,
5783
        $startDate,
5784
        $endDate
5785
    ) {
5786
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5787
        $courseId = intval($courseId);
5788
        $sessionId = intval($sessionId);
5789
        $startDate = Database::escape_string($startDate);
5790
        $endDate = Database::escape_string($endDate);
5791
5792
        $sql = "SELECT * FROM $table
5793
                WHERE
5794
                    c_id = $courseId AND
5795
                    session_id = $sessionId AND
5796
                    login_course_date BETWEEN '$startDate' AND '$endDate'
5797
                ";
5798
5799
        $result = Database::query($sql);
5800
5801
        return Database::store_result($result);
5802
    }
5803
5804
    /**
5805
     * Get login information from the track_e_course_access table, for any
5806
     * course in the given session.
5807
     *
5808
     * @param int $sessionId
5809
     * @param int $userId
5810
     *
5811
     * @return array
5812
     */
5813
    public static function getFirstCourseAccessPerSessionAndUser($sessionId, $userId)
5814
    {
5815
        $sessionId = (int) $sessionId;
5816
        $userId = (int) $userId;
5817
5818
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5819
        $sql = "SELECT * FROM $table
5820
                WHERE session_id = $sessionId AND user_id = $userId
5821
                ORDER BY login_course_date ASC
5822
                LIMIT 1";
5823
5824
        $result = Database::query($sql);
5825
        $courseAccess = [];
5826
        if (Database::num_rows($result)) {
5827
            $courseAccess = Database::fetch_array($result, 'ASSOC');
5828
        }
5829
5830
        return $courseAccess;
5831
    }
5832
5833
    /**
5834
     * @param int  $courseId
5835
     * @param int  $sessionId
5836
     * @param bool $getAllSessions
5837
     *
5838
     * @return mixed
5839
     */
5840
    public static function getCountForum(
5841
        $courseId,
5842
        $sessionId = 0,
5843
        $getAllSessions = false
5844
    ) {
5845
        $forum = Database::get_course_table(TABLE_FORUM);
5846
        if ($getAllSessions) {
5847
            $sql = "SELECT count(*) as count
5848
                    FROM $forum f
5849
                    WHERE f.c_id = %s";
5850
        } else {
5851
            $sql = "SELECT count(*) as count
5852
                    FROM $forum f
5853
                    WHERE f.c_id = %s and f.session_id = %s";
5854
        }
5855
5856
        $sql = sprintf($sql, intval($courseId), intval($sessionId));
5857
        $result = Database::query($sql);
5858
        $row = Database::fetch_array($result);
5859
5860
        return $row['count'];
5861
    }
5862
5863
    /**
5864
     * @param int $userId
5865
     * @param int $courseId
5866
     * @param int $sessionId
5867
     *
5868
     * @return mixed
5869
     */
5870
    public static function getCountPostInForumPerUser(
5871
        $userId,
5872
        $courseId,
5873
        $sessionId = 0
5874
    ) {
5875
        $forum = Database::get_course_table(TABLE_FORUM);
5876
        $forum_post = Database::get_course_table(TABLE_FORUM_POST);
5877
5878
        $sql = "SELECT count(distinct post_id) as count
5879
                FROM $forum_post p
5880
                INNER JOIN $forum f
5881
                ON f.forum_id = p.forum_id AND f.c_id = p.c_id
5882
                WHERE p.poster_id = %s and f.session_id = %s and p.c_id = %s";
5883
5884
        $sql = sprintf(
5885
            $sql,
5886
            intval($userId),
5887
            intval($sessionId),
5888
            intval($courseId)
5889
        );
5890
5891
        $result = Database::query($sql);
5892
        $row = Database::fetch_array($result);
5893
5894
        return $row['count'];
5895
    }
5896
5897
    /**
5898
     * @param int $userId
5899
     * @param int $courseId
5900
     * @param int $sessionId
5901
     *
5902
     * @return mixed
5903
     */
5904
    public static function getCountForumPerUser(
5905
        $userId,
5906
        $courseId,
5907
        $sessionId = 0
5908
    ) {
5909
        $forum = Database::get_course_table(TABLE_FORUM);
5910
        $forum_post = Database::get_course_table(TABLE_FORUM_POST);
5911
5912
        $sql = "SELECT count(distinct f.forum_id) as count
5913
                FROM $forum_post p
5914
                INNER JOIN $forum f
5915
                ON f.forum_id = p.forum_id AND f.c_id = p.c_id
5916
                WHERE p.poster_id = %s and f.session_id = %s and p.c_id = %s";
5917
5918
        $sql = sprintf(
5919
            $sql,
5920
            intval($userId),
5921
            intval($sessionId),
5922
            intval($courseId)
5923
        );
5924
5925
        $result = Database::query($sql);
5926
        $row = Database::fetch_array($result);
5927
5928
        return $row['count'];
5929
    }
5930
5931
    /**
5932
     * Returns the course name from a given code.
5933
     *
5934
     * @param string $code
5935
     *
5936
     * @return string
5937
     */
5938
    public static function getCourseNameFromCode($code)
5939
    {
5940
        $tbl_main_categories = Database::get_main_table(TABLE_MAIN_COURSE);
5941
        $code = Database::escape_string($code);
5942
        $sql = "SELECT title
5943
                FROM $tbl_main_categories
5944
                WHERE code = '$code'";
5945
        $result = Database::query($sql);
5946
        if ($col = Database::fetch_array($result)) {
5947
            return $col['title'];
5948
        }
5949
    }
5950
5951
    /**
5952
     * Generates a course code from a course title.
5953
     *
5954
     * @todo Such a function might be useful in other places too. It might be moved in the CourseManager class.
5955
     * @todo the function might be upgraded for avoiding code duplications (currently,
5956
     * it might suggest a code that is already in use)
5957
     *
5958
     * @param string $title A course title
5959
     *
5960
     * @return string A proposed course code
5961
     *                +
5962
     * @assert (null,null) === false
5963
     * @assert ('ABC_DEF', null) === 'ABCDEF'
5964
     * @assert ('ABC09*^[%A', null) === 'ABC09A'
5965
     */
5966
    public static function generate_course_code($title)
5967
    {
5968
        return substr(
5969
            preg_replace('/[^A-Z0-9]/', '', strtoupper(api_replace_dangerous_char($title))),
5970
            0,
5971
            self::MAX_COURSE_LENGTH_CODE
5972
        );
5973
    }
5974
5975
    /**
5976
     * @param $courseId
5977
     *
5978
     * @return array
5979
     */
5980
    public static function getCourseSettings($courseId)
5981
    {
5982
        $settingTable = Database::get_course_table(TABLE_COURSE_SETTING);
5983
        $courseId = intval($courseId);
5984
        $sql = "SELECT * FROM $settingTable WHERE c_id = $courseId";
5985
        $result = Database::query($sql);
5986
        $settings = [];
5987
        if (Database::num_rows($result)) {
5988
            while ($row = Database::fetch_array($result, 'ASSOC')) {
5989
                $settings[$row['variable']] = $row;
5990
            }
5991
        }
5992
5993
        return $settings;
5994
    }
5995
5996
    /**
5997
     * this function gets all the users of the course,
5998
     * including users from linked courses.
5999
     *
6000
     * @param $filterByActive
6001
     *
6002
     * @return array
6003
     */
6004
    public static function getCourseUsers($filterByActive = null)
6005
    {
6006
        // This would return only the users from real courses:
6007
        $userList = self::get_user_list_from_course_code(
6008
            api_get_course_id(),
6009
            api_get_session_id(),
6010
            null,
6011
            null,
6012
            null,
6013
            null,
6014
            false,
6015
            false,
6016
            [],
6017
            [],
6018
            [],
6019
            $filterByActive
6020
        );
6021
6022
        return $userList;
6023
    }
6024
6025
    /**
6026
     * this function gets all the groups of the course,
6027
     * not including linked courses.
6028
     */
6029
    public static function getCourseGroups()
6030
    {
6031
        $sessionId = api_get_session_id();
6032
        if ($sessionId != 0) {
6033
            $groupList = self::get_group_list_of_course(
6034
                api_get_course_id(),
6035
                $sessionId,
6036
                1
6037
            );
6038
        } else {
6039
            $groupList = self::get_group_list_of_course(
6040
                api_get_course_id(),
6041
                0,
6042
                1
6043
            );
6044
        }
6045
6046
        return $groupList;
6047
    }
6048
6049
    /**
6050
     * @param FormValidator $form
6051
     * @param array         $alreadySelected
6052
     *
6053
     * @return HTML_QuickForm_element
6054
     */
6055
    public static function addUserGroupMultiSelect(&$form, $alreadySelected)
6056
    {
6057
        $userList = self::getCourseUsers(true);
6058
        $groupList = self::getCourseGroups();
6059
6060
        $array = self::buildSelectOptions(
6061
            $groupList,
6062
            $userList,
6063
            $alreadySelected
6064
        );
6065
6066
        $result = [];
6067
        foreach ($array as $content) {
6068
            $result[$content['value']] = $content['content'];
6069
        }
6070
6071
        return $form->addElement(
6072
            'advmultiselect',
6073
            'users',
6074
            get_lang('Users'),
6075
            $result,
6076
            ['select_all_checkbox' => true]
6077
        );
6078
    }
6079
6080
    /**
6081
     * This function separates the users from the groups
6082
     * users have a value USER:XXX (with XXX the groups id have a value
6083
     *  GROUP:YYY (with YYY the group id).
6084
     *
6085
     * @param array $to Array of strings that define the type and id of each destination
6086
     *
6087
     * @return array Array of groups and users (each an array of IDs)
6088
     */
6089
    public static function separateUsersGroups($to)
6090
    {
6091
        $groupList = [];
6092
        $userList = [];
6093
6094
        foreach ($to as $to_item) {
6095
            if (!empty($to_item)) {
6096
                $parts = explode(':', $to_item);
6097
                $type = isset($parts[0]) ? $parts[0] : '';
6098
                $id = isset($parts[1]) ? $parts[1] : '';
6099
6100
                switch ($type) {
6101
                    case 'GROUP':
6102
                        $groupList[] = (int) $id;
6103
                        break;
6104
                    case 'USER':
6105
                        $userList[] = (int) $id;
6106
                        break;
6107
                }
6108
            }
6109
        }
6110
6111
        $send_to['groups'] = $groupList;
6112
        $send_to['users'] = $userList;
6113
6114
        return $send_to;
6115
    }
6116
6117
    /**
6118
     * Shows the form for sending a message to a specific group or user.
6119
     *
6120
     * @param FormValidator $form
6121
     * @param array         $groupInfo
6122
     * @param array         $to
6123
     *
6124
     * @return HTML_QuickForm_element
6125
     */
6126
    public static function addGroupMultiSelect($form, $groupInfo, $to = [])
6127
    {
6128
        $groupUsers = GroupManager::get_subscribed_users($groupInfo);
6129
        $array = self::buildSelectOptions([$groupInfo], $groupUsers, $to);
6130
6131
        $result = [];
6132
        foreach ($array as $content) {
6133
            $result[$content['value']] = $content['content'];
6134
        }
6135
6136
        return $form->addElement('advmultiselect', 'users', get_lang('Users'), $result);
6137
    }
6138
6139
    /**
6140
     * this function shows the form for sending a message to a specific group or user.
6141
     *
6142
     * @param array $groupList
6143
     * @param array $userList
6144
     * @param array $alreadySelected
6145
     *
6146
     * @return array
6147
     */
6148
    public static function buildSelectOptions(
6149
        $groupList = [],
6150
        $userList = [],
6151
        $alreadySelected = []
6152
    ) {
6153
        if (empty($alreadySelected)) {
6154
            $alreadySelected = [];
6155
        }
6156
6157
        $result = [];
6158
        // adding the groups to the select form
6159
        if ($groupList) {
6160
            foreach ($groupList as $thisGroup) {
6161
                $groupId = $thisGroup['iid'];
6162
                if (is_array($alreadySelected)) {
6163
                    if (!in_array(
6164
                        "GROUP:".$groupId,
6165
                        $alreadySelected
6166
                    )
6167
                    ) {
6168
                        $userCount = isset($thisGroup['userNb']) ? $thisGroup['userNb'] : 0;
6169
                        if (empty($userCount)) {
6170
                            $userCount = isset($thisGroup['count_users']) ? $thisGroup['count_users'] : 0;
6171
                        }
6172
                        // $alreadySelected is the array containing the groups (and users) that are already selected
6173
                        $user_label = ($userCount > 0) ? get_lang('Users') : get_lang('LowerCaseUser');
6174
                        $user_disabled = ($userCount > 0) ? "" : "disabled=disabled";
6175
                        $result[] = [
6176
                            'disabled' => $user_disabled,
6177
                            'value' => "GROUP:".$groupId,
6178
                            // The space before "G" is needed in order to advmultiselect.php js puts groups first
6179
                            'content' => " G: ".$thisGroup['name']." - ".$userCount." ".$user_label,
6180
                        ];
6181
                    }
6182
                }
6183
            }
6184
        }
6185
6186
        // adding the individual users to the select form
6187
        if ($userList) {
6188
            foreach ($userList as $user) {
6189
                if (is_array($alreadySelected)) {
6190
                    if (!in_array(
6191
                        "USER:".$user['user_id'],
6192
                        $alreadySelected
6193
                    )
6194
                    ) {
6195
                        // $alreadySelected is the array containing the users (and groups) that are already selected
6196
                        $result[] = [
6197
                            'value' => "USER:".$user['user_id'],
6198
                            'content' => api_get_person_name($user['firstname'], $user['lastname']),
6199
                        ];
6200
                    }
6201
                }
6202
            }
6203
        }
6204
6205
        return $result;
6206
    }
6207
6208
    /**
6209
     * @return array a list (array) of all courses
6210
     */
6211
    public static function get_course_list()
6212
    {
6213
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
6214
6215
        return Database::store_result(Database::query("SELECT *, id as real_id FROM $table"));
6216
    }
6217
6218
    /**
6219
     * Returns course code from a given gradebook category's id.
6220
     *
6221
     * @param int  Category ID
6222
     *
6223
     * @return string Course code
6224
     */
6225
    public static function get_course_by_category($category_id)
6226
    {
6227
        $category_id = (int) $category_id;
6228
        $sql = 'SELECT c_id FROM '.Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY).'
6229
                WHERE id='.$category_id;
6230
        $info = Database::fetch_array(Database::query($sql), 'ASSOC');
6231
6232
        return $info ? $info['c_id'] : false;
6233
    }
6234
6235
    /**
6236
     * This function gets all the courses that are not in a session.
6237
     *
6238
     * @param date Start date
6239
     * @param date End date
6240
     * @param bool $includeClosed Whether to include closed and hidden courses
6241
     *
6242
     * @return array Not-in-session courses
6243
     */
6244
    public static function getCoursesWithoutSession(
6245
        $startDate = null,
6246
        $endDate = null,
6247
        $includeClosed = false
6248
    ) {
6249
        $dateConditional = ($startDate && $endDate) ?
6250
            " WHERE session_id IN (SELECT id FROM ".Database::get_main_table(TABLE_MAIN_SESSION).
6251
            " WHERE access_start_date = '$startDate' AND access_end_date = '$endDate')" : null;
6252
        $visibility = ($includeClosed ? '' : 'visibility NOT IN (0, 4) AND ');
6253
6254
        $sql = "SELECT id, code, title
6255
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
6256
                WHERE $visibility code NOT IN (
6257
                    SELECT DISTINCT course_code 
6258
                    FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE).$dateConditional."
6259
                )
6260
                ORDER BY id";
6261
6262
        $result = Database::query($sql);
6263
        $courses = [];
6264
        while ($row = Database::fetch_array($result)) {
6265
            $courses[] = $row;
6266
        }
6267
6268
        return $courses;
6269
    }
6270
6271
    /**
6272
     * Get list of courses based on users of a group for a group admin.
6273
     *
6274
     * @param int $userId The user id
6275
     *
6276
     * @return array
6277
     */
6278
    public static function getCoursesFollowedByGroupAdmin($userId)
6279
    {
6280
        $coursesList = [];
6281
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
6282
        $courseUserTable = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6283
        $userGroup = new UserGroup();
6284
        $userIdList = $userGroup->getGroupUsersByUser($userId);
6285
6286
        if (empty($userIdList)) {
6287
            return [];
6288
        }
6289
6290
        $sql = "SELECT DISTINCT(c.id), c.title
6291
                FROM $courseTable c
6292
                INNER JOIN $courseUserTable cru ON c.id = cru.c_id
6293
                WHERE (
6294
                    cru.user_id IN (".implode(', ', $userIdList).")
6295
                    AND cru.relation_type = 0
6296
                )";
6297
6298
        if (api_is_multiple_url_enabled()) {
6299
            $courseAccessUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
6300
            $accessUrlId = api_get_current_access_url_id();
6301
6302
            if ($accessUrlId != -1) {
6303
                $sql = "SELECT DISTINCT(c.id), c.title
6304
                        FROM $courseTable c
6305
                        INNER JOIN $courseUserTable cru ON c.id = cru.c_id
6306
                        INNER JOIN $courseAccessUrlTable crau ON c.id = crau.c_id
6307
                        WHERE crau.access_url_id = $accessUrlId
6308
                            AND (
6309
                            cru.id_user IN (".implode(', ', $userIdList).") AND
6310
                            cru.relation_type = 0
6311
                        )";
6312
            }
6313
        }
6314
6315
        $result = Database::query($sql);
6316
        while ($row = Database::fetch_assoc($result)) {
6317
            $coursesList[] = $row;
6318
        }
6319
6320
        return $coursesList;
6321
    }
6322
6323
    /**
6324
     * Direct course link see #5299.
6325
     *
6326
     * You can send to your students an URL like this
6327
     * http://chamilodev.beeznest.com/main/auth/inscription.php?c=ABC&e=3
6328
     * Where "c" is the course code and "e" is the exercise Id, after a successful
6329
     * registration the user will be sent to the course or exercise
6330
     *
6331
     * @param array $form_data
6332
     *
6333
     * @return array
6334
     */
6335
    public static function redirectToCourse($form_data)
6336
    {
6337
        $course_code_redirect = Session::read('course_redirect');
6338
        $_user = api_get_user_info();
6339
        $userId = api_get_user_id();
6340
6341
        if (!empty($course_code_redirect)) {
6342
            $course_info = api_get_course_info($course_code_redirect);
6343
            if (!empty($course_info)) {
6344
                if (in_array(
6345
                    $course_info['visibility'],
6346
                    [COURSE_VISIBILITY_OPEN_PLATFORM, COURSE_VISIBILITY_OPEN_WORLD]
6347
                )
6348
                ) {
6349
                    if (self::is_user_subscribed_in_course($userId, $course_info['code'])) {
6350
                        $form_data['action'] = $course_info['course_public_url'];
6351
                        $form_data['message'] = sprintf(get_lang('YouHaveBeenRegisteredToCourseX'), $course_info['title']);
6352
                        $form_data['button'] = Display::button(
6353
                            'next',
6354
                            get_lang('GoToCourse', null, $_user['language']),
6355
                            ['class' => 'btn btn-primary btn-large']
6356
                        );
6357
6358
                        $exercise_redirect = intval(Session::read('exercise_redirect'));
6359
                        // Specify the course id as the current context does not
6360
                        // hold a global $_course array
6361
                        $objExercise = new Exercise($course_info['real_id']);
6362
                        $result = $objExercise->read($exercise_redirect);
6363
6364
                        if (!empty($exercise_redirect) && !empty($result)) {
6365
                            $form_data['action'] = api_get_path(WEB_CODE_PATH).
6366
                                'exercise/overview.php?exerciseId='.$exercise_redirect.'&cidReq='.$course_info['code'];
6367
                            $form_data['message'] .= '<br />'.get_lang('YouCanAccessTheExercise');
6368
                            $form_data['button'] = Display::button(
6369
                                'next',
6370
                                get_lang('Go', null, $_user['language']),
6371
                                ['class' => 'btn btn-primary btn-large']
6372
                            );
6373
                        }
6374
6375
                        if (!empty($form_data['action'])) {
6376
                            header('Location: '.$form_data['action']);
6377
                            exit;
6378
                        }
6379
                    }
6380
                }
6381
            }
6382
        }
6383
6384
        return $form_data;
6385
    }
6386
6387
    /**
6388
     * Return tab of params to display a course title in the My Courses tab
6389
     * Check visibility, right, and notification icons, and load_dirs option
6390
     * get html course params.
6391
     *
6392
     * @param $courseId
6393
     * @param bool $loadDirs
6394
     *
6395
     * @return array with keys ['right_actions'] ['teachers'] ['notifications']
6396
     */
6397
    public static function getCourseParamsForDisplay($courseId, $loadDirs = false)
6398
    {
6399
        $userId = api_get_user_id();
6400
        $courseId = intval($courseId);
6401
        // Table definitions
6402
        $TABLECOURS = Database::get_main_table(TABLE_MAIN_COURSE);
6403
        $TABLECOURSUSER = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6404
        $TABLE_ACCESS_URL_REL_COURSE = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
6405
        $current_url_id = api_get_current_access_url_id();
6406
6407
        // Get course list auto-register
6408
        $special_course_list = self::get_special_course_list();
6409
6410
        $without_special_courses = '';
6411
        if (!empty($special_course_list)) {
6412
            $without_special_courses = ' AND course.id NOT IN ("'.implode('","', $special_course_list).'")';
6413
        }
6414
6415
        //AND course_rel_user.relation_type<>".COURSE_RELATION_TYPE_RRHH."
6416
        $sql = "SELECT 
6417
                    course.id, 
6418
                    course.title, 
6419
                    course.code, 
6420
                    course.subscribe subscr, 
6421
                    course.unsubscribe unsubscr, 
6422
                    course_rel_user.status status,
6423
                    course_rel_user.sort sort, 
6424
                    course_rel_user.user_course_cat user_course_cat
6425
                FROM
6426
                $TABLECOURS course 
6427
                INNER JOIN $TABLECOURSUSER course_rel_user                
6428
                ON (course.id = course_rel_user.c_id)
6429
                INNER JOIN $TABLE_ACCESS_URL_REL_COURSE url
6430
                ON (url.c_id = course.id)
6431
                WHERE
6432
                    course.id = $courseId AND
6433
                    course_rel_user.user_id = $userId
6434
                    $without_special_courses
6435
                ";
6436
6437
        // If multiple URL access mode is enabled, only fetch courses
6438
        // corresponding to the current URL.
6439
        if (api_get_multiple_access_url() && $current_url_id != -1) {
6440
            $sql .= " AND url.c_id = course.id AND access_url_id = $current_url_id";
6441
        }
6442
        // Use user's classification for courses (if any).
6443
        $sql .= " ORDER BY course_rel_user.user_course_cat, course_rel_user.sort ASC";
6444
6445
        $result = Database::query($sql);
6446
6447
        // Browse through all courses. We can only have one course because
6448
        // of the  course.id=".intval($courseId) in sql query
6449
        $course = Database::fetch_array($result);
6450
        $course_info = api_get_course_info_by_id($courseId);
6451
        if (empty($course_info)) {
6452
            return '';
6453
        }
6454
6455
        //$course['id_session'] = null;
6456
        $course_info['id_session'] = null;
6457
        $course_info['status'] = $course['status'];
6458
6459
        // For each course, get if there is any notification icon to show
6460
        // (something that would have changed since the user's last visit).
6461
        $show_notification = !api_get_configuration_value('hide_course_notification')
6462
            ? Display::show_notification($course_info)
6463
            : '';
6464
6465
        // New code displaying the user's status in respect to this course.
6466
        $status_icon = Display::return_icon(
6467
            'blackboard.png',
6468
            $course_info['title'],
6469
            [],
6470
            ICON_SIZE_LARGE
6471
        );
6472
6473
        $params = [];
6474
        $params['right_actions'] = '';
6475
6476
        if (api_is_platform_admin()) {
6477
            if ($loadDirs) {
6478
                $params['right_actions'] .= '<a id="document_preview_'.$course_info['real_id'].'_0" class="document_preview" href="javascript:void(0);">'.Display::return_icon('folder.png', get_lang('Documents'), ['align' => 'absmiddle'], ICON_SIZE_SMALL).'</a>';
6479
                $params['right_actions'] .= '<a href="'.api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cidReq='.$course['code'].'">'.
6480
                    Display::return_icon('edit.png', get_lang('Edit'), ['align' => 'absmiddle'], ICON_SIZE_SMALL).
6481
                    '</a>';
6482
                $params['right_actions'] .= Display::div(
6483
                    '',
6484
                    [
6485
                        'id' => 'document_result_'.$course_info['real_id'].'_0',
6486
                        'class' => 'document_preview_container',
6487
                    ]
6488
                );
6489
            } else {
6490
                $params['right_actions'] .= '<a class="btn btn-default btn-sm" title="'.get_lang('Edit').'" href="'.api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cidReq='.$course['code'].'">'.
6491
                    Display::returnFontAwesomeIcon('pencil').'</a>';
6492
            }
6493
        } else {
6494
            if ($course_info['visibility'] != COURSE_VISIBILITY_CLOSED) {
6495
                if ($loadDirs) {
6496
                    $params['right_actions'] .= '<a id="document_preview_'.$course_info['real_id'].'_0" class="document_preview" href="javascript:void(0);">'.
6497
                        Display::return_icon('folder.png', get_lang('Documents'), ['align' => 'absmiddle'], ICON_SIZE_SMALL).'</a>';
6498
                    $params['right_actions'] .= Display::div(
6499
                        '',
6500
                        [
6501
                            'id' => 'document_result_'.$course_info['real_id'].'_0',
6502
                            'class' => 'document_preview_container',
6503
                        ]
6504
                    );
6505
                } else {
6506
                    if ($course_info['status'] == COURSEMANAGER) {
6507
                        $params['right_actions'] .= '<a class="btn btn-default btn-sm" title="'.get_lang('Edit').'" href="'.api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cidReq='.$course['code'].'">'.
6508
                            Display::returnFontAwesomeIcon('pencil').'</a>';
6509
                    }
6510
                }
6511
            }
6512
        }
6513
6514
        $course_title_url = '';
6515
        if ($course_info['visibility'] != COURSE_VISIBILITY_CLOSED || $course['status'] == COURSEMANAGER) {
6516
            $course_title_url = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/?id_session=0';
6517
            $course_title = Display::url($course_info['title'], $course_title_url);
6518
        } else {
6519
            $course_title = $course_info['title'].' '.Display::tag(
6520
                'span',
6521
                get_lang('CourseClosed'),
6522
                ['class' => 'item_closed']
6523
            );
6524
        }
6525
6526
        // Start displaying the course block itself
6527
        if (api_get_setting('display_coursecode_in_courselist') === 'true') {
6528
            $course_title .= ' ('.$course_info['visual_code'].') ';
6529
        }
6530
        $teachers = '';
6531
        if (api_get_setting('display_teacher_in_courselist') === 'true') {
6532
            $teachers = self::getTeacherListFromCourseCodeToString(
6533
                $course['code'],
6534
                self::USER_SEPARATOR,
6535
                true
6536
            );
6537
        }
6538
        $params['link'] = $course_title_url;
6539
        $params['icon'] = $status_icon;
6540
        $params['title'] = $course_title;
6541
        $params['teachers'] = $teachers;
6542
        if ($course_info['visibility'] != COURSE_VISIBILITY_CLOSED) {
6543
            $params['notifications'] = $show_notification;
6544
        }
6545
6546
        return $params;
6547
    }
6548
6549
    /**
6550
     * Get the course id based on the original id and field name in the extra fields.
6551
     * Returns 0 if course was not found.
6552
     *
6553
     * @param string $original_course_id_value Original course id
6554
     * @param string $original_course_id_name  Original field name
6555
     *
6556
     * @return int Course id
6557
     */
6558
    public static function get_course_id_from_original_id($original_course_id_value, $original_course_id_name)
6559
    {
6560
        $extraFieldValue = new ExtraFieldValue('course');
6561
        $value = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
6562
            $original_course_id_name,
6563
            $original_course_id_value
6564
        );
6565
6566
        if ($value) {
6567
            return $value['item_id'];
6568
        }
6569
6570
        return 0;
6571
    }
6572
6573
    /**
6574
     * Helper function to create a default gradebook (if necessary) upon course creation.
6575
     *
6576
     * @param int    $modelId    The gradebook model ID
6577
     * @param string $courseCode Course code
6578
     */
6579
    public static function createDefaultGradebook($modelId, $courseCode)
6580
    {
6581
        if (api_get_setting('gradebook_enable_grade_model') === 'true') {
6582
            //Create gradebook_category for the new course and add
6583
            // a gradebook model for the course
6584
            if (isset($modelId) &&
6585
                !empty($modelId) &&
6586
                $modelId != '-1'
6587
            ) {
6588
                GradebookUtils::create_default_course_gradebook(
6589
                    $courseCode,
6590
                    $modelId
6591
                );
6592
            }
6593
        }
6594
    }
6595
6596
    /**
6597
     * Helper function to check if there is a course template and, if so, to
6598
     * copy the template as basis for the new course.
6599
     *
6600
     * @param string $courseCode     Course code
6601
     * @param int    $courseTemplate 0 if no course template is defined
6602
     */
6603
    public static function useTemplateAsBasisIfRequired($courseCode, $courseTemplate)
6604
    {
6605
        $template = api_get_setting('course_creation_use_template');
6606
        $teacherCanSelectCourseTemplate = api_get_setting('teacher_can_select_course_template') === 'true';
6607
        $courseTemplate = isset($courseTemplate) ? intval($courseTemplate) : 0;
6608
6609
        $useTemplate = false;
6610
6611
        if ($teacherCanSelectCourseTemplate && $courseTemplate) {
6612
            $useTemplate = true;
6613
            $originCourse = api_get_course_info_by_id($courseTemplate);
6614
        } elseif (!empty($template)) {
6615
            $useTemplate = true;
6616
            $originCourse = api_get_course_info_by_id($template);
6617
        }
6618
6619
        if ($useTemplate) {
6620
            // Include the necessary libraries to generate a course copy
6621
            // Call the course copy object
6622
            $originCourse['official_code'] = $originCourse['code'];
6623
            $cb = new CourseBuilder(null, $originCourse);
6624
            $course = $cb->build(null, $originCourse['code']);
6625
            $cr = new CourseRestorer($course);
6626
            $cr->set_file_option();
6627
            $cr->restore($courseCode);
6628
        }
6629
    }
6630
6631
    /**
6632
     * Helper method to get the number of users defined with a specific course extra field.
6633
     *
6634
     * @param string $name                 Field title
6635
     * @param string $tableExtraFields     The extra fields table name
6636
     * @param string $tableUserFieldValues The user extra field value table name
6637
     *
6638
     * @return int The number of users with this extra field with a specific value
6639
     */
6640
    public static function getCountRegisteredUsersWithCourseExtraField(
6641
        $name,
6642
        $tableExtraFields = '',
6643
        $tableUserFieldValues = ''
6644
    ) {
6645
        if (empty($tableExtraFields)) {
6646
            $tableExtraFields = Database::get_main_table(TABLE_EXTRA_FIELD);
6647
        }
6648
        if (empty($tableUserFieldValues)) {
6649
            $tableUserFieldValues = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
6650
        }
6651
6652
        $registered_users_with_extra_field = 0;
6653
        if (!empty($name) && $name != '-') {
6654
            $extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
6655
            $name = Database::escape_string($name);
6656
            $sql = "SELECT count(v.item_id) as count
6657
                    FROM $tableUserFieldValues v 
6658
                    INNER JOIN $tableExtraFields f
6659
                    ON (f.id = v.field_id)
6660
                    WHERE value = '$name' AND extra_field_type = $extraFieldType";
6661
            $result_count = Database::query($sql);
6662
            if (Database::num_rows($result_count)) {
6663
                $row_count = Database::fetch_array($result_count);
6664
                $registered_users_with_extra_field = $row_count['count'];
6665
            }
6666
        }
6667
6668
        return $registered_users_with_extra_field;
6669
    }
6670
6671
    /**
6672
     * Get the course categories form a course list.
6673
     *
6674
     * @param array $courseList
6675
     *
6676
     * @return array
6677
     */
6678
    public static function getCourseCategoriesFromCourseList(array $courseList)
6679
    {
6680
        $allCategories = array_column($courseList, 'category');
6681
        $categories = array_unique($allCategories);
6682
6683
        sort($categories);
6684
6685
        return $categories;
6686
    }
6687
6688
    /**
6689
     * Display the description button of a course in the course catalog.
6690
     *
6691
     * @param array $course
6692
     *
6693
     * @return string HTML string
6694
     */
6695
    public static function returnDescriptionButton($course)
6696
    {
6697
        if (empty($course)) {
6698
            return '';
6699
        }
6700
6701
        if (api_get_setting('show_courses_descriptions_in_catalog') == 'true') {
6702
            $title = $course['title'];
6703
            $url = api_get_path(WEB_CODE_PATH).'inc/ajax/course_home.ajax.php?a=show_course_information&code='.$course['code'];
6704
            $html = Display::url(
6705
                Display::returnFontAwesomeIcon('info-circle', 'lg'),
6706
                $url,
6707
                [
6708
                    'class' => 'ajax btn btn-light btn-sm',
6709
                    'data-title' => $title,
6710
                    'title' => get_lang('Description'),
6711
                    'aria-label' => get_lang('Description'),
6712
                    'data-size' => 'lg',
6713
                ]
6714
            );
6715
6716
            return $html;
6717
        }
6718
6719
        return '';
6720
    }
6721
6722
    /**
6723
     * @param Course $course
6724
     *
6725
     * @return bool
6726
     */
6727
    public static function hasPicture(Course $course)
6728
    {
6729
        return file_exists(api_get_path(SYS_COURSE_PATH).$course->getDirectory().'/course-pic85x85.png');
6730
    }
6731
6732
    /**
6733
     * Get the course picture path.
6734
     *
6735
     * @param Course $course
6736
     * @param bool   $fullSize
6737
     *
6738
     * @return string|null
6739
     */
6740
    public static function getPicturePath(Course $course, $fullSize = false)
6741
    {
6742
        if (!self::hasPicture($course)) {
6743
            return null;
6744
        }
6745
6746
        if ($fullSize) {
6747
            return api_get_path(WEB_COURSE_PATH).$course->getDirectory().'/course-pic.png';
6748
        }
6749
6750
        return api_get_path(WEB_COURSE_PATH).$course->getDirectory().'/course-pic85x85.png';
6751
    }
6752
6753
    /**
6754
     * @return int
6755
     */
6756
    public static function getCountOpenCourses()
6757
    {
6758
        $visibility = [
6759
            COURSE_VISIBILITY_REGISTERED,
6760
            COURSE_VISIBILITY_OPEN_PLATFORM,
6761
            COURSE_VISIBILITY_OPEN_WORLD,
6762
        ];
6763
6764
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
6765
        $sql = "SELECT count(id) count 
6766
                FROM $table 
6767
                WHERE visibility IN (".implode(',', $visibility).")";
6768
        $result = Database::query($sql);
6769
        $row = Database::fetch_array($result);
6770
6771
        return (int) $row['count'];
6772
    }
6773
6774
    /**
6775
     * @return int
6776
     */
6777
    public static function getCountExercisesFromOpenCourse()
6778
    {
6779
        $visibility = [
6780
            COURSE_VISIBILITY_REGISTERED,
6781
            COURSE_VISIBILITY_OPEN_PLATFORM,
6782
            COURSE_VISIBILITY_OPEN_WORLD,
6783
        ];
6784
6785
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
6786
        $tableExercise = Database::get_course_table(TABLE_QUIZ_TEST);
6787
        $sql = "SELECT count(e.iid) count 
6788
                FROM $table c INNER JOIN $tableExercise e
6789
                ON (c.id = e.c_id)
6790
                WHERE e.active <> -1 AND visibility IN (".implode(',', $visibility).")";
6791
        $result = Database::query($sql);
6792
        $row = Database::fetch_array($result);
6793
6794
        return (int) $row['count'];
6795
    }
6796
6797
    /**
6798
     * @param ToolChain $toolList
6799
     */
6800
    public static function setToolList($toolList)
6801
    {
6802
        self::$toolList = $toolList;
6803
    }
6804
6805
    /**
6806
     * @return ToolChain
6807
     */
6808
    public static function getToolList()
6809
    {
6810
        return self::$toolList;
6811
    }
6812
6813
    /**
6814
     * Check if a specific access-url-related setting is a problem or not.
6815
     *
6816
     * @param array  $_configuration The $_configuration array
6817
     * @param int    $accessUrlId    The access URL ID
6818
     * @param string $param
6819
     * @param string $msgLabel
6820
     *
6821
     * @return bool|string
6822
     */
6823
    private static function checkCreateCourseAccessUrlParam($_configuration, $accessUrlId, $param, $msgLabel)
6824
    {
6825
        if (isset($_configuration[$accessUrlId][$param]) && $_configuration[$accessUrlId][$param] > 0) {
6826
            $num = self::count_courses($accessUrlId);
6827
            if ($num >= $_configuration[$accessUrlId][$param]) {
6828
                api_warn_hosting_contact($param);
6829
6830
                Display::addFlash(
6831
                    Display::return_message($msgLabel)
6832
                );
6833
            }
6834
        }
6835
6836
        return false;
6837
    }
6838
6839
    /**
6840
     * Fill course with all necessary items.
6841
     *
6842
     * @param array $courseInfo Course info array
6843
     * @param array $params     Parameters from the course creation form
6844
     * @param int   $authorId
6845
     */
6846
    private static function fillCourse($courseInfo, $params, $authorId = 0)
6847
    {
6848
        $authorId = empty($authorId) ? api_get_user_id() : (int) $authorId;
6849
6850
        AddCourse::prepare_course_repository($courseInfo['directory']);
6851
        AddCourse::fillCourse(
6852
            $courseInfo,
6853
            $params['exemplary_content'],
6854
            $authorId
6855
        );
6856
6857
        if (isset($params['gradebook_model_id'])) {
6858
            self::createDefaultGradebook(
6859
                $params['gradebook_model_id'],
6860
                $courseInfo['code']
6861
            );
6862
        }
6863
6864
        // If parameter defined, copy the contents from a specific
6865
        // template course into this new course
6866
        if (isset($params['course_template'])) {
6867
            self::useTemplateAsBasisIfRequired(
6868
                $courseInfo['id'],
6869
                $params['course_template']
6870
            );
6871
        }
6872
        $params['course_code'] = $courseInfo['code'];
6873
        $params['item_id'] = $courseInfo['real_id'];
6874
6875
        $courseFieldValue = new ExtraFieldValue('course');
6876
        $courseFieldValue->saveFieldValues($params);
6877
    }
6878
}
6879