Passed
Push — master ( f7e68c...d99f69 )
by Julito
17:56
created

UserManager::update_user_picture()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 7
nc 3
nop 3
dl 0
loc 11
rs 10
c 0
b 0
f 0
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Entity\ExtraField as EntityExtraField;
5
use Chamilo\CoreBundle\Entity\ExtraFieldSavedSearch;
6
use Chamilo\CoreBundle\Entity\SkillRelUser;
7
use Chamilo\CoreBundle\Entity\SkillRelUserComment;
8
use Chamilo\CoreBundle\Entity\User;
9
use Chamilo\CoreBundle\Entity\UserRelUser;
10
use Chamilo\CoreBundle\Framework\Container;
11
use Chamilo\CoreBundle\Repository\GroupRepository;
12
use Chamilo\CoreBundle\Repository\Node\UserRepository;
13
use ChamiloSession as Session;
14
use Symfony\Component\HttpFoundation\File\UploadedFile;
15
16
/**
17
 * Class UserManager.
18
 *
19
 * This library provides functions for user management.
20
 * Include/require it in your code to use its functionality.
21
 *
22
 * @author Julio Montoya <[email protected]> Social network groups added 2009/12
23
 */
24
class UserManager
25
{
26
    // This constants are deprecated use the constants located in ExtraField
27
    public const USER_FIELD_TYPE_TEXT = 1;
28
    public const USER_FIELD_TYPE_TEXTAREA = 2;
29
    public const USER_FIELD_TYPE_RADIO = 3;
30
    public const USER_FIELD_TYPE_SELECT = 4;
31
    public const USER_FIELD_TYPE_SELECT_MULTIPLE = 5;
32
    public const USER_FIELD_TYPE_DATE = 6;
33
    public const USER_FIELD_TYPE_DATETIME = 7;
34
    public const USER_FIELD_TYPE_DOUBLE_SELECT = 8;
35
    public const USER_FIELD_TYPE_DIVIDER = 9;
36
    public const USER_FIELD_TYPE_TAG = 10;
37
    public const USER_FIELD_TYPE_TIMEZONE = 11;
38
    public const USER_FIELD_TYPE_SOCIAL_PROFILE = 12;
39
    public const USER_FIELD_TYPE_FILE = 13;
40
    public const USER_FIELD_TYPE_MOBILE_PHONE_NUMBER = 14;
41
42
    public function __construct()
43
    {
44
    }
45
46
    /**
47
     * Repository is use to query the DB, selects, etc.
48
     *
49
     * @return UserRepository
50
     */
51
    public static function getRepository()
52
    {
53
        return Container::getUserRepository();
54
    }
55
56
    /**
57
     * Validates the password.
58
     *
59
     * @return bool
60
     */
61
    public static function isPasswordValid(User $user, $plainPassword)
62
    {
63
        $hasher = Container::$container->get('security.user_password_hasher');
0 ignored issues
show
Bug introduced by
The method get() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

63
        /** @scrutinizer ignore-call */ 
64
        $hasher = Container::$container->get('security.user_password_hasher');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
64
65
        return $hasher->isPasswordValid($user, $plainPassword);
66
    }
67
68
    /**
69
     * @param int    $userId
70
     * @param string $password
71
     */
72
    public static function updatePassword($userId, $password)
73
    {
74
        $user = api_get_user_entity($userId);
75
        $userManager = self::getRepository();
76
        $user->setPlainPassword($password);
77
        $userManager->updateUser($user, true);
78
    }
79
80
    /**
81
     * Creates a new user for the platform.
82
     *
83
     * @author Hugues Peeters <[email protected]>,
84
     * @author Roan Embrechts <[email protected]>
85
     *
86
     * @param string        $firstName
87
     * @param string        $lastName
88
     * @param int           $status                  (1 for course tutor, 5 for student, 6 for anonymous)
89
     * @param string        $email
90
     * @param string        $loginName
91
     * @param string        $password
92
     * @param string        $official_code           Any official code (optional)
93
     * @param string        $language                User language    (optional)
94
     * @param string        $phone                   Phone number    (optional)
95
     * @param string        $picture_uri             Picture URI        (optional)
96
     * @param string        $authSource              Authentication source (defaults to 'platform', dependind on constant)
97
     * @param string        $expirationDate          Account expiration date (optional, defaults to null)
98
     * @param int           $active                  Whether the account is enabled or disabled by default
99
     * @param int           $hr_dept_id              The department of HR in which the user is registered (defaults to 0)
100
     * @param array         $extra                   Extra fields (labels must be prefixed by "extra_")
101
     * @param string        $encrypt_method          Used if password is given encrypted. Set to an empty string by default
102
     * @param bool          $send_mail
103
     * @param bool          $isAdmin
104
     * @param string        $address
105
     * @param bool          $sendEmailToAllAdmins
106
     * @param FormValidator $form
107
     * @param int           $creatorId
108
     * @param array         $emailTemplate
109
     * @param string        $redirectToURLAfterLogin
110
     *
111
     * @return mixed new user id - if the new user creation succeeds, false otherwise
112
     * @desc The function tries to retrieve user id from the session.
113
     * If it exists, the current user id is the creator id. If a problem arises,
114
     * @assert ('Sam','Gamegie',5,'[email protected]','jo','jo') > 1
115
     * @assert ('Pippin','Took',null,null,'jo','jo') === false
116
     */
117
    public static function create_user(
118
        $firstName,
119
        $lastName,
120
        $status,
121
        $email,
122
        $loginName,
123
        $password,
124
        $official_code = '',
125
        $language = '',
126
        $phone = '',
127
        $picture_uri = '',
128
        $authSource = null,
129
        $expirationDate = null,
130
        $active = 1,
131
        $hr_dept_id = 0,
132
        $extra = [],
133
        $encrypt_method = '',
134
        $send_mail = false,
135
        $isAdmin = false,
136
        $address = '',
137
        $sendEmailToAllAdmins = false,
138
        $form = null,
139
        $creatorId = 0,
140
        $emailTemplate = [],
141
        $redirectToURLAfterLogin = ''
142
    ) {
143
        $authSource = !empty($authSource) ? $authSource : PLATFORM_AUTH_SOURCE;
144
        $creatorId = empty($creatorId) ? api_get_user_id() : 0;
145
146
        if (0 === $creatorId) {
147
            Display::addFlash(
148
                Display::return_message(get_lang('A user creator is needed'))
149
            );
150
151
            return false;
152
        }
153
154
        $creatorInfo = api_get_user_info($creatorId);
155
        $creatorEmail = $creatorInfo['email'] ?? '';
156
157
        // First check if the login exists.
158
        if (!self::is_username_available($loginName)) {
159
            Display::addFlash(
160
                Display::return_message(get_lang('This login is already taken !'))
161
            );
162
163
            return false;
164
        }
165
166
        global $_configuration;
167
        $original_password = $password;
168
169
        $access_url_id = 1;
170
        if (api_get_multiple_access_url()) {
171
            $access_url_id = api_get_current_access_url_id();
172
        } else {
173
            // In some cases, the first access_url ID might be different from 1
174
            // for example when using a DB cluster or hacking the DB manually.
175
            // In this case, we want the first row, not necessarily "1".
176
            $accessUrlRepository = Container::getAccessUrlRepository();
177
            $accessUrl = $accessUrlRepository->getFirstId();
178
            if (!empty($accessUrl[0]) && !empty($accessUrl[0][1])) {
179
                $access_url_id = $accessUrl[0][1];
180
            }
181
        }
182
183
        if (isset($_configuration[$access_url_id]) &&
184
            is_array($_configuration[$access_url_id]) &&
185
            isset($_configuration[$access_url_id]['hosting_limit_users']) &&
186
            $_configuration[$access_url_id]['hosting_limit_users'] > 0) {
187
            $num = self::get_number_of_users();
188
            if ($num >= $_configuration[$access_url_id]['hosting_limit_users']) {
189
                api_warn_hosting_contact('hosting_limit_users');
190
                Display::addFlash(
191
                    Display::return_message(
192
                        get_lang('Sorry, this installation has a users limit, which has now been reached. To increase the number of users allowed on this Chamilo installation, please contact your hosting provider or, if available, upgrade to a superior hosting plan.'),
193
                        'warning'
194
                    )
195
                );
196
197
                return false;
198
            }
199
        }
200
201
        if (1 === $status &&
202
            isset($_configuration[$access_url_id]) &&
203
            is_array($_configuration[$access_url_id]) &&
204
            isset($_configuration[$access_url_id]['hosting_limit_teachers']) &&
205
            $_configuration[$access_url_id]['hosting_limit_teachers'] > 0
206
        ) {
207
            $num = self::get_number_of_users(1);
208
            if ($num >= $_configuration[$access_url_id]['hosting_limit_teachers']) {
209
                Display::addFlash(
210
                    Display::return_message(
211
                        get_lang('Sorry, this installation has a teachers limit, which has now been reached. To increase the number of teachers allowed on this Chamilo installation, please contact your hosting provider or, if available, upgrade to a superior hosting plan.'),
212
                        'warning'
213
                    )
214
                );
215
                api_warn_hosting_contact('hosting_limit_teachers');
216
217
                return false;
218
            }
219
        }
220
221
        if (empty($password)) {
222
            if (PLATFORM_AUTH_SOURCE === $authSource) {
223
                Display::addFlash(
224
                    Display::return_message(
225
                        get_lang('Required field').': '.get_lang(
226
                            'Password'
227
                        ),
228
                        'warning'
229
                    )
230
                );
231
232
                return false;
233
            }
234
235
            // We use the authSource as password.
236
            // The real validation will be by processed by the auth
237
            // source not Chamilo
238
            $password = $authSource;
239
        }
240
241
        // Checking the user language
242
        $languages = api_get_languages();
243
244
        // Default to english
245
        if (!in_array($language, array_keys($languages), true)) {
246
            $language = 'en_US';
247
        }
248
249
        $now = new DateTime();
250
        if (empty($expirationDate) || '0000-00-00 00:00:00' === $expirationDate) {
251
            $expirationDate = null;
252
        // Default expiration date
253
            // if there is a default duration of a valid account then
254
            // we have to change the expiration_date accordingly
255
            // Accept 0000-00-00 00:00:00 as a null value to avoid issues with
256
            // third party code using this method with the previous (pre-1.10)
257
            // value of 0000...
258
            /*if ('' != api_get_setting('account_valid_duration')) {
259
                $expirationDate = new DateTime($currentDate);
260
                $days = (int) api_get_setting('account_valid_duration');
261
                $expirationDate->modify('+'.$days.' day');
262
            }*/
263
        } else {
264
            $expirationDate = api_get_utc_datetime($expirationDate, true, true);
265
        }
266
267
        $repo = Container::getUserRepository();
268
        $user = $repo->createUser()
269
            ->setLastname($lastName)
270
            ->setFirstname($firstName)
271
            ->setUsername($loginName)
272
            ->setStatus($status)
273
            ->setPlainPassword($password)
274
            ->setEmail($email)
275
            ->setOfficialCode($official_code)
276
            ->setCreatorId($creatorId)
277
            ->setAuthSource($authSource)
278
            ->setPhone($phone)
279
            ->setAddress($address)
280
            ->setLocale($language)
281
            ->setRegistrationDate($now)
282
            ->setHrDeptId($hr_dept_id)
283
            ->setActive($active)
284
            ->setEnabled($active)
285
            ->setTimezone(api_get_timezone())
286
        ;
287
288
        if (null !== $expirationDate) {
289
            $user->setExpirationDate($expirationDate);
290
        }
291
292
        // Add user to a group
293
        $statusToGroup = [
294
            COURSEMANAGER => 'TEACHER',
295
            STUDENT => 'STUDENT',
296
            DRH => 'RRHH',
297
            SESSIONADMIN => 'SESSION_ADMIN',
298
            STUDENT_BOSS => 'STUDENT_BOSS',
299
            INVITEE => 'INVITEE',
300
        ];
301
302
        if (isset($statusToGroup[$status])) {
303
            $group = Container::$container->get(GroupRepository::class)->findOneBy(['code' => $statusToGroup[$status]]);
304
            if ($group) {
305
                $user->addGroup($group);
306
            }
307
        }
308
309
        $repo->updateUser($user, true);
310
311
        $userId = $user->getId();
312
313
        if (!empty($userId)) {
314
            if ($isAdmin) {
315
                self::addUserAsAdmin($user);
316
            }
317
318
            if (api_get_multiple_access_url()) {
319
                UrlManager::add_user_to_url($userId, api_get_current_access_url_id());
320
            } else {
321
                //we are adding by default the access_url_user table with access_url_id = 1
322
                UrlManager::add_user_to_url($userId, 1);
323
            }
324
325
            if (is_array($extra) && count($extra) > 0) {
326
                $extra['item_id'] = $userId;
327
                $userFieldValue = new ExtraFieldValue('user');
328
                /* Force saving of extra fields (otherwise, if the current
329
                user is not admin, fields not visible to the user - most
330
                of them - are just ignored) */
331
                $userFieldValue->saveFieldValues(
332
                    $extra,
333
                    true,
334
                    null,
335
                    null,
336
                    null,
337
                    true
338
                );
339
            } else {
340
                // Create notify settings by default
341
                self::update_extra_field_value(
342
                    $userId,
343
                    'mail_notify_invitation',
344
                    '1'
345
                );
346
                self::update_extra_field_value(
347
                    $userId,
348
                    'mail_notify_message',
349
                    '1'
350
                );
351
                self::update_extra_field_value(
352
                    $userId,
353
                    'mail_notify_group_message',
354
                    '1'
355
                );
356
            }
357
358
            self::update_extra_field_value(
359
                $userId,
360
                'already_logged_in',
361
                'false'
362
            );
363
364
            if (!empty($redirectToURLAfterLogin) && api_get_configuration_value('plugin_redirection_enabled')) {
365
                RedirectionPlugin::insert($userId, $redirectToURLAfterLogin);
366
            }
367
368
            if (!empty($email) && $send_mail) {
369
                $recipient_name = api_get_person_name(
370
                    $firstName,
371
                    $lastName,
372
                    null,
373
                    PERSON_NAME_EMAIL_ADDRESS
374
                );
375
                $tpl = Container::getTwig();
376
                $emailSubject = $tpl->render('@ChamiloCore/Mailer/Legacy/subject_registration_platform.html.twig');
377
                $sender_name = api_get_person_name(
378
                    api_get_setting('administratorName'),
379
                    api_get_setting('administratorSurname'),
380
                    null,
381
                    PERSON_NAME_EMAIL_ADDRESS
382
                );
383
                $email_admin = api_get_setting('emailAdministrator');
384
385
                $url = api_get_path(WEB_PATH);
386
                if (api_is_multiple_url_enabled()) {
387
                    $access_url_id = api_get_current_access_url_id();
388
                    if (-1 != $access_url_id) {
389
                        $urlInfo = api_get_access_url($access_url_id);
390
                        if ($urlInfo) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $urlInfo of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
391
                            $url = $urlInfo['url'];
392
                        }
393
                    }
394
                }
395
396
                // variables for the default template
397
                $params = [
398
                    'complete_name' => stripslashes(api_get_person_name($firstName, $lastName)),
399
                    'login_name' => $loginName,
400
                    'original_password' => stripslashes($original_password),
401
                    'mailWebPath' => $url,
402
                    'new_user' => $user,
403
                ];
404
405
                $emailBody = $tpl->render(
406
                    '@ChamiloCore/Mailer/Legacy/content_registration_platform.html.twig',
407
                    $params
408
                );
409
410
                $userInfo = api_get_user_info($userId);
411
                $mailTemplateManager = new MailTemplateManager();
412
                $phoneNumber = $extra['mobile_phone_number'] ?? null;
413
414
                $additionalParameters = [
415
                    'smsType' => SmsPlugin::WELCOME_LOGIN_PASSWORD,
416
                    'userId' => $userId,
417
                    'mobilePhoneNumber' => $phoneNumber,
418
                    'password' => $original_password,
419
                ];
420
421
                $emailBodyTemplate = '';
422
                if (!empty($emailTemplate)) {
423
                    if (isset($emailTemplate['content_registration_platform.tpl']) &&
424
                        !empty($emailTemplate['content_registration_platform.tpl'])
425
                    ) {
426
                        $emailBodyTemplate = $mailTemplateManager->parseTemplate(
427
                            $emailTemplate['content_registration_platform.tpl'],
428
                            $userInfo
429
                        );
430
                    }
431
                }
432
433
                $twoEmail = api_get_configuration_value('send_two_inscription_confirmation_mail');
434
                if (true === $twoEmail) {
435
                    $emailBody = $tpl->render(
436
                        '@ChamiloCore/Mailer/Legacy/new_user_first_email_confirmation.html.twig'
437
                    );
438
439
                    if (!empty($emailBodyTemplate) &&
440
                        isset($emailTemplate['new_user_first_email_confirmation.tpl']) &&
441
                        !empty($emailTemplate['new_user_first_email_confirmation.tpl'])
442
                    ) {
443
                        $emailBody = $mailTemplateManager->parseTemplate(
444
                            $emailTemplate['new_user_first_email_confirmation.tpl'],
445
                            $userInfo
446
                        );
447
                    }
448
449
                    api_mail_html(
450
                        $recipient_name,
451
                        $email,
452
                        $emailSubject,
453
                        $emailBody,
454
                        $sender_name,
455
                        $email_admin,
456
                        null,
457
                        null,
458
                        null,
459
                        $additionalParameters,
460
                        $creatorEmail
461
                    );
462
463
                    $emailBody = $tpl->render('@ChamiloCore/Mailer/Legacy/new_user_second_email_confirmation.html.twig');
464
465
                    if (!empty($emailBodyTemplate) &&
466
                        isset($emailTemplate['new_user_second_email_confirmation.tpl']) &&
467
                        !empty($emailTemplate['new_user_second_email_confirmation.tpl'])
468
                    ) {
469
                        $emailBody = $mailTemplateManager->parseTemplate(
470
                            $emailTemplate['new_user_second_email_confirmation.tpl'],
471
                            $userInfo
472
                        );
473
                    }
474
475
                    api_mail_html(
476
                        $recipient_name,
477
                        $email,
478
                        $emailSubject,
479
                        $emailBody,
480
                        $sender_name,
481
                        $email_admin,
482
                        null,
483
                        null,
484
                        null,
485
                        $additionalParameters,
486
                        $creatorEmail
487
                    );
488
                } else {
489
                    if (!empty($emailBodyTemplate)) {
490
                        $emailBody = $emailBodyTemplate;
491
                    }
492
                    $sendToInbox = api_get_configuration_value('send_inscription_msg_to_inbox');
493
                    if ($sendToInbox) {
494
                        $adminList = self::get_all_administrators();
495
                        $senderId = 1;
496
                        if (!empty($adminList)) {
497
                            $adminInfo = current($adminList);
498
                            $senderId = $adminInfo['user_id'];
499
                        }
500
501
                        MessageManager::send_message_simple(
502
                            $userId,
503
                            $emailSubject,
504
                            $emailBody,
505
                            $senderId
506
                        );
507
                    } else {
508
                        api_mail_html(
509
                            $recipient_name,
510
                            $email,
511
                            $emailSubject,
512
                            $emailBody,
513
                            $sender_name,
514
                            $email_admin,
515
                            null,
516
                            null,
517
                            null,
518
                            $additionalParameters,
519
                            $creatorEmail
520
                        );
521
                    }
522
                }
523
524
                $notification = api_get_configuration_value('send_notification_when_user_added');
525
                if (!empty($notification) && isset($notification['admins']) && is_array($notification['admins'])) {
526
                    foreach ($notification['admins'] as $adminId) {
527
                        $emailSubjectToAdmin = get_lang('The user has been added').': '.
528
                            api_get_person_name($firstName, $lastName);
529
                        MessageManager::send_message_simple($adminId, $emailSubjectToAdmin, $emailBody, $userId);
530
                    }
531
                }
532
533
                if ($sendEmailToAllAdmins) {
534
                    $adminList = self::get_all_administrators();
535
                    // variables for the default template
536
                    $renderer = FormValidator::getDefaultRenderer();
537
                    // Form template
538
                    $elementTemplate = ' {label}: {element} <br />';
539
                    $renderer->setElementTemplate($elementTemplate);
540
                    /** @var FormValidator $form */
541
                    $form->freeze(null, $elementTemplate);
542
                    $form->removeElement('submit');
543
                    $formData = $form->returnForm();
544
                    $url = api_get_path(WEB_CODE_PATH).'admin/user_information.php?user_id='.$user->getId();
545
                    $params = [
546
                        'complete_name' => stripslashes(api_get_person_name($firstName, $lastName)),
547
                        'user_added' => $user,
548
                        'link' => Display::url($url, $url),
549
                        'form' => $formData,
550
                    ];
551
                    $emailBody = $tpl->render(
552
                        '@ChamiloCore/Mailer/Legacy/content_registration_platform_to_admin.html.twig',
553
                        $params
554
                    );
555
556
                    if (!empty($emailBodyTemplate) &&
557
                        isset($emailTemplate['content_registration_platform_to_admin.tpl']) &&
558
                        !empty($emailTemplate['content_registration_platform_to_admin.tpl'])
559
                    ) {
560
                        $emailBody = $mailTemplateManager->parseTemplate(
561
                            $emailTemplate['content_registration_platform_to_admin.tpl'],
562
                            $userInfo
563
                        );
564
                    }
565
566
                    $subject = get_lang('The user has been added');
567
                    foreach ($adminList as $adminId => $data) {
568
                        MessageManager::send_message_simple(
569
                            $adminId,
570
                            $subject,
571
                            $emailBody,
572
                            $userId
573
                        );
574
                    }
575
                }
576
            }
577
            Event::addEvent(LOG_USER_CREATE, LOG_USER_ID, $userId, null, $creatorId);
0 ignored issues
show
Bug introduced by
The method addEvent() does not exist on Event. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

577
            Event::/** @scrutinizer ignore-call */ 
578
                   addEvent(LOG_USER_CREATE, LOG_USER_ID, $userId, null, $creatorId);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
578
        } else {
579
            Display::addFlash(
580
                Display::return_message(
581
                    get_lang('There happened an unknown error. Please contact the platform administrator.')
582
                )
583
            );
584
585
            return false;
586
        }
587
588
        return $userId;
589
    }
590
591
    /**
592
     * Can user be deleted? This function checks whether there's a course
593
     * in which the given user is the
594
     * only course administrator. If that is the case, the user can't be
595
     * deleted because the course would remain without a course admin.
596
     *
597
     * @param int $user_id The user id
598
     *
599
     * @return bool true if user can be deleted
600
     *
601
     * @assert (null) === false
602
     * @assert (-1) === false
603
     * @assert ('abc') === false
604
     */
605
    public static function canDeleteUser($user_id)
606
    {
607
        $deny = api_get_configuration_value('deny_delete_users');
608
609
        if ($deny) {
610
            return false;
611
        }
612
613
        $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
614
        $user_id = (int) $user_id;
615
616
        if (empty($user_id)) {
617
            return false;
618
        }
619
620
        $sql = "SELECT * FROM $table_course_user
621
                WHERE status = 1 AND user_id = ".$user_id;
622
        $res = Database::query($sql);
623
        while ($course = Database::fetch_object($res)) {
624
            $sql = "SELECT id FROM $table_course_user
625
                    WHERE status=1 AND c_id = ".intval($course->c_id);
626
            $res2 = Database::query($sql);
627
            if (1 == Database::num_rows($res2)) {
628
                return false;
629
            }
630
        }
631
632
        return true;
633
    }
634
635
    /**
636
     * Delete a user from the platform, and all its belongings. This is a
637
     * very dangerous function that should only be accessible by
638
     * super-admins. Other roles should only be able to disable a user,
639
     * which removes access to the platform but doesn't delete anything.
640
     *
641
     * @param int The ID of th user to be deleted
642
     *
643
     * @throws Exception
644
     *
645
     * @return bool true if user is successfully deleted, false otherwise
646
     * @assert (null) === false
647
     * @assert ('abc') === false
648
     */
649
    public static function delete_user($user_id)
650
    {
651
        $user_id = (int) $user_id;
652
653
        if (empty($user_id)) {
654
            return false;
655
        }
656
657
        if (!self::canDeleteUser($user_id)) {
658
            return false;
659
        }
660
661
        $usergroup_rel_user = Database::get_main_table(TABLE_USERGROUP_REL_USER);
662
        $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
663
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
664
        $table_session = Database::get_main_table(TABLE_MAIN_SESSION);
665
        $table_admin = Database::get_main_table(TABLE_MAIN_ADMIN);
666
        $table_session_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
667
        $table_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
668
        $table_group = Database::get_course_table(TABLE_GROUP_USER);
669
        $table_work = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
670
671
        $userInfo = api_get_user_info($user_id);
672
        $repository = Container::getUserRepository();
673
674
        /** @var User $user */
675
        $user = $repository->find($user_id);
676
677
        $repository->deleteUser($user);
678
679
        // Unsubscribe the user from all groups in all his courses
680
        $sql = "SELECT c.id
681
                FROM $table_course c
682
                INNER JOIN $table_course_user cu
683
                ON (c.id = cu.c_id)
684
                WHERE
685
                    cu.user_id = '".$user_id."' AND
686
                    relation_type<>".COURSE_RELATION_TYPE_RRHH."
687
                ";
688
689
        $res = Database::query($sql);
690
        while ($course = Database::fetch_object($res)) {
691
            $sql = "DELETE FROM $table_group
692
                    WHERE c_id = {$course->id} AND user_id = $user_id";
693
            Database::query($sql);
694
        }
695
696
        // Unsubscribe user from usergroup_rel_user
697
        $sql = "DELETE FROM $usergroup_rel_user WHERE user_id = '".$user_id."'";
698
        Database::query($sql);
699
700
        // Unsubscribe user from all courses
701
        $sql = "DELETE FROM $table_course_user WHERE user_id = '".$user_id."'";
702
        Database::query($sql);
703
704
        // Unsubscribe user from all courses in sessions
705
        $sql = "DELETE FROM $table_session_course_user WHERE user_id = '".$user_id."'";
706
        Database::query($sql);
707
708
        // If the user was added as a id_coach then set the current admin as coach see BT#
709
        $currentUserId = api_get_user_id();
710
        $sql = "UPDATE $table_session SET id_coach = $currentUserId
711
                WHERE id_coach = '".$user_id."'";
712
        Database::query($sql);
713
714
        $sql = "UPDATE $table_session SET id_coach = $currentUserId
715
                WHERE session_admin_id = '".$user_id."'";
716
        Database::query($sql);
717
718
        // Unsubscribe user from all sessions
719
        $sql = "DELETE FROM $table_session_user
720
                WHERE user_id = '".$user_id."'";
721
        Database::query($sql);
722
723
        if (api_get_configuration_value('plugin_redirection_enabled')) {
724
            RedirectionPlugin::deleteUserRedirection($user_id);
725
        }
726
727
        // Delete user from the admin table
728
        $sql = "DELETE FROM $table_admin WHERE user_id = '".$user_id."'";
729
        Database::query($sql);
730
731
        // Delete the personal agenda-items from this user
732
        $agenda_table = Database::get_main_table(TABLE_PERSONAL_AGENDA);
733
        $sql = "DELETE FROM $agenda_table WHERE user = '".$user_id."'";
734
        Database::query($sql);
735
736
        $gradebook_results_table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_RESULT);
737
        $sql = 'DELETE FROM '.$gradebook_results_table.' WHERE user_id = '.$user_id;
738
        Database::query($sql);
739
740
        $extraFieldValue = new ExtraFieldValue('user');
741
        $extraFieldValue->deleteValuesByItem($user_id);
742
743
        UrlManager::deleteUserFromAllUrls($user_id);
744
        //UrlManager::deleteUserFromAllUrls($user_id);
745
746
        if ('true' === api_get_setting('allow_social_tool')) {
747
            $userGroup = new UserGroupModel();
748
            //Delete user from portal groups
749
            $group_list = $userGroup->get_groups_by_user($user_id);
750
            if (!empty($group_list)) {
751
                foreach ($group_list as $group_id => $data) {
752
                    $userGroup->delete_user_rel_group($user_id, $group_id);
753
                }
754
            }
755
756
            // Delete user from friend lists
757
            //SocialManager::remove_user_rel_user($user_id, true);
758
        }
759
760
        // Removing survey invitation
761
        SurveyManager::delete_all_survey_invitations_by_user($user_id);
762
763
        // Delete students works
764
        /*$sql = "DELETE FROM $table_work WHERE user_id = $user_id ";
765
        Database::query($sql);*/
766
767
        /*$sql = "UPDATE c_item_property SET to_user_id = NULL
768
                WHERE to_user_id = '".$user_id."'";
769
        Database::query($sql);
770
771
        $sql = "UPDATE c_item_property SET insert_user_id = NULL
772
                WHERE insert_user_id = '".$user_id."'";
773
        Database::query($sql);
774
775
        $sql = "UPDATE c_item_property SET lastedit_user_id = NULL
776
                WHERE lastedit_user_id = '".$user_id."'";
777
        Database::query($sql);*/
778
779
        // Skills
780
        $em = Database::getManager();
781
782
        $criteria = ['user' => $user_id];
783
        $skills = $em->getRepository(SkillRelUser::class)->findBy($criteria);
784
        if ($skills) {
785
            /** @var SkillRelUser $skill */
786
            foreach ($skills as $skill) {
787
                $comments = $skill->getComments();
788
                if ($comments) {
789
                    /** @var SkillRelUserComment $comment */
790
                    foreach ($comments as $comment) {
791
                        $em->remove($comment);
792
                    }
793
                }
794
                $em->remove($skill);
795
            }
796
        }
797
798
        // ExtraFieldSavedSearch
799
        $criteria = ['user' => $user_id];
800
        $searchList = $em->getRepository(ExtraFieldSavedSearch::class)->findBy($criteria);
801
        if ($searchList) {
802
            foreach ($searchList as $search) {
803
                $em->remove($search);
804
            }
805
        }
806
807
        $connection = Database::getManager()->getConnection();
808
        $tableExists = $connection->getSchemaManager()->tablesExist(['plugin_bbb_room']);
809
        if ($tableExists) {
810
            // Delete user from database
811
            $sql = "DELETE FROM plugin_bbb_room WHERE participant_id = $user_id";
812
            Database::query($sql);
813
        }
814
815
        // Delete user/ticket relationships :(
816
        $tableExists = $connection->getSchemaManager()->tablesExist(['ticket_ticket']);
817
        if ($tableExists) {
818
            TicketManager::deleteUserFromTicketSystem($user_id);
819
        }
820
821
        $tableExists = $connection->getSchemaManager()->tablesExist(['c_lp_category_user']);
822
        if ($tableExists) {
823
            $sql = "DELETE FROM c_lp_category_user WHERE user_id = $user_id";
824
            Database::query($sql);
825
        }
826
827
        $app_plugin = new AppPlugin();
828
        $app_plugin->performActionsWhenDeletingItem('user', $user_id);
829
830
        // Add event to system log
831
        $authorId = api_get_user_id();
832
833
        Event::addEvent(
834
            LOG_USER_DELETE,
835
            LOG_USER_ID,
836
            $user_id,
837
            api_get_utc_datetime(),
838
            $authorId
839
        );
840
841
        Event::addEvent(
842
            LOG_USER_DELETE,
843
            LOG_USER_OBJECT,
844
            $userInfo,
845
            api_get_utc_datetime(),
846
            $authorId
847
        );
848
849
        return true;
850
    }
851
852
    /**
853
     * Deletes users completely. Can be called either as:
854
     * - UserManager::delete_users(1, 2, 3); or
855
     * - UserManager::delete_users(array(1, 2, 3));.
856
     *
857
     * @param array|int $ids
858
     *
859
     * @return bool True if at least one user was successfuly deleted. False otherwise.
860
     *
861
     * @author Laurent Opprecht
862
     *
863
     * @uses \UserManager::delete_user() to actually delete each user
864
     * @assert (null) === false
865
     * @assert (-1) === false
866
     * @assert (array(-1)) === false
867
     */
868
    public static function delete_users($ids = [])
869
    {
870
        $result = false;
871
        $ids = is_array($ids) ? $ids : func_get_args();
872
        if (!is_array($ids) || 0 == count($ids)) {
873
            return false;
874
        }
875
        $ids = array_map('intval', $ids);
876
        foreach ($ids as $id) {
877
            if (empty($id) || $id < 1) {
878
                continue;
879
            }
880
            $deleted = self::delete_user($id);
881
            $result = $deleted || $result;
882
        }
883
884
        return $result;
885
    }
886
887
    /**
888
     * Disable users. Can be called either as:
889
     * - UserManager::deactivate_users(1, 2, 3);
890
     * - UserManager::deactivate_users(array(1, 2, 3));.
891
     *
892
     * @param array|int $ids
893
     *
894
     * @return bool
895
     *
896
     * @author Laurent Opprecht
897
     * @assert (null) === false
898
     * @assert (array(-1)) === false
899
     */
900
    public static function deactivate_users($ids = [])
901
    {
902
        if (empty($ids)) {
903
            return false;
904
        }
905
906
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
907
908
        $ids = is_array($ids) ? $ids : func_get_args();
909
        $ids = array_map('intval', $ids);
910
        $ids = implode(',', $ids);
911
912
        $sql = "UPDATE $table_user SET active = 0 WHERE id IN ($ids)";
913
        $r = Database::query($sql);
914
        if (false !== $r) {
915
            Event::addEvent(LOG_USER_DISABLE, LOG_USER_ID, $ids);
916
917
            return true;
918
        }
919
920
        return false;
921
    }
922
923
    /**
924
     * Enable users. Can be called either as:
925
     * - UserManager::activate_users(1, 2, 3);
926
     * - UserManager::activate_users(array(1, 2, 3));.
927
     *
928
     * @param array|int IDs of the users to enable
929
     *
930
     * @return bool
931
     *
932
     * @author Laurent Opprecht
933
     * @assert (null) === false
934
     * @assert (array(-1)) === false
935
     */
936
    public static function activate_users($ids = [])
937
    {
938
        if (empty($ids)) {
939
            return false;
940
        }
941
942
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
943
944
        $ids = is_array($ids) ? $ids : func_get_args();
945
        $ids = array_map('intval', $ids);
946
        $ids = implode(',', $ids);
947
948
        $sql = "UPDATE $table_user SET active = 1 WHERE id IN ($ids)";
949
        $r = Database::query($sql);
950
        if (false !== $r) {
951
            Event::addEvent(LOG_USER_ENABLE, LOG_USER_ID, $ids);
952
953
            return true;
954
        }
955
956
        return false;
957
    }
958
959
    /**
960
     * Update user information with all the parameters passed to this function.
961
     *
962
     * @param int    $user_id         The ID of the user to be updated
963
     * @param string $firstname       The user's firstname
964
     * @param string $lastname        The user's lastname
965
     * @param string $username        The user's username (login)
966
     * @param string $password        The user's password
967
     * @param string $auth_source     The authentication source (default: "platform")
968
     * @param string $email           The user's e-mail address
969
     * @param int    $status          The user's status
970
     * @param string $official_code   The user's official code (usually just an internal institutional code)
971
     * @param string $phone           The user's phone number
972
     * @param string $picture_uri     The user's picture URL (internal to the Chamilo directory)
973
     * @param string $expiration_date The date at which this user will be automatically disabled
974
     * @param int    $active          Whether this account needs to be enabled (1) or disabled (0)
975
     * @param int    $creator_id      The user ID of the person who registered this user (optional, defaults to null)
976
     * @param int    $hr_dept_id      The department of HR in which the user is registered (optional, defaults to 0)
977
     * @param array  $extra           Additional fields to add to this user as extra fields (defaults to null)
978
     * @param string $language        The language to which the user account will be set
979
     * @param string $encrypt_method  The cipher method. This parameter is deprecated. It will use the system's default
980
     * @param bool   $send_email      Whether to send an e-mail to the user after the update is complete
981
     * @param int    $reset_password  Method used to reset password (0, 1, 2 or 3 - see usage examples for details)
982
     * @param string $address
983
     * @param array  $emailTemplate
984
     *
985
     * @return bool|int False on error, or the user ID if the user information was updated
986
     * @assert (false, false, false, false, false, false, false, false, false, false, false, false, false) === false
987
     */
988
    public static function update_user(
989
        $user_id,
990
        $firstname,
991
        $lastname,
992
        $username,
993
        $password,
994
        $auth_source,
995
        $email,
996
        $status,
997
        $official_code,
998
        $phone,
999
        $picture_uri,
1000
        $expiration_date,
1001
        $active,
1002
        $creator_id = null,
1003
        $hr_dept_id = 0,
1004
        $extra = null,
1005
        $language = 'en_US',
1006
        $encrypt_method = '',
1007
        $send_email = false,
1008
        $reset_password = 0,
1009
        $address = null,
1010
        $emailTemplate = []
1011
    ) {
1012
        $original_password = $password;
1013
        $user_id = (int) $user_id;
1014
        $creator_id = (int) $creator_id;
1015
1016
        if (empty($user_id)) {
1017
            return false;
1018
        }
1019
1020
        $userManager = self::getRepository();
1021
        $user = api_get_user_entity($user_id);
1022
1023
        if (empty($user)) {
1024
            return false;
1025
        }
1026
1027
        if (0 == $reset_password) {
1028
            $password = null;
1029
            $auth_source = $user->getAuthSource();
1030
        } elseif (1 == $reset_password) {
1031
            $original_password = $password = api_generate_password();
1032
            $auth_source = PLATFORM_AUTH_SOURCE;
1033
        } elseif (2 == $reset_password) {
1034
            $password = $password;
1035
            $auth_source = PLATFORM_AUTH_SOURCE;
1036
        } elseif (3 == $reset_password) {
1037
            $password = $password;
1038
            $auth_source = $auth_source;
1039
        }
1040
1041
        // Checking the user language
1042
        $languages = array_keys(api_get_languages());
1043
        if (!in_array($language, $languages)) {
1044
            $language = api_get_setting('platformLanguage');
1045
        }
1046
1047
        $change_active = 0;
1048
        $isUserActive = $user->getActive();
1049
        if ($isUserActive != $active) {
1050
            $change_active = 1;
1051
        }
1052
1053
        $originalUsername = $user->getUsername();
1054
1055
        // If username is different from original then check if it exists.
1056
        if ($originalUsername !== $username) {
1057
            $available = self::is_username_available($username);
1058
            if (false === $available) {
1059
                return false;
1060
            }
1061
        }
1062
1063
        if (!empty($expiration_date)) {
1064
            $expiration_date = api_get_utc_datetime($expiration_date);
1065
            $expiration_date = new \DateTime(
1066
                $expiration_date,
1067
                new DateTimeZone('UTC')
1068
            );
1069
        }
1070
1071
        $user
1072
            ->setLastname($lastname)
1073
            ->setFirstname($firstname)
1074
            ->setUsername($username)
1075
            ->setStatus($status)
1076
            ->setAuthSource($auth_source)
1077
            ->setLocale($language)
1078
            ->setEmail($email)
1079
            ->setOfficialCode($official_code)
1080
            ->setPhone($phone)
1081
            ->setAddress($address)
1082
            ->setExpirationDate($expiration_date)
1083
            ->setActive($active)
1084
            ->setEnabled($active)
1085
            ->setHrDeptId((int) $hr_dept_id)
1086
        ;
1087
1088
        if (!is_null($password)) {
1089
            $user->setPlainPassword($password);
1090
        }
1091
1092
        $statusToGroup = [
1093
            COURSEMANAGER => 'TEACHER',
1094
            STUDENT => 'STUDENT',
1095
            DRH => 'RRHH',
1096
            SESSIONADMIN => 'SESSION_ADMIN',
1097
            STUDENT_BOSS => 'STUDENT_BOSS',
1098
            INVITEE => 'INVITEE',
1099
        ];
1100
1101
        $group = Container::$container->get(GroupRepository::class)->findOneBy(['code' => $statusToGroup[$status]]);
1102
        if ($group) {
1103
            $user->addGroup($group);
1104
        }
1105
1106
        $userManager->updateUser($user, true);
1107
        Event::addEvent(LOG_USER_UPDATE, LOG_USER_ID, $user_id);
1108
1109
        if (1 == $change_active) {
1110
            if (1 == $active) {
1111
                $event_title = LOG_USER_ENABLE;
1112
            } else {
1113
                $event_title = LOG_USER_DISABLE;
1114
            }
1115
            Event::addEvent($event_title, LOG_USER_ID, $user_id);
1116
        }
1117
1118
        if (is_array($extra) && count($extra) > 0) {
1119
            $res = true;
1120
            foreach ($extra as $fname => $fvalue) {
1121
                $res = $res && self::update_extra_field_value(
1122
                    $user_id,
1123
                    $fname,
1124
                    $fvalue
1125
                );
1126
            }
1127
        }
1128
1129
        if (!empty($email) && $send_email) {
1130
            $recipient_name = api_get_person_name($firstname, $lastname, null, PERSON_NAME_EMAIL_ADDRESS);
1131
            $emailsubject = '['.api_get_setting('siteName').'] '.get_lang('Your registration on').' '.api_get_setting('siteName');
0 ignored issues
show
Bug introduced by
Are you sure api_get_setting('siteName') of type array|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1131
            $emailsubject = '['./** @scrutinizer ignore-type */ api_get_setting('siteName').'] '.get_lang('Your registration on').' '.api_get_setting('siteName');
Loading history...
1132
            $sender_name = api_get_person_name(
1133
                api_get_setting('administratorName'),
1134
                api_get_setting('administratorSurname'),
1135
                null,
1136
                PERSON_NAME_EMAIL_ADDRESS
1137
            );
1138
            $email_admin = api_get_setting('emailAdministrator');
1139
            $url = api_get_path(WEB_PATH);
1140
            if (api_is_multiple_url_enabled()) {
1141
                $access_url_id = api_get_current_access_url_id();
1142
                if (-1 != $access_url_id) {
1143
                    $url = api_get_access_url($access_url_id);
1144
                    $url = $url['url'];
1145
                }
1146
            }
1147
1148
            $tplContent = new Template(
1149
                null,
1150
                false,
1151
                false,
1152
                false,
1153
                false,
1154
                false
1155
            );
1156
            // variables for the default template
1157
            $tplContent->assign('complete_name', stripslashes(api_get_person_name($firstname, $lastname)));
1158
            $tplContent->assign('login_name', $username);
1159
1160
            $originalPassword = '';
1161
            if ($reset_password > 0) {
1162
                $originalPassword = stripslashes($original_password);
1163
            }
1164
            $tplContent->assign('original_password', $originalPassword);
1165
            $tplContent->assign('portal_url', $url);
1166
1167
            $layoutContent = $tplContent->get_template('mail/user_edit_content.tpl');
1168
            $emailBody = $tplContent->fetch($layoutContent);
1169
1170
            $mailTemplateManager = new MailTemplateManager();
1171
1172
            if (!empty($emailTemplate) &&
1173
                isset($emailTemplate['user_edit_content.tpl']) &&
1174
                !empty($emailTemplate['user_edit_content.tpl'])
1175
            ) {
1176
                $userInfo = api_get_user_info($user_id);
1177
                $emailBody = $mailTemplateManager->parseTemplate($emailTemplate['user_edit_content.tpl'], $userInfo);
1178
            }
1179
1180
            $creatorInfo = api_get_user_info($creator_id);
1181
            $creatorEmail = isset($creatorInfo['email']) ? $creatorInfo['email'] : '';
1182
1183
            api_mail_html(
1184
                $recipient_name,
1185
                $email,
1186
                $emailsubject,
1187
                $emailBody,
1188
                $sender_name,
1189
                $email_admin,
1190
                null,
1191
                null,
1192
                null,
1193
                null,
1194
                $creatorEmail
1195
            );
1196
        }
1197
1198
        $cacheAvailable = api_get_configuration_value('apc');
1199
        if (true === $cacheAvailable) {
1200
            $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$user_id;
1201
            if (apcu_exists($apcVar)) {
1202
                apcu_delete($apcVar);
1203
            }
1204
        }
1205
1206
        return $user->getId();
1207
    }
1208
1209
    /**
1210
     * Disables a user.
1211
     *
1212
     * @param int User id
1213
     *
1214
     * @return bool
1215
     *
1216
     * @uses \UserManager::change_active_state() to actually disable the user
1217
     * @assert (0) === false
1218
     */
1219
    public static function disable($user_id)
1220
    {
1221
        if (empty($user_id)) {
1222
            return false;
1223
        }
1224
        self::change_active_state($user_id, 0);
1225
1226
        return true;
1227
    }
1228
1229
    /**
1230
     * Enable a user.
1231
     *
1232
     * @param int User id
1233
     *
1234
     * @return bool
1235
     *
1236
     * @uses \UserManager::change_active_state() to actually disable the user
1237
     * @assert (0) === false
1238
     */
1239
    public static function enable($user_id)
1240
    {
1241
        if (empty($user_id)) {
1242
            return false;
1243
        }
1244
        self::change_active_state($user_id, 1);
1245
1246
        return true;
1247
    }
1248
1249
    /**
1250
     * Returns the user's id based on the original id and field name in
1251
     * the extra fields. Returns 0 if no user was found. This function is
1252
     * mostly useful in the context of a web services-based sinchronization.
1253
     *
1254
     * @param string Original user id
1255
     * @param string Original field name
1256
     *
1257
     * @return int User id
1258
     * @assert ('0','---') === 0
1259
     */
1260
    public static function get_user_id_from_original_id(
1261
        $original_user_id_value,
1262
        $original_user_id_name
1263
    ) {
1264
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
1265
        $t_ufv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1266
        $extraFieldType = EntityExtraField::USER_FIELD_TYPE;
1267
1268
        $original_user_id_name = Database::escape_string($original_user_id_name);
1269
        $original_user_id_value = Database::escape_string($original_user_id_value);
1270
1271
        $sql = "SELECT item_id as user_id
1272
                FROM $t_uf uf
1273
                INNER JOIN $t_ufv ufv
1274
                ON ufv.field_id = uf.id
1275
                WHERE
1276
                    variable = '$original_user_id_name' AND
1277
                    value = '$original_user_id_value' AND
1278
                    extra_field_type = $extraFieldType
1279
                ";
1280
        $res = Database::query($sql);
1281
        $row = Database::fetch_object($res);
1282
        if ($row) {
1283
            return $row->user_id;
1284
        }
1285
1286
        return 0;
1287
    }
1288
1289
    /**
1290
     * Check if a username is available.
1291
     *
1292
     * @param string $username the wanted username
1293
     *
1294
     * @return bool true if the wanted username is available
1295
     * @assert ('') === false
1296
     * @assert ('xyzxyzxyz') === true
1297
     */
1298
    public static function is_username_available($username)
1299
    {
1300
        if (empty($username)) {
1301
            return false;
1302
        }
1303
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
1304
        $sql = "SELECT username FROM $table_user
1305
                WHERE username = '".Database::escape_string($username)."'";
1306
        $res = Database::query($sql);
1307
1308
        return 0 == Database::num_rows($res);
1309
    }
1310
1311
    /**
1312
     * Creates a username using person's names, i.e. creates jmontoya from Julio Montoya.
1313
     *
1314
     * @param string $firstname the first name of the user
1315
     * @param string $lastname  the last name of the user
1316
     *
1317
     * @return string suggests a username that contains only ASCII-letters and digits,
1318
     *                without check for uniqueness within the system
1319
     *
1320
     * @author Julio Montoya Armas
1321
     * @author Ivan Tcholakov, 2009 - rework about internationalization.
1322
     * @assert ('','') === false
1323
     * @assert ('a','b') === 'ab'
1324
     */
1325
    public static function create_username($firstname, $lastname)
1326
    {
1327
        if (empty($firstname) && empty($lastname)) {
1328
            return false;
1329
        }
1330
1331
        // The first letter only.
1332
        $firstname = api_substr(
1333
            preg_replace(USERNAME_PURIFIER, '', $firstname),
1334
            0,
1335
            1
1336
        );
1337
        //Looking for a space in the lastname
1338
        $pos = api_strpos($lastname, ' ');
1339
        if (false !== $pos) {
1340
            $lastname = api_substr($lastname, 0, $pos);
1341
        }
1342
1343
        $lastname = preg_replace(USERNAME_PURIFIER, '', $lastname);
1344
        $username = $firstname.$lastname;
1345
        if (empty($username)) {
1346
            $username = 'user';
1347
        }
1348
1349
        $username = URLify::transliterate($username);
1350
1351
        return strtolower(substr($username, 0, User::USERNAME_MAX_LENGTH - 3));
1352
    }
1353
1354
    /**
1355
     * Creates a unique username, using:
1356
     * 1. the first name and the last name of a user;
1357
     * 2. an already created username but not checked for uniqueness yet.
1358
     *
1359
     * @param string $firstname The first name of a given user. If the second parameter $lastname is NULL, then this
1360
     *                          parameter is treated as username which is to be checked f
1361
     *                          or uniqueness and to be modified when it is necessary.
1362
     * @param string $lastname  the last name of the user
1363
     *
1364
     * @return string Returns a username that contains only ASCII-letters and digits and that is unique in the system.
1365
     *                Note: When the method is called several times with same parameters,
1366
     *                its results look like the following sequence: ivan, ivan2, ivan3, ivan4, ...
1367
     *
1368
     * @author Ivan Tcholakov, 2009
1369
     */
1370
    public static function create_unique_username($firstname, $lastname = null)
1371
    {
1372
        if (is_null($lastname)) {
1373
            // In this case the actual input parameter $firstname should contain ASCII-letters and digits only.
1374
            // For making this method tolerant of mistakes,
1375
            // let us transliterate and purify the suggested input username anyway.
1376
            // So, instead of the sentence $username = $firstname; we place the following:
1377
            $username = strtolower(preg_replace(USERNAME_PURIFIER, '', $firstname));
1378
        } else {
1379
            $username = self::create_username($firstname, $lastname);
1380
        }
1381
        if (!self::is_username_available($username)) {
1382
            $i = 2;
1383
            $temp_username = substr($username, 0, User::USERNAME_MAX_LENGTH - strlen((string) $i)).$i;
1384
            while (!self::is_username_available($temp_username)) {
1385
                $i++;
1386
                $temp_username = substr($username, 0, User::USERNAME_MAX_LENGTH - strlen((string) $i)).$i;
1387
            }
1388
            $username = $temp_username;
1389
        }
1390
1391
        $username = URLify::transliterate($username);
1392
1393
        return $username;
1394
    }
1395
1396
    /**
1397
     * Modifies a given username accordingly to the specification for valid characters and length.
1398
     *
1399
     * @param $username string          The input username
1400
     * @param bool $strict (optional)   When this flag is TRUE, the result is guaranteed for full compliance,
1401
     *                     otherwise compliance may be partial. The default value is FALSE.
1402
     *
1403
     * @return string the resulting purified username
1404
     */
1405
    public static function purify_username($username, $strict = false)
1406
    {
1407
        if ($strict) {
1408
            // 1. Conversion of unacceptable letters (latinian letters with accents for example)
1409
            // into ASCII letters in order they not to be totally removed.
1410
            // 2. Applying the strict purifier.
1411
            // 3. Length limitation.
1412
            $return = 'true' === api_get_setting('login_is_email') ? substr(preg_replace(USERNAME_PURIFIER_MAIL, '', $username), 0, User::USERNAME_MAX_LENGTH) : substr(preg_replace(USERNAME_PURIFIER, '', $username), 0, User::USERNAME_MAX_LENGTH);
1413
            $return = URLify::transliterate($return);
1414
1415
            return $return;
1416
        }
1417
1418
        // 1. Applying the shallow purifier.
1419
        // 2. Length limitation.
1420
        return substr(
1421
            preg_replace(USERNAME_PURIFIER_SHALLOW, '', $username),
1422
            0,
1423
            User::USERNAME_MAX_LENGTH
1424
        );
1425
    }
1426
1427
    /**
1428
     * Checks whether the user id exists in the database.
1429
     *
1430
     * @param int $userId User id
1431
     *
1432
     * @return bool True if user id was found, false otherwise
1433
     */
1434
    public static function is_user_id_valid($userId)
1435
    {
1436
        $resultData = Database::select(
1437
            'COUNT(1) AS count',
1438
            Database::get_main_table(TABLE_MAIN_USER),
1439
            [
1440
                'where' => ['id = ?' => (int) $userId],
1441
            ],
1442
            'first'
1443
        );
1444
1445
        if (false === $resultData) {
1446
            return false;
1447
        }
1448
1449
        return $resultData['count'] > 0;
1450
    }
1451
1452
    /**
1453
     * Checks whether a given username matches to the specification strictly.
1454
     * The empty username is assumed here as invalid.
1455
     * Mostly this function is to be used in the user interface built-in validation routines
1456
     * for providing feedback while usernames are enterd manually.
1457
     *
1458
     * @param string $username the input username
1459
     *
1460
     * @return bool returns TRUE if the username is valid, FALSE otherwise
1461
     */
1462
    public static function is_username_valid($username)
1463
    {
1464
        return !empty($username) && $username == self::purify_username($username, true);
1465
    }
1466
1467
    /**
1468
     * Checks whether a username is empty. If the username contains whitespace characters,
1469
     * such as spaces, tabulators, newlines, etc.,
1470
     * it is assumed as empty too. This function is safe for validation unpurified data (during importing).
1471
     *
1472
     * @param string $username the given username
1473
     *
1474
     * @return bool returns TRUE if length of the username exceeds the limit, FALSE otherwise
1475
     */
1476
    public static function is_username_empty($username)
1477
    {
1478
        return 0 == strlen(self::purify_username($username, false));
1479
    }
1480
1481
    /**
1482
     * Checks whether a username is too long or not.
1483
     *
1484
     * @param string $username the given username, it should contain only ASCII-letters and digits
1485
     *
1486
     * @return bool returns TRUE if length of the username exceeds the limit, FALSE otherwise
1487
     */
1488
    public static function is_username_too_long($username)
1489
    {
1490
        return strlen($username) > User::USERNAME_MAX_LENGTH;
1491
    }
1492
1493
    /**
1494
     * Get the users by ID.
1495
     *
1496
     * @param array  $ids    student ids
1497
     * @param bool   $active
1498
     * @param string $order
1499
     * @param string $limit
1500
     *
1501
     * @return array $result student information
1502
     */
1503
    public static function get_user_list_by_ids($ids = [], $active = null, $order = null, $limit = null)
1504
    {
1505
        if (empty($ids)) {
1506
            return [];
1507
        }
1508
1509
        $ids = is_array($ids) ? $ids : [$ids];
1510
        $ids = array_map('intval', $ids);
1511
        $ids = implode(',', $ids);
1512
1513
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
1514
        $sql = "SELECT * FROM $tbl_user WHERE id IN ($ids)";
1515
        if (!is_null($active)) {
1516
            $sql .= ' AND active='.($active ? '1' : '0');
1517
        }
1518
1519
        if (!is_null($order)) {
1520
            $order = Database::escape_string($order);
1521
            $sql .= ' ORDER BY '.$order;
1522
        }
1523
1524
        if (!is_null($limit)) {
1525
            $limit = Database::escape_string($limit);
1526
            $sql .= ' LIMIT '.$limit;
1527
        }
1528
1529
        $rs = Database::query($sql);
1530
        $result = [];
1531
        while ($row = Database::fetch_array($rs)) {
1532
            $result[] = $row;
1533
        }
1534
1535
        return $result;
1536
    }
1537
1538
    /**
1539
     * Get a list of users of which the given conditions match with an = 'cond'.
1540
     *
1541
     * @param array $conditions a list of condition (example : status=>STUDENT)
1542
     * @param array $order_by   a list of fields on which sort
1543
     *
1544
     * @return array an array with all users of the platform
1545
     *
1546
     * @todo security filter order by
1547
     */
1548
    public static function get_user_list(
1549
        $conditions = [],
1550
        $order_by = [],
1551
        $limit_from = false,
1552
        $limit_to = false,
1553
        $idCampus = null
1554
    ) {
1555
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
1556
        $userUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1557
        $return_array = [];
1558
        $sql = "SELECT user.*, user.id as user_id FROM $user_table user ";
1559
1560
        if (api_is_multiple_url_enabled()) {
1561
            if ($idCampus) {
1562
                $urlId = $idCampus;
1563
            } else {
1564
                $urlId = api_get_current_access_url_id();
1565
            }
1566
            $sql .= " INNER JOIN $userUrlTable url_user
1567
                      ON (user.id = url_user.user_id)
1568
                      WHERE url_user.access_url_id = $urlId";
1569
        } else {
1570
            $sql .= " WHERE 1=1 ";
1571
        }
1572
1573
        if (count($conditions) > 0) {
1574
            foreach ($conditions as $field => $value) {
1575
                $field = Database::escape_string($field);
1576
                $value = Database::escape_string($value);
1577
                $sql .= " AND $field = '$value'";
1578
            }
1579
        }
1580
1581
        if (count($order_by) > 0) {
1582
            $sql .= ' ORDER BY '.Database::escape_string(implode(',', $order_by));
1583
        }
1584
1585
        if (is_numeric($limit_from) && is_numeric($limit_from)) {
1586
            $limit_from = (int) $limit_from;
1587
            $limit_to = (int) $limit_to;
1588
            $sql .= " LIMIT $limit_from, $limit_to";
1589
        }
1590
        $sql_result = Database::query($sql);
1591
        while ($result = Database::fetch_array($sql_result)) {
1592
            $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1593
            $return_array[] = $result;
1594
        }
1595
1596
        return $return_array;
1597
    }
1598
1599
    public static function getUserListExtraConditions(
1600
        $conditions = [],
1601
        $order_by = [],
1602
        $limit_from = false,
1603
        $limit_to = false,
1604
        $idCampus = null,
1605
        $extraConditions = '',
1606
        $getCount = false
1607
    ) {
1608
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
1609
        $userUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1610
        $return_array = [];
1611
        $sql = "SELECT user.*, user.id as user_id FROM $user_table user ";
1612
1613
        if ($getCount) {
1614
            $sql = "SELECT count(user.id) count FROM $user_table user ";
1615
        }
1616
1617
        if (api_is_multiple_url_enabled()) {
1618
            if ($idCampus) {
1619
                $urlId = $idCampus;
1620
            } else {
1621
                $urlId = api_get_current_access_url_id();
1622
            }
1623
            $sql .= " INNER JOIN $userUrlTable url_user
1624
                      ON (user.user_id = url_user.user_id)
1625
                      WHERE url_user.access_url_id = $urlId";
1626
        } else {
1627
            $sql .= " WHERE 1=1 ";
1628
        }
1629
1630
        $sql .= " AND status <> ".ANONYMOUS." ";
1631
1632
        if (count($conditions) > 0) {
1633
            foreach ($conditions as $field => $value) {
1634
                $field = Database::escape_string($field);
1635
                $value = Database::escape_string($value);
1636
                $sql .= " AND $field = '$value'";
1637
            }
1638
        }
1639
1640
        $sql .= str_replace("\'", "'", Database::escape_string($extraConditions));
1641
1642
        if (!empty($order_by) && count($order_by) > 0) {
1643
            $sql .= ' ORDER BY '.Database::escape_string(implode(',', $order_by));
1644
        }
1645
1646
        if (is_numeric($limit_from) && is_numeric($limit_from)) {
1647
            $limit_from = (int) $limit_from;
1648
            $limit_to = (int) $limit_to;
1649
            $sql .= " LIMIT $limit_from, $limit_to";
1650
        }
1651
1652
        $sql_result = Database::query($sql);
1653
1654
        if ($getCount) {
1655
            $result = Database::fetch_array($sql_result);
1656
1657
            return $result['count'];
1658
        }
1659
1660
        while ($result = Database::fetch_array($sql_result)) {
1661
            $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1662
            $return_array[] = $result;
1663
        }
1664
1665
        return $return_array;
1666
    }
1667
1668
    /**
1669
     * Get a list of users of which the given conditions match with a LIKE '%cond%'.
1670
     *
1671
     * @param array  $conditions       a list of condition (exemple : status=>STUDENT)
1672
     * @param array  $order_by         a list of fields on which sort
1673
     * @param bool   $simple_like      Whether we want a simple LIKE 'abc' or a LIKE '%abc%'
1674
     * @param string $condition        Whether we want the filters to be combined by AND or OR
1675
     * @param array  $onlyThisUserList
1676
     *
1677
     * @return array an array with all users of the platform
1678
     *
1679
     * @todo optional course code parameter, optional sorting parameters...
1680
     * @todo security filter order_by
1681
     */
1682
    public static function getUserListLike(
1683
        $conditions = [],
1684
        $order_by = [],
1685
        $simple_like = false,
1686
        $condition = 'AND',
1687
        $onlyThisUserList = []
1688
    ) {
1689
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
1690
        $tblAccessUrlRelUser = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1691
        $return_array = [];
1692
        $sql_query = "SELECT user.id FROM $user_table user ";
1693
1694
        if (api_is_multiple_url_enabled()) {
1695
            $sql_query .= " INNER JOIN $tblAccessUrlRelUser auru ON auru.user_id = user.id ";
1696
        }
1697
1698
        $sql_query .= ' WHERE 1 = 1 ';
1699
        if (count($conditions) > 0) {
1700
            $temp_conditions = [];
1701
            foreach ($conditions as $field => $value) {
1702
                $field = Database::escape_string($field);
1703
                $value = Database::escape_string($value);
1704
                if ($simple_like) {
1705
                    $temp_conditions[] = $field." LIKE '$value%'";
1706
                } else {
1707
                    $temp_conditions[] = $field.' LIKE \'%'.$value.'%\'';
1708
                }
1709
            }
1710
            if (!empty($temp_conditions)) {
1711
                $sql_query .= ' AND '.implode(' '.$condition.' ', $temp_conditions);
1712
            }
1713
1714
            if (api_is_multiple_url_enabled()) {
1715
                $sql_query .= ' AND auru.access_url_id = '.api_get_current_access_url_id();
1716
            }
1717
        } else {
1718
            if (api_is_multiple_url_enabled()) {
1719
                $sql_query .= ' AND auru.access_url_id = '.api_get_current_access_url_id();
1720
            }
1721
        }
1722
1723
        if (!empty($onlyThisUserList)) {
1724
            $onlyThisUserListToString = implode("','", $onlyThisUserList);
1725
            $sql_query .= " AND user.id IN ('$onlyThisUserListToString') ";
1726
        }
1727
1728
        if (count($order_by) > 0) {
1729
            $sql_query .= ' ORDER BY '.Database::escape_string(implode(',', $order_by));
1730
        }
1731
1732
        $sql_result = Database::query($sql_query);
1733
        while ($result = Database::fetch_array($sql_result)) {
1734
            $userInfo = api_get_user_info($result['id']);
1735
            $return_array[] = $userInfo;
1736
        }
1737
1738
        return $return_array;
1739
    }
1740
1741
    /**
1742
     * Gets the current user image.
1743
     *
1744
     * @param string $userId
1745
     * @param int    $size        it can be USER_IMAGE_SIZE_SMALL,
1746
     *                            USER_IMAGE_SIZE_MEDIUM, USER_IMAGE_SIZE_BIG or  USER_IMAGE_SIZE_ORIGINAL
1747
     * @param bool   $addRandomId
1748
     * @param array  $userInfo    to avoid query the DB
1749
     *
1750
     * @todo add gravatar support
1751
     * @todo replace $userId with User entity
1752
     *
1753
     * @return string
1754
     */
1755
    public static function getUserPicture(
1756
        $userId,
1757
        int $size = USER_IMAGE_SIZE_MEDIUM,
1758
        $addRandomId = true,
1759
        $userInfo = []
1760
    ) {
1761
        $user = api_get_user_entity($userId);
1762
        $illustrationRepo = Container::getIllustrationRepository();
1763
1764
        switch ($size) {
1765
            case USER_IMAGE_SIZE_SMALL:
1766
                $width = 32;
1767
                break;
1768
            case USER_IMAGE_SIZE_MEDIUM:
1769
                $width = 64;
1770
                break;
1771
            case USER_IMAGE_SIZE_BIG:
1772
                $width = 128;
1773
                break;
1774
            case USER_IMAGE_SIZE_ORIGINAL:
1775
            default:
1776
                $width = 0;
1777
                break;
1778
        }
1779
1780
        $url = $illustrationRepo->getIllustrationUrl($user);
1781
        $params = [];
1782
        if (!empty($width)) {
1783
            $params['w'] = $width;
1784
        }
1785
1786
        if ($addRandomId) {
1787
            $params['rand'] = uniqid('u_', true);
1788
        }
1789
1790
        $paramsToString = '';
1791
        if (!empty($params)) {
1792
            $paramsToString = '?'.http_build_query($params);
1793
        }
1794
1795
        return $url.$paramsToString;
1796
1797
        /*
1798
        // Make sure userInfo is defined. Otherwise, define it!
1799
        if (empty($userInfo) || !is_array($userInfo) || 0 == count($userInfo)) {
1800
            if (empty($user_id)) {
1801
                return '';
1802
            } else {
1803
                $userInfo = api_get_user_info($user_id);
1804
            }
1805
        }
1806
1807
        $imageWebPath = self::get_user_picture_path_by_id(
1808
            $user_id,
1809
            'web',
1810
            $userInfo
1811
        );
1812
        $pictureWebFile = $imageWebPath['file'];
1813
        $pictureWebDir = $imageWebPath['dir'];
1814
1815
        $pictureAnonymousSize = '128';
1816
        $gravatarSize = 22;
1817
        $realSizeName = 'small_';
1818
1819
        switch ($size) {
1820
            case USER_IMAGE_SIZE_SMALL:
1821
                $pictureAnonymousSize = '32';
1822
                $realSizeName = 'small_';
1823
                $gravatarSize = 32;
1824
                break;
1825
            case USER_IMAGE_SIZE_MEDIUM:
1826
                $pictureAnonymousSize = '64';
1827
                $realSizeName = 'medium_';
1828
                $gravatarSize = 64;
1829
                break;
1830
            case USER_IMAGE_SIZE_ORIGINAL:
1831
                $pictureAnonymousSize = '128';
1832
                $realSizeName = '';
1833
                $gravatarSize = 128;
1834
                break;
1835
            case USER_IMAGE_SIZE_BIG:
1836
                $pictureAnonymousSize = '128';
1837
                $realSizeName = 'big_';
1838
                $gravatarSize = 128;
1839
                break;
1840
        }
1841
1842
        $gravatarEnabled = api_get_setting('gravatar_enabled');
1843
        $anonymousPath = Display::returnIconPath('unknown.png', $pictureAnonymousSize);
1844
        if ('unknown.jpg' == $pictureWebFile || empty($pictureWebFile)) {
1845
            if ('true' === $gravatarEnabled) {
1846
                $file = self::getGravatar(
1847
                    $imageWebPath['email'],
1848
                    $gravatarSize,
1849
                    api_get_setting('gravatar_type')
1850
                );
1851
1852
                if ($addRandomId) {
1853
                    $file .= '&rand='.uniqid();
1854
                }
1855
1856
                return $file;
1857
            }
1858
1859
            return $anonymousPath;
1860
        }
1861
1862
        if ($addRandomId) {
1863
            $picture .= '?rand='.uniqid();
1864
        }
1865
1866
        return $picture;*/
1867
    }
1868
1869
    /**
1870
     * Creates new user photos in various sizes of a user, or deletes user photos.
1871
     * Note: This method relies on configuration setting from main/inc/conf/profile.conf.php.
1872
     *
1873
     * @param int    $user_id the user internal identification number
1874
     * @param string $file    The common file name for the newly created photos.
1875
     *                        It will be checked and modified for compatibility with the file system.
1876
     *                        If full name is provided, path component is ignored.
1877
     *                        If an empty name is provided, then old user photos are deleted only,
1878
     *
1879
     * @see     UserManager::delete_user_picture() as the prefered way for deletion.
1880
     *
1881
     * @param string $source_file    the full system name of the image from which user photos will be created
1882
     * @param string $cropParameters Optional string that contents "x,y,width,height" of a cropped image format
1883
     *
1884
     * @return bool Returns the resulting common file name of created images which usually should be stored in database.
1885
     *              When deletion is requested returns empty string.
1886
     *              In case of internal error or negative validation returns FALSE.
1887
     */
1888
    public static function update_user_picture($userId, UploadedFile $file, string $crop = '')
1889
    {
1890
        if (empty($userId) || empty($file)) {
1891
            return false;
1892
        }
1893
1894
        $repo = Container::getUserRepository();
1895
        $user = $repo->find($userId);
1896
        if ($user) {
1897
            $repoIllustration = Container::getIllustrationRepository();
1898
            $repoIllustration->addIllustration($user, $user, $file, $crop);
1899
        }
1900
    }
1901
1902
    /**
1903
     * Deletes user photos.
1904
     *
1905
     * @param int $userId the user internal identification number
1906
     *
1907
     * @return mixed returns empty string on success, FALSE on error
1908
     */
1909
    public static function deleteUserPicture($userId)
1910
    {
1911
        $repo = Container::getUserRepository();
1912
        $user = $repo->find($userId);
1913
        if ($user) {
1914
            $illustrationRepo = Container::getIllustrationRepository();
1915
            $illustrationRepo->deleteIllustration($user);
1916
        }
1917
    }
1918
1919
    /**
1920
     * Returns an XHTML formatted list of productions for a user, or FALSE if he
1921
     * doesn't have any.
1922
     *
1923
     * If there has been a request to remove a production, the function will return
1924
     * without building the list unless forced to do so by the optional second
1925
     * parameter. This increases performance by avoiding to read through the
1926
     * productions on the filesystem before the removal request has been carried
1927
     * out because they'll have to be re-read afterwards anyway.
1928
     *
1929
     * @param int  $user_id    User id
1930
     * @param bool $force      Optional parameter to force building after a removal request
1931
     * @param bool $showDelete
1932
     *
1933
     * @return string A string containing the XHTML code to display the production list, or FALSE
1934
     */
1935
    public static function build_production_list($user_id, $force = false, $showDelete = false)
1936
    {
1937
        if (!$force && !empty($_POST['remove_production'])) {
1938
            return true; // postpone reading from the filesystem
1939
        }
1940
1941
        $productions = self::get_user_productions($user_id);
1942
1943
        if (empty($productions)) {
1944
            return false;
1945
        }
1946
1947
        return false;
1948
1949
        $production_dir = self::getUserPathById($user_id, 'web');
0 ignored issues
show
Unused Code introduced by
$production_dir = self::...thById($user_id, 'web') is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
1950
        $del_image = Display::returnIconPath('delete.png');
1951
        $add_image = Display::returnIconPath('archive.png');
1952
        $del_text = get_lang('Delete');
1953
        $production_list = '';
1954
        if (count($productions) > 0) {
1955
            $production_list = '<div class="files-production"><ul id="productions">';
1956
            foreach ($productions as $file) {
1957
                $production_list .= '<li>
1958
                    <img src="'.$add_image.'" />
1959
                    <a href="'.$production_dir.urlencode($file).'" target="_blank">
1960
                        '.htmlentities($file).'
1961
                    </a>';
1962
                if ($showDelete) {
1963
                    $production_list .= '&nbsp;&nbsp;
1964
                        <input
1965
                            style="width:16px;"
1966
                            type="image"
1967
                            name="remove_production['.urlencode($file).']"
1968
                            src="'.$del_image.'"
1969
                            alt="'.$del_text.'"
1970
                            title="'.$del_text.' '.htmlentities($file).'"
1971
                            onclick="javascript: return confirmation(\''.htmlentities($file).'\');" /></li>';
1972
                }
1973
            }
1974
            $production_list .= '</ul></div>';
1975
        }
1976
1977
        return $production_list;
1978
    }
1979
1980
    /**
1981
     * Returns an array with the user's productions.
1982
     *
1983
     * @param int $user_id User id
1984
     *
1985
     * @return array An array containing the user's productions
1986
     */
1987
    public static function get_user_productions($user_id)
1988
    {
1989
        return [];
1990
1991
        $production_repository = self::getUserPathById($user_id, 'system');
0 ignored issues
show
Unused Code introduced by
$production_repository =...yId($user_id, 'system') is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
1992
        $productions = [];
1993
1994
        if (is_dir($production_repository)) {
1995
            $handle = opendir($production_repository);
1996
            while ($file = readdir($handle)) {
1997
                if ('.' == $file ||
1998
                    '..' == $file ||
1999
                    '.htaccess' == $file ||
2000
                    is_dir($production_repository.$file)
2001
                ) {
2002
                    // skip current/parent directory and .htaccess
2003
                    continue;
2004
                }
2005
2006
                if (preg_match('/('.$user_id.'|[0-9a-f]{13}|saved)_.+\.(png|jpg|jpeg|gif)$/i', $file)) {
2007
                    // User's photos should not be listed as productions.
2008
                    continue;
2009
                }
2010
                $productions[] = $file;
2011
            }
2012
        }
2013
2014
        return $productions;
2015
    }
2016
2017
    /**
2018
     * Remove a user production.
2019
     *
2020
     * @param int    $user_id    User id
2021
     * @param string $production The production to remove
2022
     *
2023
     * @return bool
2024
     */
2025
    public static function remove_user_production($user_id, $production)
2026
    {
2027
        throw new Exception('remove_user_production');
2028
        /*$production_path = self::get_user_picture_path_by_id($user_id, 'system');
2029
        $production_file = $production_path['dir'].$production;
2030
        if (is_file($production_file)) {
2031
            unlink($production_file);
2032
2033
            return true;
2034
        }
2035
2036
        return false;*/
2037
    }
2038
2039
    /**
2040
     * Update an extra field value for a given user.
2041
     *
2042
     * @param int    $userId   User ID
2043
     * @param string $variable Field variable name
2044
     * @param string $value    Field value
2045
     *
2046
     * @return bool true if field updated, false otherwise
2047
     */
2048
    public static function update_extra_field_value($userId, $variable, $value = '')
2049
    {
2050
        $extraFieldValue = new ExtraFieldValue('user');
2051
        $params = [
2052
            'item_id' => $userId,
2053
            'variable' => $variable,
2054
            'value' => $value,
2055
        ];
2056
2057
        return $extraFieldValue->save($params);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $extraFieldValue->save($params) also could return the type integer which is incompatible with the documented return type boolean.
Loading history...
2058
    }
2059
2060
    /**
2061
     * Get an array of extra fields with field details (type, default value and options).
2062
     *
2063
     * @param    int    Offset (from which row)
2064
     * @param    int    Number of items
2065
     * @param    int    Column on which sorting is made
2066
     * @param    string    Sorting direction
2067
     * @param    bool    Optional. Whether we get all the fields or just the visible ones
0 ignored issues
show
Documentation Bug introduced by
The doc comment Optional. at position 0 could not be parsed: Unknown type name 'Optional.' at position 0 in Optional..
Loading history...
2068
     * @param    int        Optional. Whether we get all the fields with field_filter 1 or 0 or everything
2069
     *
2070
     * @return array Extra fields details (e.g. $list[2]['type'], $list[4]['options'][2]['title']
2071
     */
2072
    public static function get_extra_fields(
2073
        $from = 0,
2074
        $number_of_items = 0,
2075
        $column = 5,
2076
        $direction = 'ASC',
2077
        $all_visibility = true,
2078
        $field_filter = null
2079
    ) {
2080
        $fields = [];
2081
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
2082
        $t_ufo = Database::get_main_table(TABLE_EXTRA_FIELD_OPTIONS);
2083
        $columns = [
2084
            'id',
2085
            'variable',
2086
            'field_type',
2087
            'display_text',
2088
            'default_value',
2089
            'field_order',
2090
            'filter',
2091
        ];
2092
        $column = (int) $column;
2093
        $sort_direction = '';
2094
        if (in_array(strtoupper($direction), ['ASC', 'DESC'])) {
2095
            $sort_direction = strtoupper($direction);
2096
        }
2097
        $extraFieldType = EntityExtraField::USER_FIELD_TYPE;
2098
        $sqlf = "SELECT * FROM $t_uf WHERE extra_field_type = $extraFieldType ";
2099
        if (!$all_visibility) {
2100
            $sqlf .= " AND visible_to_self = 1 ";
2101
        }
2102
        if (!is_null($field_filter)) {
2103
            $field_filter = (int) $field_filter;
2104
            $sqlf .= " AND filter = $field_filter ";
2105
        }
2106
        $sqlf .= " ORDER BY `".$columns[$column]."` $sort_direction ";
2107
        if (0 != $number_of_items) {
2108
            $sqlf .= " LIMIT ".intval($from).','.intval($number_of_items);
2109
        }
2110
        $resf = Database::query($sqlf);
2111
        if (Database::num_rows($resf) > 0) {
2112
            while ($rowf = Database::fetch_array($resf)) {
2113
                $fields[$rowf['id']] = [
2114
                    0 => $rowf['id'],
2115
                    1 => $rowf['variable'],
2116
                    2 => $rowf['field_type'],
2117
                    3 => empty($rowf['display_text']) ? '' : $rowf['display_text'],
2118
                    4 => $rowf['default_value'],
2119
                    5 => $rowf['field_order'],
2120
                    6 => $rowf['visible_to_self'],
2121
                    7 => $rowf['changeable'],
2122
                    8 => $rowf['filter'],
2123
                    9 => [],
2124
                    10 => '<a name="'.$rowf['id'].'"></a>',
2125
                ];
2126
2127
                $sqlo = "SELECT * FROM $t_ufo
2128
                         WHERE field_id = ".$rowf['id']."
2129
                         ORDER BY option_order ASC";
2130
                $reso = Database::query($sqlo);
2131
                if (Database::num_rows($reso) > 0) {
2132
                    while ($rowo = Database::fetch_array($reso)) {
2133
                        $fields[$rowf['id']][9][$rowo['id']] = [
2134
                            0 => $rowo['id'],
2135
                            1 => $rowo['option_value'],
2136
                            2 => empty($rowo['display_text']) ? '' : $rowo['display_text'],
2137
                            3 => $rowo['option_order'],
2138
                        ];
2139
                    }
2140
                }
2141
            }
2142
        }
2143
2144
        return $fields;
2145
    }
2146
2147
    /**
2148
     * Creates a new extra field.
2149
     *
2150
     * @param string $variable    Field's internal variable name
2151
     * @param int    $fieldType   Field's type
2152
     * @param string $displayText Field's language var name
2153
     * @param string $default     Field's default value
2154
     *
2155
     * @return int
2156
     */
2157
    public static function create_extra_field(
2158
        $variable,
2159
        $fieldType,
2160
        $displayText,
2161
        $default
2162
    ) {
2163
        $extraField = new ExtraField('user');
2164
        $params = [
2165
            'variable' => $variable,
2166
            'field_type' => $fieldType,
2167
            'display_text' => $displayText,
2168
            'default_value' => $default,
2169
        ];
2170
2171
        return $extraField->save($params);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $extraField->save($params) also could return the type boolean which is incompatible with the documented return type integer.
Loading history...
2172
    }
2173
2174
    /**
2175
     * Check if a field is available.
2176
     *
2177
     * @param string $variable
2178
     *
2179
     * @return bool
2180
     */
2181
    public static function is_extra_field_available($variable)
2182
    {
2183
        $extraField = new ExtraField('user');
2184
        $data = $extraField->get_handler_field_info_by_field_variable($variable);
2185
2186
        return !empty($data) ? true : false;
2187
    }
2188
2189
    /**
2190
     * Gets user extra fields data.
2191
     *
2192
     * @param    int    User ID
2193
     * @param    bool    Whether to prefix the fields indexes with "extra_" (might be used by formvalidator)
2194
     * @param    bool    Whether to return invisible fields as well
2195
     * @param    bool    Whether to split multiple-selection fields or not
2196
     *
2197
     * @return array Array of fields => value for the given user
2198
     */
2199
    public static function get_extra_user_data(
2200
        $user_id,
2201
        $prefix = false,
2202
        $allVisibility = true,
2203
        $splitMultiple = false,
2204
        $fieldFilter = null
2205
    ) {
2206
        $user_id = (int) $user_id;
2207
2208
        if (empty($user_id)) {
2209
            return [];
2210
        }
2211
2212
        $extra_data = [];
2213
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
2214
        $t_ufv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
2215
        $sql = "SELECT f.id as id, f.variable as fvar, f.field_type as type
2216
                FROM $t_uf f
2217
                WHERE
2218
                    extra_field_type = ".EntityExtraField::USER_FIELD_TYPE."
2219
                ";
2220
        $filter_cond = '';
2221
2222
        if (!$allVisibility) {
2223
            if (isset($fieldFilter)) {
2224
                $fieldFilter = (int) $fieldFilter;
2225
                $filter_cond .= " AND filter = $fieldFilter ";
2226
            }
2227
            $sql .= " AND f.visible_to_self = 1 $filter_cond ";
2228
        } else {
2229
            if (isset($fieldFilter)) {
2230
                $fieldFilter = (int) $fieldFilter;
2231
                $sql .= " AND filter = $fieldFilter ";
2232
            }
2233
        }
2234
2235
        $sql .= ' ORDER BY f.field_order';
2236
2237
        $res = Database::query($sql);
2238
        if (Database::num_rows($res) > 0) {
2239
            while ($row = Database::fetch_array($res)) {
2240
                if (self::USER_FIELD_TYPE_TAG == $row['type']) {
2241
                    $tags = self::get_user_tags_to_string($user_id, $row['id'], false);
2242
                    $extra_data['extra_'.$row['fvar']] = $tags;
2243
                } else {
2244
                    $sqlu = "SELECT value as fval
2245
                            FROM $t_ufv
2246
                            WHERE field_id=".$row['id']." AND item_id = ".$user_id;
2247
                    $resu = Database::query($sqlu);
2248
                    // get default value
2249
                    $sql_df = "SELECT default_value as fval_df FROM $t_uf
2250
                               WHERE id=".$row['id'];
2251
                    $res_df = Database::query($sql_df);
2252
2253
                    if (Database::num_rows($resu) > 0) {
2254
                        $rowu = Database::fetch_array($resu);
2255
                        $fval = $rowu['fval'];
2256
                        if (self::USER_FIELD_TYPE_SELECT_MULTIPLE == $row['type']) {
2257
                            $fval = explode(';', $rowu['fval']);
2258
                        }
2259
                    } else {
2260
                        $row_df = Database::fetch_array($res_df);
2261
                        $fval = $row_df['fval_df'];
2262
                    }
2263
                    // We get here (and fill the $extra_data array) even if there
2264
                    // is no user with data (we fill it with default values)
2265
                    if ($prefix) {
2266
                        if (self::USER_FIELD_TYPE_RADIO == $row['type']) {
2267
                            $extra_data['extra_'.$row['fvar']]['extra_'.$row['fvar']] = $fval;
2268
                        } else {
2269
                            $extra_data['extra_'.$row['fvar']] = $fval;
2270
                        }
2271
                    } else {
2272
                        if (self::USER_FIELD_TYPE_RADIO == $row['type']) {
2273
                            $extra_data['extra_'.$row['fvar']]['extra_'.$row['fvar']] = $fval;
2274
                        } else {
2275
                            $extra_data[$row['fvar']] = $fval;
2276
                        }
2277
                    }
2278
                }
2279
            }
2280
        }
2281
2282
        return $extra_data;
2283
    }
2284
2285
    /** Get extra user data by field.
2286
     * @param int    user ID
2287
     * @param string the internal variable name of the field
2288
     *
2289
     * @return array with extra data info of a user i.e array('field_variable'=>'value');
2290
     */
2291
    public static function get_extra_user_data_by_field(
2292
        $user_id,
2293
        $field_variable,
2294
        $prefix = false,
2295
        $all_visibility = true,
2296
        $splitmultiple = false
2297
    ) {
2298
        $user_id = (int) $user_id;
2299
2300
        if (empty($user_id)) {
2301
            return [];
2302
        }
2303
2304
        $extra_data = [];
2305
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
2306
        $t_ufv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
2307
2308
        $sql = "SELECT f.id as id, f.variable as fvar, f.field_type as type
2309
                FROM $t_uf f
2310
                WHERE f.variable = '$field_variable' ";
2311
2312
        if (!$all_visibility) {
2313
            $sql .= " AND f.visible_to_self = 1 ";
2314
        }
2315
2316
        $sql .= " AND extra_field_type = ".EntityExtraField::USER_FIELD_TYPE;
2317
        $sql .= " ORDER BY f.field_order ";
2318
2319
        $res = Database::query($sql);
2320
        if (Database::num_rows($res) > 0) {
2321
            while ($row = Database::fetch_array($res)) {
2322
                $sqlu = "SELECT value as fval FROM $t_ufv v
2323
                         INNER JOIN $t_uf f
2324
                         ON (v.field_id = f.id)
2325
                         WHERE
2326
                            extra_field_type = ".EntityExtraField::USER_FIELD_TYPE." AND
2327
                            field_id = ".$row['id']." AND
2328
                            item_id = ".$user_id;
2329
                $resu = Database::query($sqlu);
2330
                $fval = '';
2331
                if (Database::num_rows($resu) > 0) {
2332
                    $rowu = Database::fetch_array($resu);
2333
                    $fval = $rowu['fval'];
2334
                    if (self::USER_FIELD_TYPE_SELECT_MULTIPLE == $row['type']) {
2335
                        $fval = explode(';', $rowu['fval']);
2336
                    }
2337
                }
2338
                if ($prefix) {
2339
                    $extra_data['extra_'.$row['fvar']] = $fval;
2340
                } else {
2341
                    $extra_data[$row['fvar']] = $fval;
2342
                }
2343
            }
2344
        }
2345
2346
        return $extra_data;
2347
    }
2348
2349
    /**
2350
     * Get the extra field information for a certain field (the options as well).
2351
     *
2352
     * @param int $variable The name of the field we want to know everything about
2353
     *
2354
     * @return array Array containing all the information about the extra profile field
2355
     *               (first level of array contains field details, then 'options' sub-array contains options details,
2356
     *               as returned by the database)
2357
     *
2358
     * @author Julio Montoya
2359
     *
2360
     * @since v1.8.6
2361
     */
2362
    public static function get_extra_field_information_by_name($variable)
2363
    {
2364
        $extraField = new ExtraField('user');
2365
2366
        return $extraField->get_handler_field_info_by_field_variable($variable);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $extraField->get_...eld_variable($variable) also could return the type boolean which is incompatible with the documented return type array.
Loading history...
2367
    }
2368
2369
    /**
2370
     * Get the extra field information for user tag (the options as well).
2371
     *
2372
     * @param int $variable The name of the field we want to know everything about
2373
     *
2374
     * @return array Array containing all the information about the extra profile field
2375
     *               (first level of array contains field details, then 'options' sub-array contains options details,
2376
     *               as returned by the database)
2377
     *
2378
     * @author José Loguercio
2379
     *
2380
     * @since v1.11.0
2381
     */
2382
    public static function get_extra_field_tags_information_by_name($variable)
2383
    {
2384
        $extraField = new ExtraField('user');
2385
2386
        return $extraField->get_handler_field_info_by_tags($variable);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $extraField->get_...info_by_tags($variable) also could return the type boolean which is incompatible with the documented return type array.
Loading history...
2387
    }
2388
2389
    /**
2390
     * Get all the extra field information of a certain field (also the options).
2391
     *
2392
     * @param int $fieldId the ID of the field we want to know everything of
2393
     *
2394
     * @return array $return containing all th information about the extra profile field
2395
     *
2396
     * @author Julio Montoya
2397
     *
2398
     * @deprecated
2399
     * @since v1.8.6
2400
     */
2401
    public static function get_extra_field_information($fieldId)
2402
    {
2403
        $extraField = new ExtraField('user');
2404
2405
        return $extraField->getFieldInfoByFieldId($fieldId);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $extraField->getF...InfoByFieldId($fieldId) also could return the type boolean which is incompatible with the documented return type array.
Loading history...
2406
    }
2407
2408
    /**
2409
     * Get extra user data by value.
2410
     *
2411
     * @param string $variable       the internal variable name of the field
2412
     * @param string $value          the internal value of the field
2413
     * @param bool   $all_visibility
2414
     *
2415
     * @return array with extra data info of a user i.e array('field_variable'=>'value');
2416
     */
2417
    public static function get_extra_user_data_by_value($variable, $value, $all_visibility = true)
2418
    {
2419
        $extraFieldValue = new ExtraFieldValue('user');
2420
        $extraField = new ExtraField('user');
2421
2422
        $info = $extraField->get_handler_field_info_by_field_variable($variable);
2423
2424
        if (false === $info) {
2425
            return [];
2426
        }
2427
2428
        $data = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
2429
            $variable,
2430
            $value,
2431
            false,
2432
            false,
2433
            true
2434
        );
2435
2436
        $result = [];
2437
        if (!empty($data)) {
2438
            foreach ($data as $item) {
2439
                $result[] = $item['item_id'];
2440
            }
2441
        }
2442
2443
        return $result;
2444
    }
2445
2446
    /**
2447
     * Get extra user data by tags value.
2448
     *
2449
     * @param int    $fieldId the ID of the field we want to know everything of
2450
     * @param string $tag     the tag name for search
2451
     *
2452
     * @return array with extra data info of a user
2453
     *
2454
     * @author José Loguercio
2455
     *
2456
     * @since v1.11.0
2457
     */
2458
    public static function get_extra_user_data_by_tags($fieldId, $tag)
2459
    {
2460
        $extraField = new ExtraField('user');
2461
        $result = $extraField->getAllUserPerTag($fieldId, $tag);
2462
        $array = [];
2463
        foreach ($result as $index => $user) {
2464
            $array[] = $user['user_id'];
2465
        }
2466
2467
        return $array;
2468
    }
2469
2470
    /**
2471
     * Get extra user data by field variable.
2472
     *
2473
     * @param string $variable field variable
2474
     *
2475
     * @return array data
2476
     */
2477
    public static function get_extra_user_data_by_field_variable($variable)
2478
    {
2479
        $extraInfo = self::get_extra_field_information_by_name($variable);
2480
        $field_id = (int) $extraInfo['id'];
2481
2482
        $extraField = new ExtraFieldValue('user');
2483
        $data = $extraField->getValuesByFieldId($field_id);
2484
2485
        if (!empty($data)) {
2486
            foreach ($data as $row) {
2487
                $user_id = $row['item_id'];
2488
                $data[$user_id] = $row;
2489
            }
2490
        }
2491
2492
        return $data;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $data could also return false which is incompatible with the documented return type array. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
2493
    }
2494
2495
    /**
2496
     * Get extra user data tags by field variable.
2497
     *
2498
     * @param string $variable field variable
2499
     *
2500
     * @return array
2501
     */
2502
    public static function get_extra_user_data_for_tags($variable)
2503
    {
2504
        $data = self::get_extra_field_tags_information_by_name($variable);
2505
2506
        return $data;
2507
    }
2508
2509
    /**
2510
     * Gives a list of [session_category][session_id] for the current user.
2511
     *
2512
     * @param int  $user_id
2513
     * @param bool $is_time_over                 whether to fill the first element or not
2514
     *                                           (to give space for courses out of categories)
2515
     * @param bool $ignore_visibility_for_admins optional true if limit time from session is over, false otherwise
2516
     * @param bool $ignoreTimeLimit              ignore time start/end
2517
     * @param bool $getCount
2518
     *
2519
     * @return array list of statuses [session_category][session_id]
2520
     *
2521
     * @todo ensure multiple access urls are managed correctly
2522
     */
2523
    public static function get_sessions_by_category(
2524
        $user_id,
2525
        $is_time_over = true,
2526
        $ignore_visibility_for_admins = false,
2527
        $ignoreTimeLimit = false,
2528
        $getCount = false
2529
    ) {
2530
        $user_id = (int) $user_id;
2531
2532
        if (empty($user_id)) {
2533
            return [];
2534
        }
2535
2536
        $allowOrder = api_get_configuration_value('session_list_order');
2537
        $position = '';
2538
        if ($allowOrder) {
2539
            $position = ', s.position AS position ';
2540
        }
2541
2542
        // Get the list of sessions per user
2543
        $now = new DateTime('now', new DateTimeZone('UTC'));
2544
2545
        // LEFT JOIN is used for session_rel_course_rel_user because an inner
2546
        // join would not catch session-courses where the user is general
2547
        // session coach but which do not have students nor coaches registered
2548
        $dqlSelect = ' COUNT(DISTINCT s.id) ';
2549
2550
        if (!$getCount) {
2551
            $dqlSelect = " DISTINCT
2552
                s.id,
2553
                s.name,
2554
                s.accessStartDate AS access_start_date,
2555
                s.accessEndDate AS access_end_date,
2556
                s.duration,
2557
                sc.id AS session_category_id,
2558
                sc.name AS session_category_name,
2559
                sc.dateStart AS session_category_date_start,
2560
                sc.dateEnd AS session_category_date_end,
2561
                s.coachAccessStartDate AS coach_access_start_date,
2562
                s.coachAccessEndDate AS coach_access_end_date,
2563
                CASE WHEN s.accessEndDate IS NULL THEN 1 ELSE 0 END HIDDEN _isFieldNull
2564
                $position
2565
            ";
2566
        }
2567
2568
        $dql = "SELECT $dqlSelect
2569
                FROM ChamiloCoreBundle:Session AS s
2570
                LEFT JOIN ChamiloCoreBundle:SessionRelCourseRelUser AS scu WITH scu.session = s
2571
                INNER JOIN ChamiloCoreBundle:AccessUrlRelSession AS url WITH url.session = s.id
2572
                LEFT JOIN ChamiloCoreBundle:SessionCategory AS sc WITH s.category = sc ";
2573
2574
        // A single OR operation on scu.user = :user OR s.generalCoach = :user
2575
        // is awfully inefficient for large sets of data (1m25s for 58K
2576
        // sessions, BT#14115) but executing a similar query twice and grouping
2577
        // the results afterwards in PHP takes about 1/1000th of the time
2578
        // (0.1s + 0.0s) for the same set of data, so we do it this way...
2579
        $dqlStudent = $dql." WHERE scu.user = :user AND url.url = :url ";
2580
        $dqlCoach = $dql." WHERE s.generalCoach = :user AND url.url = :url ";
2581
2582
        // Default order
2583
        $order = 'ORDER BY sc.name, s.name';
2584
2585
        // Order by date if showing all sessions
2586
        $showAllSessions = true === api_get_configuration_value('show_all_sessions_on_my_course_page');
2587
        if ($showAllSessions) {
2588
            $order = 'ORDER BY s.accessStartDate';
2589
        }
2590
2591
        // Order by position
2592
        if ($allowOrder) {
2593
            $order = 'ORDER BY s.position';
2594
        }
2595
2596
        // Order by dates according to settings
2597
        $orderBySettings = api_get_configuration_value('my_courses_session_order');
2598
        if (!empty($orderBySettings) && isset($orderBySettings['field']) && isset($orderBySettings['order'])) {
2599
            $field = $orderBySettings['field'];
2600
            $orderSetting = $orderBySettings['order'];
2601
            switch ($field) {
2602
                case 'start_date':
2603
                    $order = " ORDER BY s.accessStartDate $orderSetting";
2604
                    break;
2605
                case 'end_date':
2606
                    $order = " ORDER BY s.accessEndDate $orderSetting ";
2607
                    if ('asc' == $orderSetting) {
2608
                        // Put null values at the end
2609
                        // https://stackoverflow.com/questions/12652034/how-can-i-order-by-null-in-dql
2610
                        $order = ' ORDER BY _isFieldNull asc, s.accessEndDate asc';
2611
                    }
2612
                    break;
2613
                case 'name':
2614
                    $order = " ORDER BY s.name $orderSetting ";
2615
                    break;
2616
            }
2617
        }
2618
2619
        $dqlStudent .= $order;
2620
        $dqlCoach .= $order;
2621
2622
        $accessUrlId = api_get_current_access_url_id();
2623
        $dqlStudent = Database::getManager()
2624
            ->createQuery($dqlStudent)
2625
            ->setParameters(
2626
                ['user' => $user_id, 'url' => $accessUrlId]
2627
            )
2628
        ;
2629
        $dqlCoach = Database::getManager()
2630
            ->createQuery($dqlCoach)
2631
            ->setParameters(
2632
                ['user' => $user_id, 'url' => $accessUrlId]
2633
            )
2634
        ;
2635
2636
        if ($getCount) {
2637
            return $dqlStudent->getSingleScalarResult() + $dqlCoach->getSingleScalarResult();
2638
        }
2639
2640
        $sessionDataStudent = $dqlStudent->getResult();
2641
        $sessionDataCoach = $dqlCoach->getResult();
2642
2643
        $sessionData = [];
2644
        // First fill $sessionData with student sessions
2645
        if (!empty($sessionDataStudent)) {
2646
            foreach ($sessionDataStudent as $row) {
2647
                $sessionData[$row['id']] = $row;
2648
            }
2649
        }
2650
        // Overwrite session data of the user as a student with session data
2651
        // of the user as a coach.
2652
        // There shouldn't be such duplicate rows, but just in case...
2653
        if (!empty($sessionDataCoach)) {
2654
            foreach ($sessionDataCoach as $row) {
2655
                $sessionData[$row['id']] = $row;
2656
            }
2657
        }
2658
2659
        $collapsable = api_get_configuration_value('allow_user_session_collapsable');
2660
        $extraField = new ExtraFieldValue('session');
2661
        $collapsableLink = api_get_path(WEB_PATH).'user_portal.php?action=collapse_session';
2662
2663
        if (empty($sessionData)) {
2664
            return [];
2665
        }
2666
        $categories = [];
2667
        foreach ($sessionData as $row) {
2668
            $session_id = $row['id'];
2669
            $coachList = SessionManager::getCoachesBySession($session_id);
2670
            $categoryStart = $row['session_category_date_start'] ? $row['session_category_date_start']->format('Y-m-d') : '';
2671
            $categoryEnd = $row['session_category_date_end'] ? $row['session_category_date_end']->format('Y-m-d') : '';
2672
            $courseList = self::get_courses_list_by_session($user_id, $session_id);
2673
            $daysLeft = SessionManager::getDayLeftInSession($row, $user_id);
2674
2675
            // User portal filters:
2676
            if (false === $ignoreTimeLimit) {
2677
                if ($is_time_over) {
2678
                    // History
2679
                    if ($row['duration']) {
2680
                        if ($daysLeft >= 0) {
2681
                            continue;
2682
                        }
2683
                    } else {
2684
                        if (empty($row['access_end_date'])) {
2685
                            continue;
2686
                        } else {
2687
                            if ($row['access_end_date'] > $now) {
2688
                                continue;
2689
                            }
2690
                        }
2691
                    }
2692
                } else {
2693
                    // Current user portal
2694
                    $isGeneralCoach = SessionManager::user_is_general_coach($user_id, $row['id']);
2695
                    $isCoachOfCourse = in_array($user_id, $coachList);
2696
2697
                    if (api_is_platform_admin() || $isGeneralCoach || $isCoachOfCourse) {
2698
                        // Teachers can access the session depending in the access_coach date
2699
                    } else {
2700
                        if ($row['duration']) {
2701
                            if ($daysLeft <= 0) {
2702
                                continue;
2703
                            }
2704
                        } else {
2705
                            if (isset($row['access_end_date']) &&
2706
                                !empty($row['access_end_date'])
2707
                            ) {
2708
                                if ($row['access_end_date'] <= $now) {
2709
                                    continue;
2710
                                }
2711
                            }
2712
                        }
2713
                    }
2714
                }
2715
            }
2716
2717
            $categories[$row['session_category_id']]['session_category'] = [
2718
                'id' => $row['session_category_id'],
2719
                'name' => $row['session_category_name'],
2720
                'date_start' => $categoryStart,
2721
                'date_end' => $categoryEnd,
2722
            ];
2723
2724
            $visibility = api_get_session_visibility(
2725
                $session_id,
2726
                null,
2727
                $ignore_visibility_for_admins
2728
            );
2729
2730
            if (SESSION_VISIBLE != $visibility) {
2731
                // Course Coach session visibility.
2732
                $blockedCourseCount = 0;
2733
                $closedVisibilityList = [
2734
                    COURSE_VISIBILITY_CLOSED,
2735
                    COURSE_VISIBILITY_HIDDEN,
2736
                ];
2737
2738
                foreach ($courseList as $course) {
2739
                    // Checking session visibility
2740
                    $sessionCourseVisibility = api_get_session_visibility(
2741
                        $session_id,
2742
                        $course['real_id'],
2743
                        $ignore_visibility_for_admins
2744
                    );
2745
2746
                    $courseIsVisible = !in_array($course['visibility'], $closedVisibilityList);
2747
                    if (false === $courseIsVisible || SESSION_INVISIBLE == $sessionCourseVisibility) {
2748
                        $blockedCourseCount++;
2749
                    }
2750
                }
2751
2752
                // If all courses are blocked then no show in the list.
2753
                if ($blockedCourseCount === count($courseList)) {
2754
                    $visibility = SESSION_INVISIBLE;
2755
                } else {
2756
                    $visibility = $sessionCourseVisibility;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $sessionCourseVisibility does not seem to be defined for all execution paths leading up to this point.
Loading history...
2757
                }
2758
            }
2759
2760
            switch ($visibility) {
2761
                case SESSION_VISIBLE_READ_ONLY:
2762
                case SESSION_VISIBLE:
2763
                case SESSION_AVAILABLE:
2764
                    break;
2765
                case SESSION_INVISIBLE:
2766
                    if (false === $ignore_visibility_for_admins) {
2767
                        continue 2;
2768
                    }
2769
            }
2770
2771
            $collapsed = '';
2772
            $collapsedAction = '';
2773
            if ($collapsable) {
2774
                $collapsableData = SessionManager::getCollapsableData(
2775
                    $user_id,
2776
                    $session_id,
2777
                    $extraField,
2778
                    $collapsableLink
2779
                );
2780
                $collapsed = $collapsableData['collapsed'];
2781
                $collapsedAction = $collapsableData['collapsable_link'];
2782
            }
2783
2784
            $categories[$row['session_category_id']]['sessions'][] = [
2785
                'session_name' => $row['name'],
2786
                'session_id' => $row['id'],
2787
                'access_start_date' => $row['access_start_date'] ? $row['access_start_date']->format('Y-m-d H:i:s') : null,
2788
                'access_end_date' => $row['access_end_date'] ? $row['access_end_date']->format('Y-m-d H:i:s') : null,
2789
                'coach_access_start_date' => $row['coach_access_start_date'] ? $row['coach_access_start_date']->format('Y-m-d H:i:s') : null,
2790
                'coach_access_end_date' => $row['coach_access_end_date'] ? $row['coach_access_end_date']->format('Y-m-d H:i:s') : null,
2791
                'courses' => $courseList,
2792
                'collapsed' => $collapsed,
2793
                'collapsable_link' => $collapsedAction,
2794
                'duration' => $row['duration'],
2795
            ];
2796
        }
2797
2798
        return $categories;
2799
    }
2800
2801
    /**
2802
     * Gives a list of [session_id-course_code] => [status] for the current user.
2803
     *
2804
     * @param int $user_id
2805
     * @param int $sessionLimit
2806
     *
2807
     * @return array list of statuses (session_id-course_code => status)
2808
     */
2809
    public static function get_personal_session_course_list($user_id, $sessionLimit = null)
2810
    {
2811
        // Database Table Definitions
2812
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
2813
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
2814
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2815
        $tbl_session_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
2816
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2817
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2818
        $tblCourseCategory = Database::get_main_table(TABLE_MAIN_CATEGORY);
2819
2820
        $user_id = (int) $user_id;
2821
2822
        if (empty($user_id)) {
2823
            return [];
2824
        }
2825
2826
        // We filter the courses from the URL
2827
        $join_access_url = $where_access_url = '';
2828
        if (api_get_multiple_access_url()) {
2829
            $access_url_id = api_get_current_access_url_id();
2830
            if (-1 != $access_url_id) {
2831
                $tbl_url_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2832
                $join_access_url = "LEFT JOIN $tbl_url_course url_rel_course ON url_rel_course.c_id = course.id";
2833
                $where_access_url = " AND access_url_id = $access_url_id ";
2834
            }
2835
        }
2836
2837
        // Courses in which we subscribed out of any session
2838
2839
        $sql = "SELECT
2840
                    course.code,
2841
                    course_rel_user.status course_rel_status,
2842
                    course_rel_user.sort sort,
2843
                    course_rel_user.user_course_cat user_course_cat
2844
                 FROM $tbl_course_user course_rel_user
2845
                 LEFT JOIN $tbl_course course
2846
                 ON course.id = course_rel_user.c_id
2847
                 $join_access_url
2848
                 WHERE
2849
                    course_rel_user.user_id = '".$user_id."' AND
2850
                    course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH."
2851
                    $where_access_url
2852
                 ORDER BY course_rel_user.sort, course.title ASC";
2853
2854
        $course_list_sql_result = Database::query($sql);
2855
        $personal_course_list = [];
2856
        if (Database::num_rows($course_list_sql_result) > 0) {
2857
            while ($result_row = Database::fetch_array($course_list_sql_result, 'ASSOC')) {
2858
                $course_info = api_get_course_info($result_row['code']);
2859
                $result_row['course_info'] = $course_info;
2860
                $personal_course_list[] = $result_row;
2861
            }
2862
        }
2863
2864
        $coachCourseConditions = '';
2865
        // Getting sessions that are related to a coach in the session_rel_course_rel_user table
2866
        if (api_is_allowed_to_create_course()) {
2867
            $sessionListFromCourseCoach = [];
2868
            $sql = " SELECT DISTINCT session_id
2869
                    FROM $tbl_session_course_user
2870
                    WHERE user_id = $user_id AND status = 2 ";
2871
2872
            $result = Database::query($sql);
2873
            if (Database::num_rows($result)) {
2874
                $result = Database::store_result($result);
2875
                foreach ($result as $session) {
2876
                    $sessionListFromCourseCoach[] = $session['session_id'];
2877
                }
2878
            }
2879
            if (!empty($sessionListFromCourseCoach)) {
2880
                $condition = implode("','", $sessionListFromCourseCoach);
2881
                $coachCourseConditions = " OR ( s.id IN ('$condition'))";
2882
            }
2883
        }
2884
2885
        // Get the list of sessions where the user is subscribed
2886
        // This is divided into two different queries
2887
        $sessions = [];
2888
        $sessionLimitRestriction = '';
2889
        if (!empty($sessionLimit)) {
2890
            $sessionLimit = (int) $sessionLimit;
2891
            $sessionLimitRestriction = "LIMIT $sessionLimit";
2892
        }
2893
2894
        $sql = "SELECT DISTINCT s.id, name, access_start_date, access_end_date
2895
                FROM $tbl_session_user su INNER JOIN $tbl_session s
2896
                ON (s.id = su.session_id)
2897
                WHERE (
2898
                    su.user_id = $user_id AND
2899
                    su.relation_type <> ".SESSION_RELATION_TYPE_RRHH."
2900
                )
2901
                $coachCourseConditions
2902
                ORDER BY access_start_date, access_end_date, name
2903
                $sessionLimitRestriction
2904
        ";
2905
2906
        $result = Database::query($sql);
2907
        if (Database::num_rows($result) > 0) {
2908
            while ($row = Database::fetch_assoc($result)) {
2909
                $sessions[$row['id']] = $row;
2910
            }
2911
        }
2912
2913
        $sql = "SELECT DISTINCT
2914
                id, name, access_start_date, access_end_date
2915
                FROM $tbl_session s
2916
                WHERE (
2917
                    id_coach = $user_id
2918
                )
2919
                $coachCourseConditions
2920
                ORDER BY access_start_date, access_end_date, name";
2921
2922
        $result = Database::query($sql);
2923
        if (Database::num_rows($result) > 0) {
2924
            while ($row = Database::fetch_assoc($result)) {
2925
                if (empty($sessions[$row['id']])) {
2926
                    $sessions[$row['id']] = $row;
2927
                }
2928
            }
2929
        }
2930
2931
        if (api_is_allowed_to_create_course()) {
2932
            foreach ($sessions as $enreg) {
2933
                $session_id = $enreg['id'];
2934
                $session_visibility = api_get_session_visibility($session_id);
2935
2936
                if (SESSION_INVISIBLE == $session_visibility) {
2937
                    continue;
2938
                }
2939
2940
                // This query is horribly slow when more than a few thousand
2941
                // users and just a few sessions to which they are subscribed
2942
                $sql = "SELECT DISTINCT
2943
                        course.code code,
2944
                        course.title i,
2945
                        ".(api_is_western_name_order() ? "CONCAT(user.firstname,' ',user.lastname)" : "CONCAT(user.lastname,' ',user.firstname)")." t,
2946
                        email, course.course_language l,
2947
                        1 sort,
2948
                        course_category.code user_course_cat,
2949
                        access_start_date,
2950
                        access_end_date,
2951
                        session.id as session_id,
2952
                        session.name as session_name
2953
                    FROM $tbl_session_course_user as session_course_user
2954
                    INNER JOIN $tbl_course AS course
2955
                        ON course.id = session_course_user.c_id
2956
                    LEFT JOIN $tblCourseCategory course_category ON course.category_id = course_category.id
2957
                    INNER JOIN $tbl_session as session
2958
                        ON session.id = session_course_user.session_id
2959
                    LEFT JOIN $tbl_user as user
2960
                        ON user.id = session_course_user.user_id OR session.id_coach = user.id
2961
                    WHERE
2962
                        session_course_user.session_id = $session_id AND (
2963
                            (session_course_user.user_id = $user_id AND session_course_user.status = 2)
2964
                            OR session.id_coach = $user_id
2965
                        )
2966
                    ORDER BY i";
2967
                $course_list_sql_result = Database::query($sql);
2968
                while ($result_row = Database::fetch_array($course_list_sql_result, 'ASSOC')) {
2969
                    $result_row['course_info'] = api_get_course_info($result_row['code']);
2970
                    $key = $result_row['session_id'].' - '.$result_row['code'];
2971
                    $personal_course_list[$key] = $result_row;
2972
                }
2973
            }
2974
        }
2975
2976
        foreach ($sessions as $enreg) {
2977
            $session_id = $enreg['id'];
2978
            $session_visibility = api_get_session_visibility($session_id);
2979
            if (SESSION_INVISIBLE == $session_visibility) {
2980
                continue;
2981
            }
2982
2983
            /* This query is very similar to the above query,
2984
               but it will check the session_rel_course_user table if there are courses registered to our user or not */
2985
            $sql = "SELECT DISTINCT
2986
                course.code code,
2987
                course.title i, CONCAT(user.lastname,' ',user.firstname) t,
2988
                email,
2989
                course.course_language l,
2990
                1 sort,
2991
                course_category.code user_course_cat,
2992
                access_start_date,
2993
                access_end_date,
2994
                session.id as session_id,
2995
                session.name as session_name,
2996
                IF((session_course_user.user_id = 3 AND session_course_user.status=2),'2', '5')
2997
            FROM $tbl_session_course_user as session_course_user
2998
            INNER JOIN $tbl_course AS course
2999
            ON course.id = session_course_user.c_id AND session_course_user.session_id = $session_id
3000
            LEFT JOIN $tblCourseCategory course_category ON course.category_id = course_category.id
3001
            INNER JOIN $tbl_session as session
3002
            ON session_course_user.session_id = session.id
3003
            LEFT JOIN $tbl_user as user ON user.id = session_course_user.user_id
3004
            WHERE session_course_user.user_id = $user_id
3005
            ORDER BY i";
3006
3007
            $course_list_sql_result = Database::query($sql);
3008
            while ($result_row = Database::fetch_array($course_list_sql_result, 'ASSOC')) {
3009
                $result_row['course_info'] = api_get_course_info($result_row['code']);
3010
                $key = $result_row['session_id'].' - '.$result_row['code'];
3011
                if (!isset($personal_course_list[$key])) {
3012
                    $personal_course_list[$key] = $result_row;
3013
                }
3014
            }
3015
        }
3016
3017
        return $personal_course_list;
3018
    }
3019
3020
    /**
3021
     * Gives a list of courses for the given user in the given session.
3022
     *
3023
     * @param int $user_id
3024
     * @param int $session_id
3025
     *
3026
     * @return array list of statuses (session_id-course_code => status)
3027
     */
3028
    public static function get_courses_list_by_session($user_id, $session_id)
3029
    {
3030
        // Database Table Definitions
3031
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3032
        $tableCourse = Database::get_main_table(TABLE_MAIN_COURSE);
3033
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3034
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3035
3036
        $user_id = (int) $user_id;
3037
        $session_id = (int) $session_id;
3038
        // We filter the courses from the URL
3039
        $join_access_url = $where_access_url = '';
3040
        if (api_get_multiple_access_url()) {
3041
            $urlId = api_get_current_access_url_id();
3042
            if (-1 != $urlId) {
3043
                $tbl_url_session = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
3044
                $join_access_url = " ,  $tbl_url_session url_rel_session ";
3045
                $where_access_url = " AND access_url_id = $urlId AND url_rel_session.session_id = $session_id ";
3046
            }
3047
        }
3048
3049
        /* This query is very similar to the query below, but it will check the
3050
        session_rel_course_user table if there are courses registered
3051
        to our user or not */
3052
        $sql = "SELECT DISTINCT
3053
                    c.title,
3054
                    c.visibility,
3055
                    c.id as real_id,
3056
                    c.code as course_code,
3057
                    sc.position,
3058
                    c.unsubscribe
3059
                FROM $tbl_session_course_user as scu
3060
                INNER JOIN $tbl_session_course sc
3061
                ON (scu.session_id = sc.session_id AND scu.c_id = sc.c_id)
3062
                INNER JOIN $tableCourse as c
3063
                ON (scu.c_id = c.id)
3064
                $join_access_url
3065
                WHERE
3066
                    scu.user_id = $user_id AND
3067
                    scu.session_id = $session_id
3068
                    $where_access_url
3069
                ORDER BY sc.position ASC";
3070
3071
        $myCourseList = [];
3072
        $courses = [];
3073
        $result = Database::query($sql);
3074
        if (Database::num_rows($result) > 0) {
3075
            while ($result_row = Database::fetch_array($result, 'ASSOC')) {
3076
                $result_row['status'] = 5;
3077
                if (!in_array($result_row['real_id'], $courses)) {
3078
                    $position = $result_row['position'];
3079
                    if (!isset($myCourseList[$position])) {
3080
                        $myCourseList[$position] = $result_row;
3081
                    } else {
3082
                        $myCourseList[] = $result_row;
3083
                    }
3084
                    $courses[] = $result_row['real_id'];
3085
                }
3086
            }
3087
        }
3088
3089
        if (api_is_allowed_to_create_course()) {
3090
            $sql = "SELECT DISTINCT
3091
                        c.title,
3092
                        c.visibility,
3093
                        c.id as real_id,
3094
                        c.code as course_code,
3095
                        sc.position,
3096
                        c.unsubscribe
3097
                    FROM $tbl_session_course_user as scu
3098
                    INNER JOIN $tbl_session as s
3099
                    ON (scu.session_id = s.id)
3100
                    INNER JOIN $tbl_session_course sc
3101
                    ON (scu.session_id = sc.session_id AND scu.c_id = sc.c_id)
3102
                    INNER JOIN $tableCourse as c
3103
                    ON (scu.c_id = c.id)
3104
                    $join_access_url
3105
                    WHERE
3106
                      s.id = $session_id AND
3107
                      (
3108
                        (scu.user_id = $user_id AND scu.status = 2) OR
3109
                        s.id_coach = $user_id
3110
                      )
3111
                    $where_access_url
3112
                    ORDER BY sc.position ASC";
3113
            $result = Database::query($sql);
3114
3115
            if (Database::num_rows($result) > 0) {
3116
                while ($result_row = Database::fetch_array($result, 'ASSOC')) {
3117
                    $result_row['status'] = 2;
3118
                    if (!in_array($result_row['real_id'], $courses)) {
3119
                        $position = $result_row['position'];
3120
                        if (!isset($myCourseList[$position])) {
3121
                            $myCourseList[$position] = $result_row;
3122
                        } else {
3123
                            $myCourseList[] = $result_row;
3124
                        }
3125
                        $courses[] = $result_row['real_id'];
3126
                    }
3127
                }
3128
            }
3129
        }
3130
3131
        if (api_is_drh()) {
3132
            $sessionList = SessionManager::get_sessions_followed_by_drh($user_id);
3133
            $sessionList = array_keys($sessionList);
3134
            if (in_array($session_id, $sessionList)) {
3135
                $courseList = SessionManager::get_course_list_by_session_id($session_id);
3136
                if (!empty($courseList)) {
3137
                    foreach ($courseList as $course) {
3138
                        if (!in_array($course['id'], $courses)) {
3139
                            $position = $course['position'];
3140
                            if (!isset($myCourseList[$position])) {
3141
                                $myCourseList[$position] = $course;
3142
                            } else {
3143
                                $myCourseList[] = $course;
3144
                            }
3145
                        }
3146
                    }
3147
                }
3148
            }
3149
        } else {
3150
            //check if user is general coach for this session
3151
            $sessionInfo = api_get_session_info($session_id);
3152
            if ($sessionInfo['id_coach'] == $user_id) {
3153
                $courseList = SessionManager::get_course_list_by_session_id($session_id);
3154
                if (!empty($courseList)) {
3155
                    foreach ($courseList as $course) {
3156
                        if (!in_array($course['id'], $courses)) {
3157
                            $position = $course['position'];
3158
                            if (!isset($myCourseList[$position])) {
3159
                                $myCourseList[$position] = $course;
3160
                            } else {
3161
                                $myCourseList[] = $course;
3162
                            }
3163
                        }
3164
                    }
3165
                }
3166
            }
3167
        }
3168
3169
        if (!empty($myCourseList)) {
3170
            ksort($myCourseList);
3171
            $checkPosition = array_filter(array_column($myCourseList, 'position'));
3172
            if (empty($checkPosition)) {
3173
                // The session course list doesn't have any position,
3174
                // then order the course list by course code
3175
                $list = array_column($myCourseList, 'course_code');
3176
                array_multisort($myCourseList, SORT_ASC, $list);
0 ignored issues
show
Bug introduced by
SORT_ASC cannot be passed to array_multisort() as the parameter $rest expects a reference. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

3176
                array_multisort($myCourseList, /** @scrutinizer ignore-type */ SORT_ASC, $list);
Loading history...
3177
            }
3178
        }
3179
3180
        return $myCourseList;
3181
    }
3182
3183
    /**
3184
     * Get user id from a username.
3185
     *
3186
     * @param string $username
3187
     *
3188
     * @return int User ID (or false if not found)
3189
     */
3190
    public static function get_user_id_from_username($username)
3191
    {
3192
        if (empty($username)) {
3193
            return false;
3194
        }
3195
        $username = trim($username);
3196
        $username = Database::escape_string($username);
3197
        $t_user = Database::get_main_table(TABLE_MAIN_USER);
3198
        $sql = "SELECT id FROM $t_user WHERE username = '$username'";
3199
        $res = Database::query($sql);
3200
3201
        if (false === $res) {
3202
            return false;
3203
        }
3204
        if (1 !== Database::num_rows($res)) {
3205
            return false;
3206
        }
3207
        $row = Database::fetch_array($res);
3208
3209
        return $row['id'];
3210
    }
3211
3212
    /**
3213
     * Get the users files upload from his share_folder.
3214
     *
3215
     * @param string $user_id      User ID
3216
     * @param string $course       course directory
3217
     * @param string $resourceType resource type: images, all
3218
     *
3219
     * @return string
3220
     */
3221
    /*public static function get_user_upload_files_by_course(
3222
        $user_id,
3223
        $course,
3224
        $resourceType = 'all'
3225
    ) {
3226
        $return = '';
3227
        $user_id = (int) $user_id;
3228
3229
        if (!empty($user_id) && !empty($course)) {
3230
            $path = api_get_path(SYS_COURSE_PATH).$course.'/document/shared_folder/sf_user_'.$user_id.'/';
3231
            $web_path = api_get_path(WEB_COURSE_PATH).$course.'/document/shared_folder/sf_user_'.$user_id.'/';
3232
            $file_list = [];
3233
3234
            if (is_dir($path)) {
3235
                $handle = opendir($path);
3236
                while ($file = readdir($handle)) {
3237
                    if ('.' == $file || '..' == $file || '.htaccess' == $file || is_dir($path.$file)) {
3238
                        continue; // skip current/parent directory and .htaccess
3239
                    }
3240
                    $file_list[] = $file;
3241
                }
3242
                if (count($file_list) > 0) {
3243
                    $return = "<h4>$course</h4>";
3244
                    $return .= '<ul class="thumbnails">';
3245
                }
3246
                $extensionList = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'tif'];
3247
                foreach ($file_list as $file) {
3248
                    if ('all' == $resourceType) {
3249
                        $return .= '<li>
3250
                            <a href="'.$web_path.urlencode($file).'" target="_blank">'.htmlentities($file).'</a></li>';
3251
                    } elseif ('images' == $resourceType) {
3252
                        //get extension
3253
                        $ext = explode('.', $file);
3254
                        if (isset($ext[1]) && in_array($ext[1], $extensionList)) {
3255
                            $return .= '<li class="span2">
3256
                                            <a class="thumbnail" href="'.$web_path.urlencode($file).'" target="_blank">
3257
                                                <img src="'.$web_path.urlencode($file).'" >
3258
                                            </a>
3259
                                        </li>';
3260
                        }
3261
                    }
3262
                }
3263
                if (count($file_list) > 0) {
3264
                    $return .= '</ul>';
3265
                }
3266
            }
3267
        }
3268
3269
        return $return;
3270
    }*/
3271
3272
    /**
3273
     * Gets the API key (or keys) and return them into an array.
3274
     *
3275
     * @param int     Optional user id (defaults to the result of api_get_user_id())
3276
     * @param string $api_service
3277
     *
3278
     * @return mixed Non-indexed array containing the list of API keys for this user, or FALSE on error
3279
     */
3280
    public static function get_api_keys($user_id = null, $api_service = 'dokeos')
3281
    {
3282
        if ($user_id != strval(intval($user_id))) {
3283
            return false;
3284
        }
3285
        if (empty($user_id)) {
3286
            $user_id = api_get_user_id();
3287
        }
3288
        if (false === $user_id) {
3289
            return false;
3290
        }
3291
        $service_name = Database::escape_string($api_service);
3292
        if (false === is_string($service_name)) {
3293
            return false;
3294
        }
3295
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3296
        $sql = "SELECT * FROM $t_api WHERE user_id = $user_id AND api_service='$api_service';";
3297
        $res = Database::query($sql);
3298
        if (false === $res) {
3299
            return false;
3300
        } //error during query
3301
        $num = Database::num_rows($res);
3302
        if (0 == $num) {
3303
            return false;
3304
        }
3305
        $list = [];
3306
        while ($row = Database::fetch_array($res)) {
3307
            $list[$row['id']] = $row['api_key'];
3308
        }
3309
3310
        return $list;
3311
    }
3312
3313
    /**
3314
     * Adds a new API key to the users' account.
3315
     *
3316
     * @param   int     Optional user ID (defaults to the results of api_get_user_id())
3317
     * @param string $api_service
3318
     *
3319
     * @return bool True on success, false on failure
3320
     */
3321
    public static function add_api_key($user_id = null, $api_service = 'dokeos')
3322
    {
3323
        if ($user_id != strval(intval($user_id))) {
3324
            return false;
3325
        }
3326
        if (empty($user_id)) {
3327
            $user_id = api_get_user_id();
3328
        }
3329
        if (false === $user_id) {
3330
            return false;
3331
        }
3332
        $service_name = Database::escape_string($api_service);
3333
        if (false === is_string($service_name)) {
3334
            return false;
3335
        }
3336
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3337
        $md5 = md5((time() + ($user_id * 5)) - rand(10000, 10000)); //generate some kind of random key
3338
        $sql = "INSERT INTO $t_api (user_id, api_key,api_service) VALUES ($user_id,'$md5','$service_name')";
3339
        $res = Database::query($sql);
3340
        if (false === $res) {
3341
            return false;
3342
        } //error during query
3343
        $num = Database::insert_id();
3344
3345
        return 0 == $num ? false : $num;
0 ignored issues
show
Bug Best Practice introduced by
The expression return 0 == $num ? false : $num also could return the type string which is incompatible with the documented return type boolean.
Loading history...
3346
    }
3347
3348
    /**
3349
     * Deletes an API key from the user's account.
3350
     *
3351
     * @param   int     API key's internal ID
3352
     *
3353
     * @return bool True on success, false on failure
3354
     */
3355
    public static function delete_api_key($key_id)
3356
    {
3357
        if ($key_id != strval(intval($key_id))) {
3358
            return false;
3359
        }
3360
        if (false === $key_id) {
3361
            return false;
3362
        }
3363
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3364
        $sql = "SELECT * FROM $t_api WHERE id = ".$key_id;
3365
        $res = Database::query($sql);
3366
        if (false === $res) {
3367
            return false;
3368
        } //error during query
3369
        $num = Database::num_rows($res);
3370
        if (1 !== $num) {
3371
            return false;
3372
        }
3373
        $sql = "DELETE FROM $t_api WHERE id = ".$key_id;
3374
        $res = Database::query($sql);
3375
        if (false === $res) {
3376
            return false;
3377
        } //error during query
3378
3379
        return true;
3380
    }
3381
3382
    /**
3383
     * Regenerate an API key from the user's account.
3384
     *
3385
     * @param   int     user ID (defaults to the results of api_get_user_id())
3386
     * @param   string  API key's internal ID
3387
     *
3388
     * @return int num
3389
     */
3390
    public static function update_api_key($user_id, $api_service)
3391
    {
3392
        if ($user_id != strval(intval($user_id))) {
3393
            return false;
3394
        }
3395
        if (false === $user_id) {
3396
            return false;
3397
        }
3398
        $service_name = Database::escape_string($api_service);
3399
        if (false === is_string($service_name)) {
3400
            return false;
3401
        }
3402
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3403
        $sql = "SELECT id FROM $t_api
3404
                WHERE user_id=".$user_id." AND api_service='".$api_service."'";
3405
        $res = Database::query($sql);
3406
        $num = Database::num_rows($res);
3407
        if (1 == $num) {
3408
            $id_key = Database::fetch_array($res, 'ASSOC');
3409
            self::delete_api_key($id_key['id']);
3410
            $num = self::add_api_key($user_id, $api_service);
3411
        } elseif (0 == $num) {
3412
            $num = self::add_api_key($user_id, $api_service);
3413
        }
3414
3415
        return $num;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $num also could return the type boolean which is incompatible with the documented return type integer.
Loading history...
3416
    }
3417
3418
    /**
3419
     * @param   int     user ID (defaults to the results of api_get_user_id())
3420
     * @param   string    API key's internal ID
3421
     *
3422
     * @return int row ID, or return false if not found
3423
     */
3424
    public static function get_api_key_id($user_id, $api_service)
3425
    {
3426
        if ($user_id != strval(intval($user_id))) {
3427
            return false;
3428
        }
3429
        if (false === $user_id) {
3430
            return false;
3431
        }
3432
        if (empty($api_service)) {
3433
            return false;
3434
        }
3435
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3436
        $api_service = Database::escape_string($api_service);
3437
        $sql = "SELECT id FROM $t_api
3438
                WHERE user_id=".$user_id." AND api_service='".$api_service."'";
3439
        $res = Database::query($sql);
3440
        if (Database::num_rows($res) < 1) {
3441
            return false;
3442
        }
3443
        $row = Database::fetch_array($res, 'ASSOC');
3444
3445
        return $row['id'];
3446
    }
3447
3448
    /**
3449
     * Checks if a user_id is platform admin.
3450
     *
3451
     * @param   int user ID
3452
     *
3453
     * @return bool True if is admin, false otherwise
3454
     *
3455
     * @see main_api.lib.php::api_is_platform_admin() for a context-based check
3456
     */
3457
    public static function is_admin($user_id)
3458
    {
3459
        $user_id = (int) $user_id;
3460
        if (empty($user_id)) {
3461
            return false;
3462
        }
3463
        $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
3464
        $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
3465
        $res = Database::query($sql);
3466
3467
        return 1 === Database::num_rows($res);
3468
    }
3469
3470
    /**
3471
     * Get the total count of users.
3472
     *
3473
     * @param int $status        Status of users to be counted
3474
     * @param int $access_url_id Access URL ID (optional)
3475
     * @param int $active
3476
     *
3477
     * @return mixed Number of users or false on error
3478
     */
3479
    public static function get_number_of_users($status = 0, $access_url_id = 1, $active = null)
3480
    {
3481
        $t_u = Database::get_main_table(TABLE_MAIN_USER);
3482
        $t_a = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3483
3484
        if (api_is_multiple_url_enabled()) {
3485
            $sql = "SELECT count(u.id)
3486
                    FROM $t_u u
3487
                    INNER JOIN $t_a url_user
3488
                    ON (u.id = url_user.user_id)
3489
                    WHERE url_user.access_url_id = $access_url_id
3490
            ";
3491
        } else {
3492
            $sql = "SELECT count(u.id)
3493
                    FROM $t_u u
3494
                    WHERE 1 = 1 ";
3495
        }
3496
3497
        $status = (int) $status;
3498
        if (!empty($status) && $status > 0) {
3499
            $sql .= " AND u.status = $status ";
3500
        }
3501
3502
        if (null !== $active) {
3503
            $active = (int) $active;
3504
            $sql .= " AND u.active = $active ";
3505
        }
3506
3507
        $res = Database::query($sql);
3508
        if (1 === Database::num_rows($res)) {
3509
            return (int) Database::result($res, 0, 0);
3510
        }
3511
3512
        return false;
3513
    }
3514
3515
    /**
3516
     * Gets the tags of a specific field_id
3517
     * USER TAGS.
3518
     *
3519
     * Instructions to create a new user tag by Julio Montoya <[email protected]>
3520
     *
3521
     * 1. Create a new extra field in main/admin/user_fields.php with the "TAG" field type make it available and visible.
3522
     *    Called it "books" for example.
3523
     * 2. Go to profile main/auth/profile.php There you will see a special input (facebook style) that will show suggestions of tags.
3524
     * 3. All the tags are registered in the user_tag table and the relationship between user and tags is in the user_rel_tag table
3525
     * 4. Tags are independent this means that tags can't be shared between tags + book + hobbies.
3526
     * 5. Test and enjoy.
3527
     *
3528
     * @param string $tag
3529
     * @param int    $field_id      field_id
3530
     * @param string $return_format how we are going to result value in array or in a string (json)
3531
     * @param $limit
3532
     *
3533
     * @return mixed
3534
     */
3535
    public static function get_tags($tag, $field_id, $return_format = 'json', $limit = 10)
3536
    {
3537
        // database table definition
3538
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3539
        $field_id = (int) $field_id;
3540
        $limit = (int) $limit;
3541
        $tag = trim(Database::escape_string($tag));
3542
3543
        // all the information of the field
3544
        $sql = "SELECT DISTINCT id, tag from $table_user_tag
3545
                WHERE field_id = $field_id AND tag LIKE '$tag%' ORDER BY tag LIMIT $limit";
3546
        $result = Database::query($sql);
3547
        $return = [];
3548
        if (Database::num_rows($result) > 0) {
3549
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3550
                $return[] = ['id' => $row['tag'], 'text' => $row['tag']];
3551
            }
3552
        }
3553
        if ('json' === $return_format) {
3554
            $return = json_encode($return);
3555
        }
3556
3557
        return $return;
3558
    }
3559
3560
    /**
3561
     * @param int $field_id
3562
     * @param int $limit
3563
     *
3564
     * @return array
3565
     */
3566
    public static function get_top_tags($field_id, $limit = 100)
3567
    {
3568
        // database table definition
3569
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3570
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3571
        $field_id = (int) $field_id;
3572
        $limit = (int) $limit;
3573
        // all the information of the field
3574
        $sql = "SELECT count(*) count, tag FROM $table_user_tag_values  uv
3575
                INNER JOIN $table_user_tag ut
3576
                ON (ut.id = uv.tag_id)
3577
                WHERE field_id = $field_id
3578
                GROUP BY tag_id
3579
                ORDER BY count DESC
3580
                LIMIT $limit";
3581
        $result = Database::query($sql);
3582
        $return = [];
3583
        if (Database::num_rows($result) > 0) {
3584
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3585
                $return[] = $row;
3586
            }
3587
        }
3588
3589
        return $return;
3590
    }
3591
3592
    /**
3593
     * Get user's tags.
3594
     *
3595
     * @param int $user_id
3596
     * @param int $field_id
3597
     *
3598
     * @return array
3599
     */
3600
    public static function get_user_tags($user_id, $field_id)
3601
    {
3602
        // database table definition
3603
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3604
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3605
        $field_id = (int) $field_id;
3606
        $user_id = (int) $user_id;
3607
3608
        // all the information of the field
3609
        $sql = "SELECT ut.id, tag, count
3610
                FROM $table_user_tag ut
3611
                INNER JOIN $table_user_tag_values uv
3612
                ON (uv.tag_id=ut.ID)
3613
                WHERE field_id = $field_id AND user_id = $user_id
3614
                ORDER BY tag";
3615
        $result = Database::query($sql);
3616
        $return = [];
3617
        if (Database::num_rows($result) > 0) {
3618
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3619
                $return[$row['id']] = ['tag' => $row['tag'], 'count' => $row['count']];
3620
            }
3621
        }
3622
3623
        return $return;
3624
    }
3625
3626
    /**
3627
     * Get user's tags.
3628
     *
3629
     * @param int  $user_id
3630
     * @param int  $field_id
3631
     * @param bool $show_links show links or not
3632
     *
3633
     * @return string
3634
     */
3635
    public static function get_user_tags_to_string($user_id, $field_id, $show_links = true)
3636
    {
3637
        // database table definition
3638
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3639
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3640
        $field_id = (int) $field_id;
3641
        $user_id = (int) $user_id;
3642
3643
        // all the information of the field
3644
        $sql = "SELECT ut.id, tag,count FROM $table_user_tag ut
3645
                INNER JOIN $table_user_tag_values uv
3646
                ON (uv.tag_id = ut.id)
3647
                WHERE field_id = $field_id AND user_id = $user_id
3648
                ORDER BY tag";
3649
3650
        $result = Database::query($sql);
3651
        $return = [];
3652
        if (Database::num_rows($result) > 0) {
3653
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3654
                $return[$row['id']] = ['tag' => $row['tag'], 'count' => $row['count']];
3655
            }
3656
        }
3657
        $user_tags = $return;
3658
        $tag_tmp = [];
3659
        foreach ($user_tags as $tag) {
3660
            if ($show_links) {
3661
                $tag_tmp[] = '<a href="'.api_get_path(WEB_PATH).'main/search/index.php?q='.$tag['tag'].'">'.
3662
                    $tag['tag'].
3663
                '</a>';
3664
            } else {
3665
                $tag_tmp[] = $tag['tag'];
3666
            }
3667
        }
3668
3669
        if (is_array($user_tags) && count($user_tags) > 0) {
3670
            return implode(', ', $tag_tmp);
3671
        } else {
3672
            return '';
3673
        }
3674
    }
3675
3676
    /**
3677
     * Get the tag id.
3678
     *
3679
     * @param int $tag
3680
     * @param int $field_id
3681
     *
3682
     * @return int returns 0 if fails otherwise the tag id
3683
     */
3684
    public static function get_tag_id($tag, $field_id)
3685
    {
3686
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3687
        $tag = Database::escape_string($tag);
3688
        $field_id = (int) $field_id;
3689
        //with COLLATE latin1_bin to select query in a case sensitive mode
3690
        $sql = "SELECT id FROM $table_user_tag
3691
                WHERE tag LIKE '$tag' AND field_id = $field_id";
3692
        $result = Database::query($sql);
3693
        if (Database::num_rows($result) > 0) {
3694
            $row = Database::fetch_array($result, 'ASSOC');
3695
3696
            return $row['id'];
3697
        } else {
3698
            return 0;
3699
        }
3700
    }
3701
3702
    /**
3703
     * Get the tag id.
3704
     *
3705
     * @param int $tag_id
3706
     * @param int $field_id
3707
     *
3708
     * @return int 0 if fails otherwise the tag id
3709
     */
3710
    public static function get_tag_id_from_id($tag_id, $field_id)
3711
    {
3712
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3713
        $tag_id = (int) $tag_id;
3714
        $field_id = (int) $field_id;
3715
        $sql = "SELECT id FROM $table_user_tag
3716
                WHERE id = '$tag_id' AND field_id = $field_id";
3717
        $result = Database::query($sql);
3718
        if (Database::num_rows($result) > 0) {
3719
            $row = Database::fetch_array($result, 'ASSOC');
3720
3721
            return $row['id'];
3722
        } else {
3723
            return false;
3724
        }
3725
    }
3726
3727
    /**
3728
     * Adds a user-tag value.
3729
     *
3730
     * @param mixed $tag
3731
     * @param int   $user_id
3732
     * @param int   $field_id field id of the tag
3733
     *
3734
     * @return bool True if the tag was inserted or updated. False otherwise.
3735
     *              The return value doesn't take into account *values* added to the tag.
3736
     *              Only the creation/update of the tag field itself.
3737
     */
3738
    public static function add_tag($tag, $user_id, $field_id)
3739
    {
3740
        // database table definition
3741
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3742
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3743
        $tag = trim(Database::escape_string($tag));
3744
        $user_id = (int) $user_id;
3745
        $field_id = (int) $field_id;
3746
3747
        $tag_id = self::get_tag_id($tag, $field_id);
3748
3749
        /* IMPORTANT
3750
         *  @todo we don't create tags with numbers
3751
         *
3752
         */
3753
        if (is_numeric($tag)) {
3754
            //the form is sending an id this means that the user select it from the list so it MUST exists
3755
            /* $new_tag_id = self::get_tag_id_from_id($tag,$field_id);
3756
              if ($new_tag_id !== false) {
3757
              $sql = "UPDATE $table_user_tag SET count = count + 1 WHERE id  = $new_tag_id";
3758
              $result = Database::query($sql);
3759
              $last_insert_id = $new_tag_id;
3760
              } else {
3761
              $sql = "INSERT INTO $table_user_tag (tag, field_id,count) VALUES ('$tag','$field_id', count + 1)";
3762
              $result = Database::query($sql);
3763
              $last_insert_id = Database::insert_id();
3764
              } */
3765
        }
3766
3767
        //this is a new tag
3768
        if (0 == $tag_id) {
3769
            //the tag doesn't exist
3770
            $sql = "INSERT INTO $table_user_tag (tag, field_id,count) VALUES ('$tag','$field_id', count + 1)";
3771
            Database::query($sql);
3772
            $last_insert_id = Database::insert_id();
3773
        } else {
3774
            //the tag exists we update it
3775
            $sql = "UPDATE $table_user_tag SET count = count + 1 WHERE id  = $tag_id";
3776
            Database::query($sql);
3777
            $last_insert_id = $tag_id;
3778
        }
3779
3780
        if (!empty($last_insert_id) && (0 != $last_insert_id)) {
3781
            //we insert the relationship user-tag
3782
            $sql = "SELECT tag_id FROM $table_user_tag_values
3783
                    WHERE user_id = $user_id AND tag_id = $last_insert_id ";
3784
            $result = Database::query($sql);
3785
            //if the relationship does not exist we create it
3786
            if (0 == Database::num_rows($result)) {
3787
                $sql = "INSERT INTO $table_user_tag_values SET user_id = $user_id, tag_id = $last_insert_id";
3788
                Database::query($sql);
3789
            }
3790
3791
            return true;
3792
        }
3793
3794
        return false;
3795
    }
3796
3797
    /**
3798
     * Deletes an user tag.
3799
     *
3800
     * @param int $user_id
3801
     * @param int $field_id
3802
     */
3803
    public static function delete_user_tags($user_id, $field_id)
3804
    {
3805
        // database table definition
3806
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3807
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3808
        $user_id = (int) $user_id;
3809
3810
        $tags = self::get_user_tags($user_id, $field_id);
3811
        if (is_array($tags) && count($tags) > 0) {
3812
            foreach ($tags as $key => $tag) {
3813
                if ($tag['count'] > '0') {
3814
                    $sql = "UPDATE $table_user_tag SET count = count - 1  WHERE id = $key ";
3815
                    Database::query($sql);
3816
                }
3817
                $sql = "DELETE FROM $table_user_tag_values
3818
                        WHERE user_id = $user_id AND tag_id = $key";
3819
                Database::query($sql);
3820
            }
3821
        }
3822
    }
3823
3824
    /**
3825
     * Process the tag list comes from the UserManager::update_extra_field_value() function.
3826
     *
3827
     * @param array $tags     the tag list that will be added
3828
     * @param int   $user_id
3829
     * @param int   $field_id
3830
     *
3831
     * @return bool
3832
     */
3833
    public static function process_tags($tags, $user_id, $field_id)
3834
    {
3835
        // We loop the tags and add it to the DB
3836
        if (is_array($tags)) {
3837
            foreach ($tags as $tag) {
3838
                self::add_tag($tag, $user_id, $field_id);
3839
            }
3840
        } else {
3841
            self::add_tag($tags, $user_id, $field_id);
3842
        }
3843
3844
        return true;
3845
    }
3846
3847
    /**
3848
     * Returns a list of all administrators.
3849
     *
3850
     * @return array
3851
     */
3852
    public static function get_all_administrators()
3853
    {
3854
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
3855
        $table_admin = Database::get_main_table(TABLE_MAIN_ADMIN);
3856
        $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3857
        $access_url_id = api_get_current_access_url_id();
3858
        if (api_get_multiple_access_url()) {
3859
            $sql = "SELECT admin.user_id, username, firstname, lastname, email, active
3860
                    FROM $tbl_url_rel_user as url
3861
                    INNER JOIN $table_admin as admin
3862
                    ON (admin.user_id=url.user_id)
3863
                    INNER JOIN $table_user u
3864
                    ON (u.id=admin.user_id)
3865
                    WHERE access_url_id ='".$access_url_id."'";
3866
        } else {
3867
            $sql = "SELECT admin.user_id, username, firstname, lastname, email, active
3868
                    FROM $table_admin as admin
3869
                    INNER JOIN $table_user u
3870
                    ON (u.id=admin.user_id)";
3871
        }
3872
        $result = Database::query($sql);
3873
        $return = [];
3874
        if (Database::num_rows($result) > 0) {
3875
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3876
                $return[$row['user_id']] = $row;
3877
            }
3878
        }
3879
3880
        return $return;
3881
    }
3882
3883
    /**
3884
     * Search an user (tags, first name, last name and email ).
3885
     *
3886
     * @param string $tag
3887
     * @param int    $field_id        field id of the tag
3888
     * @param int    $from            where to start in the query
3889
     * @param int    $number_of_items
3890
     * @param bool   $getCount        get count or not
3891
     *
3892
     * @return array
3893
     */
3894
    public static function get_all_user_tags(
3895
        $tag,
3896
        $field_id = 0,
3897
        $from = 0,
3898
        $number_of_items = 10,
3899
        $getCount = false
3900
    ) {
3901
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
3902
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3903
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3904
        $access_url_rel_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3905
3906
        $field_id = intval($field_id);
3907
        $from = intval($from);
3908
        $number_of_items = intval($number_of_items);
3909
3910
        $where_field = "";
3911
        $where_extra_fields = self::get_search_form_where_extra_fields();
3912
        if (0 != $field_id) {
3913
            $where_field = " field_id = $field_id AND ";
3914
        }
3915
3916
        // all the information of the field
3917
        if ($getCount) {
3918
            $select = "SELECT count(DISTINCT u.id) count";
3919
        } else {
3920
            $select = "SELECT DISTINCT u.id, u.username, firstname, lastname, email, tag, picture_uri";
3921
        }
3922
3923
        $sql = " $select
3924
                FROM $user_table u
3925
                INNER JOIN $access_url_rel_user_table url_rel_user
3926
                ON (u.id = url_rel_user.user_id)
3927
                LEFT JOIN $table_user_tag_values uv
3928
                ON (u.id AND uv.user_id AND uv.user_id = url_rel_user.user_id)
3929
                LEFT JOIN $table_user_tag ut ON (uv.tag_id = ut.id)
3930
                WHERE
3931
                    ($where_field tag LIKE '".Database::escape_string($tag."%")."') OR
3932
                    (
3933
                        u.firstname LIKE '".Database::escape_string("%".$tag."%")."' OR
3934
                        u.lastname LIKE '".Database::escape_string("%".$tag."%")."' OR
3935
                        u.username LIKE '".Database::escape_string("%".$tag."%")."' OR
3936
                        concat(u.firstname, ' ', u.lastname) LIKE '".Database::escape_string("%".$tag."%")."' OR
3937
                        concat(u.lastname, ' ', u.firstname) LIKE '".Database::escape_string("%".$tag."%")."'
3938
                     )
3939
                     ".(!empty($where_extra_fields) ? $where_extra_fields : '')."
3940
                     AND url_rel_user.access_url_id=".api_get_current_access_url_id();
3941
3942
        $keyword_active = true;
3943
        // only active users
3944
        if ($keyword_active) {
3945
            $sql .= " AND u.active='1'";
3946
        }
3947
        // avoid anonymous
3948
        $sql .= " AND u.status <> 6 ";
3949
        $sql .= " ORDER BY username";
3950
        $sql .= " LIMIT $from , $number_of_items";
3951
3952
        $result = Database::query($sql);
3953
        $return = [];
3954
3955
        if (Database::num_rows($result) > 0) {
3956
            if ($getCount) {
3957
                $row = Database::fetch_array($result, 'ASSOC');
3958
3959
                return $row['count'];
3960
            }
3961
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3962
                $return[$row['id']] = $row;
3963
            }
3964
        }
3965
3966
        return $return;
3967
    }
3968
3969
    /**
3970
     * Get extra filterable user fields (only type select).
3971
     *
3972
     * @return array Array of extra fields as [int => ['name' => ..., 'variable' => ..., 'data' => ...]] (
3973
     *               or empty array if no extra field)
3974
     */
3975
    public static function getExtraFilterableFields()
3976
    {
3977
        $extraFieldList = self::get_extra_fields();
3978
        $fields = [];
3979
        if (is_array($extraFieldList)) {
3980
            foreach ($extraFieldList as $extraField) {
3981
                // If is enabled to filter and is a "<select>" field type
3982
                if (1 == $extraField[8] && 4 == $extraField[2]) {
3983
                    $fields[] = [
3984
                        'name' => $extraField[3],
3985
                        'variable' => $extraField[1],
3986
                        'data' => $extraField[9],
3987
                    ];
3988
                }
3989
            }
3990
        }
3991
3992
        return $fields;
3993
    }
3994
3995
    /**
3996
     * Get extra where clauses for finding users based on extra filterable user fields (type select).
3997
     *
3998
     * @return string With AND clauses based on user's ID which have the values to search in extra user fields
3999
     *                (or empty if no extra field exists)
4000
     */
4001
    public static function get_search_form_where_extra_fields()
4002
    {
4003
        $useExtraFields = false;
4004
        $extraFields = self::getExtraFilterableFields();
4005
        $extraFieldResult = [];
4006
        if (is_array($extraFields) && count($extraFields) > 0) {
4007
            foreach ($extraFields as $extraField) {
4008
                $varName = 'field_'.$extraField['variable'];
4009
                if (self::is_extra_field_available($extraField['variable'])) {
4010
                    if (isset($_GET[$varName]) && '0' != $_GET[$varName]) {
4011
                        $useExtraFields = true;
4012
                        $extraFieldResult[] = self::get_extra_user_data_by_value(
4013
                            $extraField['variable'],
4014
                            $_GET[$varName]
4015
                        );
4016
                    }
4017
                }
4018
            }
4019
        }
4020
4021
        if ($useExtraFields) {
4022
            $finalResult = [];
4023
            if (count($extraFieldResult) > 1) {
4024
                for ($i = 0; $i < count($extraFieldResult) - 1; $i++) {
4025
                    if (is_array($extraFieldResult[$i]) && is_array($extraFieldResult[$i + 1])) {
4026
                        $finalResult = array_intersect($extraFieldResult[$i], $extraFieldResult[$i + 1]);
4027
                    }
4028
                }
4029
            } else {
4030
                $finalResult = $extraFieldResult[0];
4031
            }
4032
4033
            if (is_array($finalResult) && count($finalResult) > 0) {
4034
                $whereFilter = " AND u.id IN  ('".implode("','", $finalResult)."') ";
4035
            } else {
4036
                //no results
4037
                $whereFilter = " AND u.id  = -1 ";
4038
            }
4039
4040
            return $whereFilter;
4041
        }
4042
4043
        return '';
4044
    }
4045
4046
    /**
4047
     * Show the search form.
4048
     *
4049
     * @param string $query the value of the search box
4050
     *
4051
     * @throws Exception
4052
     *
4053
     * @return string HTML form
4054
     */
4055
    public static function get_search_form($query, $defaultParams = [])
4056
    {
4057
        $searchType = isset($_GET['search_type']) ? $_GET['search_type'] : null;
4058
        $form = new FormValidator(
4059
            'search_user',
4060
            'get',
4061
            api_get_path(WEB_PATH).'main/social/search.php',
4062
            '',
4063
            [],
4064
            FormValidator::LAYOUT_HORIZONTAL
4065
        );
4066
4067
        $query = Security::remove_XSS($query);
4068
4069
        if (!empty($query)) {
4070
            $form->addHeader(get_lang('Results and feedback').' "'.$query.'"');
0 ignored issues
show
Bug introduced by
Are you sure $query of type array|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

4070
            $form->addHeader(get_lang('Results and feedback').' "'./** @scrutinizer ignore-type */ $query.'"');
Loading history...
4071
        }
4072
4073
        $form->addText(
4074
            'q',
4075
            get_lang('Users, Groups'),
4076
            false,
4077
            [
4078
                'id' => 'q',
4079
            ]
4080
        );
4081
        $options = [
4082
            0 => get_lang('Select'),
4083
            1 => get_lang('User'),
4084
            2 => get_lang('Group'),
4085
        ];
4086
        $form->addSelect(
4087
            'search_type',
4088
            get_lang('Type'),
4089
            $options,
4090
            ['onchange' => 'javascript: extra_field_toogle();', 'id' => 'search_type']
4091
        );
4092
4093
        // Extra fields
4094
        $extraFields = self::getExtraFilterableFields();
4095
        $defaults = [];
4096
        if (is_array($extraFields) && count($extraFields) > 0) {
4097
            foreach ($extraFields as $extraField) {
4098
                $varName = 'field_'.$extraField['variable'];
4099
                $options = [
4100
                    0 => get_lang('Select'),
4101
                ];
4102
                foreach ($extraField['data'] as $option) {
4103
                    if (isset($_GET[$varName])) {
4104
                        if ($_GET[$varName] == $option[1]) {
4105
                            $defaults[$option[1]] = true;
4106
                        }
4107
                    }
4108
4109
                    $options[$option[1]] = $option[1];
4110
                }
4111
                $form->addSelect($varName, $extraField['name'], $options);
4112
            }
4113
        }
4114
4115
        $defaults['search_type'] = (int) $searchType;
4116
        $defaults['q'] = $query;
4117
4118
        if (!empty($defaultParams)) {
4119
            $defaults = array_merge($defaults, $defaultParams);
4120
        }
4121
        $form->setDefaults($defaults);
4122
        $form->addButtonSearch(get_lang('Search'));
4123
4124
        $js = '<script>
4125
        extra_field_toogle();
4126
        function extra_field_toogle() {
4127
            if (jQuery("select[name=search_type]").val() != "1") {
4128
                jQuery(".extra_field").hide();
4129
            } else {
4130
                jQuery(".extra_field").show();
4131
            }
4132
        }
4133
        </script>';
4134
4135
        return $js.$form->returnForm();
4136
    }
4137
4138
    /**
4139
     * @param int $userId
4140
     *
4141
     * @return array
4142
     */
4143
    public static function getDrhListFromUser($userId)
4144
    {
4145
        $tblUser = Database::get_main_table(TABLE_MAIN_USER);
4146
        $tblUserRelUser = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4147
        $tblUserRelAccessUrl = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
4148
        $userId = (int) $userId;
4149
4150
        $orderBy = null;
4151
        if (api_is_western_name_order()) {
4152
            $orderBy .= ' ORDER BY firstname, lastname ';
4153
        } else {
4154
            $orderBy .= ' ORDER BY lastname, firstname ';
4155
        }
4156
4157
        $sql = "SELECT u.id, username, u.firstname, u.lastname
4158
                FROM $tblUser u
4159
                INNER JOIN $tblUserRelUser uru ON (uru.friend_user_id = u.id)
4160
                INNER JOIN $tblUserRelAccessUrl a ON (a.user_id = u.id)
4161
                WHERE
4162
                    access_url_id = ".api_get_current_access_url_id()." AND
4163
                    uru.user_id = '$userId' AND
4164
                    relation_type = '".UserRelUser::USER_RELATION_TYPE_RRHH."'
4165
                    $orderBy
4166
                ";
4167
        $result = Database::query($sql);
4168
4169
        return Database::store_result($result);
4170
    }
4171
4172
    /**
4173
     * get users followed by human resource manager.
4174
     *
4175
     * @param int    $userId
4176
     * @param int    $userStatus         (STUDENT, COURSEMANAGER, etc)
4177
     * @param bool   $getOnlyUserId
4178
     * @param bool   $getSql
4179
     * @param bool   $getCount
4180
     * @param int    $from
4181
     * @param int    $numberItems
4182
     * @param int    $column
4183
     * @param string $direction
4184
     * @param int    $active
4185
     * @param string $lastConnectionDate
4186
     *
4187
     * @return array users
4188
     */
4189
    public static function get_users_followed_by_drh(
4190
        $userId,
4191
        $userStatus = 0,
4192
        $getOnlyUserId = false,
4193
        $getSql = false,
4194
        $getCount = false,
4195
        $from = null,
4196
        $numberItems = null,
4197
        $column = null,
4198
        $direction = null,
4199
        $active = null,
4200
        $lastConnectionDate = null
4201
    ) {
4202
        return self::getUsersFollowedByUser(
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::getUsersFol...astConnectionDate, DRH) also could return the type string which is incompatible with the documented return type array.
Loading history...
4203
            $userId,
4204
            $userStatus,
4205
            $getOnlyUserId,
4206
            $getSql,
4207
            $getCount,
4208
            $from,
4209
            $numberItems,
4210
            $column,
4211
            $direction,
4212
            $active,
4213
            $lastConnectionDate,
4214
            DRH
4215
        );
4216
    }
4217
4218
    /**
4219
     * Get users followed by human resource manager.
4220
     *
4221
     * @param int    $userId
4222
     * @param int    $userStatus             Filter users by status (STUDENT, COURSEMANAGER, etc)
4223
     * @param bool   $getOnlyUserId
4224
     * @param bool   $getSql
4225
     * @param bool   $getCount
4226
     * @param int    $from
4227
     * @param int    $numberItems
4228
     * @param int    $column
4229
     * @param string $direction
4230
     * @param int    $active
4231
     * @param string $lastConnectionDate
4232
     * @param int    $status                 the function is called by who? COURSEMANAGER, DRH?
4233
     * @param string $keyword
4234
     * @param bool   $checkSessionVisibility
4235
     *
4236
     * @return mixed Users list (array) or the SQL query if $getSQL was set to true
4237
     */
4238
    public static function getUsersFollowedByUser(
4239
        $userId,
4240
        $userStatus = null,
4241
        $getOnlyUserId = false,
4242
        $getSql = false,
4243
        $getCount = false,
4244
        $from = null,
4245
        $numberItems = null,
4246
        $column = null,
4247
        $direction = null,
4248
        $active = null,
4249
        $lastConnectionDate = null,
4250
        $status = null,
4251
        $keyword = null,
4252
        $checkSessionVisibility = false
4253
    ) {
4254
        // Database Table Definitions
4255
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
4256
        $tbl_user_rel_user = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4257
        $tbl_user_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
4258
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
4259
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4260
        $tbl_session_rel_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4261
        $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
4262
        $tbl_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
4263
4264
        $userId = (int) $userId;
4265
        $limitCondition = '';
4266
4267
        if (isset($from) && isset($numberItems)) {
4268
            $from = (int) $from;
4269
            $numberItems = (int) $numberItems;
4270
            $limitCondition = "LIMIT $from, $numberItems";
4271
        }
4272
4273
        $column = Database::escape_string($column);
4274
        $direction = in_array(strtolower($direction), ['asc', 'desc']) ? $direction : null;
4275
4276
        $userConditions = '';
4277
        if (!empty($userStatus)) {
4278
            $userConditions .= ' AND u.status = '.intval($userStatus);
4279
        }
4280
4281
        $select = " SELECT DISTINCT u.id user_id, u.username, u.lastname, u.firstname, u.email ";
4282
        if ($getOnlyUserId) {
4283
            $select = " SELECT DISTINCT u.id user_id";
4284
        }
4285
4286
        $masterSelect = "SELECT DISTINCT * FROM ";
4287
4288
        if ($getCount) {
4289
            $masterSelect = "SELECT COUNT(DISTINCT(user_id)) as count FROM ";
4290
            $select = " SELECT DISTINCT(u.id) user_id";
4291
        }
4292
4293
        if (!is_null($active)) {
4294
            $active = intval($active);
4295
            $userConditions .= " AND u.active = $active ";
4296
        }
4297
4298
        if (!empty($keyword)) {
4299
            $keyword = trim(Database::escape_string($keyword));
4300
            $keywordParts = array_filter(explode(' ', $keyword));
4301
            $extraKeyword = '';
4302
            if (!empty($keywordParts)) {
4303
                $keywordPartsFixed = Database::escape_string(implode('%', $keywordParts));
4304
                if (!empty($keywordPartsFixed)) {
4305
                    $extraKeyword .= " OR
4306
                        CONCAT(u.firstname, ' ', u.lastname) LIKE '%$keywordPartsFixed%' OR
4307
                        CONCAT(u.lastname, ' ', u.firstname) LIKE '%$keywordPartsFixed%' ";
4308
                }
4309
            }
4310
            $userConditions .= " AND (
4311
                u.username LIKE '%$keyword%' OR
4312
                u.firstname LIKE '%$keyword%' OR
4313
                u.lastname LIKE '%$keyword%' OR
4314
                u.official_code LIKE '%$keyword%' OR
4315
                u.email LIKE '%$keyword%' OR
4316
                CONCAT(u.firstname, ' ', u.lastname) LIKE '%$keyword%' OR
4317
                CONCAT(u.lastname, ' ', u.firstname) LIKE '%$keyword%'
4318
                $extraKeyword
4319
            )";
4320
        }
4321
4322
        if (!empty($lastConnectionDate)) {
4323
            $lastConnectionDate = Database::escape_string($lastConnectionDate);
4324
            $userConditions .= " AND u.last_login <= '$lastConnectionDate' ";
4325
        }
4326
4327
        $sessionConditionsCoach = null;
4328
        $dateCondition = '';
4329
        $drhConditions = null;
4330
        $teacherSelect = null;
4331
        $urlId = api_get_current_access_url_id();
4332
4333
        switch ($status) {
4334
            case DRH:
4335
                $drhConditions .= " AND
4336
                    friend_user_id = '$userId' AND
4337
                    relation_type = '".UserRelUser::USER_RELATION_TYPE_RRHH."'
4338
                ";
4339
                break;
4340
            case COURSEMANAGER:
4341
                $drhConditions .= " AND
4342
                    friend_user_id = '$userId' AND
4343
                    relation_type = '".UserRelUser::USER_RELATION_TYPE_RRHH."'
4344
                ";
4345
4346
                $sessionConditionsCoach .= " AND
4347
                    (s.id_coach = '$userId')
4348
                ";
4349
4350
                $sessionConditionsTeacher = " AND
4351
                    (scu.status = 2 AND scu.user_id = '$userId')
4352
                ";
4353
4354
                if ($checkSessionVisibility) {
4355
                    $today = api_strtotime('now', 'UTC');
4356
                    $today = date('Y-m-d', $today);
4357
                    $dateCondition = "
4358
                        AND
4359
                        (
4360
                            (s.access_start_date <= '$today' AND '$today' <= s.access_end_date) OR
4361
                            (s.access_start_date IS NULL AND s.access_end_date IS NULL) OR
4362
                            (s.access_start_date <= '$today' AND s.access_end_date IS NULL) OR
4363
                            ('$today' <= s.access_end_date AND s.access_start_date IS NULL)
4364
                        )
4365
					";
4366
                }
4367
4368
                // Use $tbl_session_rel_course_rel_user instead of $tbl_session_rel_user
4369
                /*
4370
                INNER JOIN $tbl_session_rel_user sru
4371
                ON (sru.user_id = u.id)
4372
                INNER JOIN $tbl_session_rel_course_rel_user scu
4373
                ON (scu.user_id = u.id AND scu.c_id IS NOT NULL AND visibility = 1)*/
4374
                $teacherSelect =
4375
                "UNION ALL (
4376
                        $select
4377
                        FROM $tbl_user u
4378
                        INNER JOIN $tbl_session_rel_user sru ON (sru.user_id = u.id)
4379
                        WHERE
4380
                            (
4381
                                sru.session_id IN (
4382
                                    SELECT DISTINCT(s.id) FROM $tbl_session s INNER JOIN
4383
                                    $tbl_session_rel_access_url session_rel_access_rel_user
4384
                                    ON session_rel_access_rel_user.session_id = s.id
4385
                                    WHERE access_url_id = ".$urlId."
4386
                                    $sessionConditionsCoach
4387
                                ) OR sru.session_id IN (
4388
                                    SELECT DISTINCT(s.id) FROM $tbl_session s
4389
                                    INNER JOIN $tbl_session_rel_access_url url
4390
                                    ON (url.session_id = s.id)
4391
                                    INNER JOIN $tbl_session_rel_course_rel_user scu
4392
                                    ON (scu.session_id = s.id)
4393
                                    WHERE access_url_id = ".$urlId."
4394
                                    $sessionConditionsTeacher
4395
                                    $dateCondition
4396
                                )
4397
                            )
4398
                            $userConditions
4399
                    )
4400
                    UNION ALL(
4401
                        $select
4402
                        FROM $tbl_user u
4403
                        INNER JOIN $tbl_course_user cu ON (cu.user_id = u.id)
4404
                        WHERE cu.c_id IN (
4405
                            SELECT DISTINCT(c_id) FROM $tbl_course_user
4406
                            WHERE user_id = $userId AND status = ".COURSEMANAGER."
4407
                        )
4408
                        $userConditions
4409
                    )"
4410
                ;
4411
                break;
4412
            case STUDENT_BOSS:
4413
                $drhConditions = " AND friend_user_id = $userId AND relation_type = ".UserRelUser::USER_RELATION_TYPE_BOSS;
4414
                break;
4415
            case HRM_REQUEST:
4416
                $drhConditions .= " AND
4417
                    friend_user_id = '$userId' AND
4418
                    relation_type = '".UserRelUser::USER_RELATION_TYPE_HRM_REQUEST."'
4419
                ";
4420
                break;
4421
        }
4422
4423
        $join = null;
4424
        $sql = " $masterSelect
4425
                (
4426
                    (
4427
                        $select
4428
                        FROM $tbl_user u
4429
                        INNER JOIN $tbl_user_rel_user uru ON (uru.user_id = u.id)
4430
                        LEFT JOIN $tbl_user_rel_access_url a ON (a.user_id = u.id)
4431
                        $join
4432
                        WHERE
4433
                            access_url_id = ".$urlId."
4434
                            $drhConditions
4435
                            $userConditions
4436
                    )
4437
                    $teacherSelect
4438
4439
                ) as t1";
4440
4441
        if ($getSql) {
4442
            return $sql;
4443
        }
4444
        if ($getCount) {
4445
            $result = Database::query($sql);
4446
            $row = Database::fetch_array($result);
4447
4448
            return $row['count'];
4449
        }
4450
4451
        $orderBy = null;
4452
        if (false == $getOnlyUserId) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
4453
            if (api_is_western_name_order()) {
4454
                $orderBy .= " ORDER BY firstname, lastname ";
4455
            } else {
4456
                $orderBy .= " ORDER BY lastname, firstname ";
4457
            }
4458
4459
            if (!empty($column) && !empty($direction)) {
4460
                // Fixing order due the UNIONs
4461
                $column = str_replace('u.', '', $column);
4462
                $orderBy = " ORDER BY `$column` $direction ";
4463
            }
4464
        }
4465
4466
        $sql .= $orderBy;
4467
        $sql .= $limitCondition;
4468
4469
        $result = Database::query($sql);
4470
        $users = [];
4471
        if (Database::num_rows($result) > 0) {
4472
            while ($row = Database::fetch_array($result)) {
4473
                $users[$row['user_id']] = $row;
4474
            }
4475
        }
4476
4477
        return $users;
4478
    }
4479
4480
    /**
4481
     * Subscribes users to human resource manager (Dashboard feature).
4482
     *
4483
     * @param int   $hr_dept_id
4484
     * @param array $users_id
4485
     * @param bool  $deleteOtherAssignedUsers
4486
     *
4487
     * @return int
4488
     */
4489
    public static function subscribeUsersToHRManager(
4490
        $hr_dept_id,
4491
        $users_id,
4492
        $deleteOtherAssignedUsers = true
4493
    ) {
4494
        return self::subscribeUsersToUser(
4495
            $hr_dept_id,
4496
            $users_id,
4497
            UserRelUser::USER_RELATION_TYPE_RRHH,
4498
            false,
4499
            $deleteOtherAssignedUsers
4500
        );
4501
    }
4502
4503
    /**
4504
     * Register request to assign users to HRM.
4505
     *
4506
     * @param int   $hrmId   The HRM ID
4507
     * @param array $usersId The users IDs
4508
     *
4509
     * @return int
4510
     */
4511
    public static function requestUsersToHRManager($hrmId, $usersId)
4512
    {
4513
        return self::subscribeUsersToUser(
4514
            $hrmId,
4515
            $usersId,
4516
            UserRelUser::USER_RELATION_TYPE_HRM_REQUEST,
4517
            false,
4518
            false
4519
        );
4520
    }
4521
4522
    /**
4523
     * Remove the requests for assign a user to a HRM.
4524
     *
4525
     * @param array $usersId List of user IDs from whom to remove all relations requests with HRM
4526
     */
4527
    public static function clearHrmRequestsForUser(User $hrmId, $usersId)
4528
    {
4529
        $users = implode(', ', $usersId);
4530
        Database::getManager()
4531
            ->createQuery('
4532
                DELETE FROM ChamiloCoreBundle:UserRelUser uru
4533
                WHERE uru.friendUserId = :hrm_id AND uru.relationType = :relation_type AND uru.userId IN (:users_ids)
4534
            ')
4535
            ->execute(['hrm_id' => $hrmId, 'relation_type' => UserRelUser::USER_RELATION_TYPE_HRM_REQUEST, 'users_ids' => $users]);
4536
    }
4537
4538
    /**
4539
     * Add subscribed users to a user by relation type.
4540
     *
4541
     * @param int    $userId                   The user id
4542
     * @param array  $subscribedUsersId        The id of subscribed users
4543
     * @param string $relationType             The relation type
4544
     * @param bool   $deleteUsersBeforeInsert
4545
     * @param bool   $deleteOtherAssignedUsers
4546
     *
4547
     * @return int
4548
     */
4549
    public static function subscribeUsersToUser(
4550
        $userId,
4551
        $subscribedUsersId,
4552
        $relationType,
4553
        $deleteUsersBeforeInsert = false,
4554
        $deleteOtherAssignedUsers = true
4555
    ) {
4556
        $userRelUserTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4557
        $userRelAccessUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
4558
4559
        $userId = (int) $userId;
4560
        $relationType = (int) $relationType;
4561
        $affectedRows = 0;
4562
4563
        if ($deleteOtherAssignedUsers) {
4564
            if (api_get_multiple_access_url()) {
4565
                // Deleting assigned users to hrm_id
4566
                $sql = "SELECT s.user_id
4567
                        FROM $userRelUserTable s
4568
                        INNER JOIN $userRelAccessUrlTable a
4569
                        ON (a.user_id = s.user_id)
4570
                        WHERE
4571
                            friend_user_id = $userId AND
4572
                            relation_type = $relationType AND
4573
                            access_url_id = ".api_get_current_access_url_id();
4574
            } else {
4575
                $sql = "SELECT user_id
4576
                        FROM $userRelUserTable
4577
                        WHERE
4578
                            friend_user_id = $userId AND
4579
                            relation_type = $relationType";
4580
            }
4581
            $result = Database::query($sql);
4582
4583
            if (Database::num_rows($result) > 0) {
4584
                while ($row = Database::fetch_array($result)) {
4585
                    $sql = "DELETE FROM $userRelUserTable
4586
                            WHERE
4587
                                user_id = {$row['user_id']} AND
4588
                                friend_user_id = $userId AND
4589
                                relation_type = $relationType";
4590
                    Database::query($sql);
4591
                }
4592
            }
4593
        }
4594
4595
        if ($deleteUsersBeforeInsert) {
4596
            $sql = "DELETE FROM $userRelUserTable
4597
                    WHERE
4598
                        user_id = $userId AND
4599
                        relation_type = $relationType";
4600
            Database::query($sql);
4601
        }
4602
4603
        // Inserting new user list
4604
        if (is_array($subscribedUsersId)) {
4605
            foreach ($subscribedUsersId as $subscribedUserId) {
4606
                $subscribedUserId = (int) $subscribedUserId;
4607
                $sql = "SELECT id
4608
                        FROM $userRelUserTable
4609
                        WHERE
4610
                            user_id = $subscribedUserId AND
4611
                            friend_user_id = $userId AND
4612
                            relation_type = $relationType";
4613
4614
                $result = Database::query($sql);
4615
                $num = Database::num_rows($result);
4616
                if (0 === $num) {
4617
                    $date = api_get_utc_datetime();
4618
                    $sql = "INSERT INTO $userRelUserTable (user_id, friend_user_id, relation_type, last_edit)
4619
                            VALUES ($subscribedUserId, $userId, $relationType, '$date')";
4620
                    $result = Database::query($sql);
4621
                    $affectedRows += Database::affected_rows($result);
4622
                }
4623
            }
4624
        }
4625
4626
        return $affectedRows;
4627
    }
4628
4629
    /**
4630
     * This function check if an user is followed by human resources manager.
4631
     *
4632
     * @param int $user_id
4633
     * @param int $hr_dept_id Human resources manager
4634
     *
4635
     * @return bool
4636
     */
4637
    public static function is_user_followed_by_drh($user_id, $hr_dept_id)
4638
    {
4639
        $tbl_user_rel_user = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4640
        $user_id = (int) $user_id;
4641
        $hr_dept_id = (int) $hr_dept_id;
4642
        $result = false;
4643
4644
        $sql = "SELECT user_id FROM $tbl_user_rel_user
4645
                WHERE
4646
                    user_id = $user_id AND
4647
                    friend_user_id = $hr_dept_id AND
4648
                    relation_type = ".UserRelUser::USER_RELATION_TYPE_RRHH;
4649
        $rs = Database::query($sql);
4650
        if (Database::num_rows($rs) > 0) {
4651
            $result = true;
4652
        }
4653
4654
        return $result;
4655
    }
4656
4657
    /**
4658
     * Return the user id of teacher or session administrator.
4659
     *
4660
     * @param array $courseInfo
4661
     *
4662
     * @return mixed The user id, or false if the session ID was negative
4663
     */
4664
    public static function get_user_id_of_course_admin_or_session_admin($courseInfo)
4665
    {
4666
        $session = api_get_session_id();
4667
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
4668
        $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4669
        $table_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4670
4671
        if (empty($courseInfo)) {
4672
            return false;
4673
        }
4674
4675
        $courseId = $courseInfo['real_id'];
4676
4677
        if (0 == $session || is_null($session)) {
4678
            $sql = 'SELECT u.id uid FROM '.$table_user.' u
4679
                    INNER JOIN '.$table_course_user.' ru
4680
                    ON ru.user_id = u.id
4681
                    WHERE
4682
                        ru.status = 1 AND
4683
                        ru.c_id = "'.$courseId.'" ';
4684
            $rs = Database::query($sql);
4685
            $num_rows = Database::num_rows($rs);
4686
            if (1 == $num_rows) {
4687
                $row = Database::fetch_array($rs);
4688
4689
                return $row['uid'];
4690
            } else {
4691
                $my_num_rows = $num_rows;
4692
                $my_user_id = Database::result($rs, $my_num_rows - 1, 'uid');
4693
4694
                return $my_user_id;
4695
            }
4696
        } elseif ($session > 0) {
4697
            $sql = 'SELECT u.id uid FROM '.$table_user.' u
4698
                    INNER JOIN '.$table_session_course_user.' sru
4699
                    ON sru.user_id=u.id
4700
                    WHERE
4701
                        sru.c_id="'.$courseId.'" AND
4702
                        sru.status=2';
4703
            $rs = Database::query($sql);
4704
            $row = Database::fetch_array($rs);
4705
4706
            return $row['uid'];
4707
        }
4708
4709
        return false;
4710
    }
4711
4712
    /**
4713
     * Determines if a user is a gradebook certified.
4714
     *
4715
     * @param int $cat_id  The category id of gradebook
4716
     * @param int $user_id The user id
4717
     *
4718
     * @return bool
4719
     */
4720
    public static function is_user_certified($cat_id, $user_id)
4721
    {
4722
        $cat_id = (int) $cat_id;
4723
        $user_id = (int) $user_id;
4724
4725
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
4726
        $sql = 'SELECT path_certificate
4727
                FROM '.$table.'
4728
                WHERE
4729
                    cat_id = "'.$cat_id.'" AND
4730
                    user_id = "'.$user_id.'"';
4731
        $rs = Database::query($sql);
4732
        $row = Database::fetch_array($rs);
4733
4734
        if ('' == $row['path_certificate'] || is_null($row['path_certificate'])) {
4735
            return false;
4736
        }
4737
4738
        return true;
4739
    }
4740
4741
    /**
4742
     * Gets the info about a gradebook certificate for a user by course.
4743
     *
4744
     * @param array $course_info The course code
4745
     * @param int   $session_id
4746
     * @param int   $user_id     The user id
4747
     *
4748
     * @return array if there is not information return false
4749
     */
4750
    public static function get_info_gradebook_certificate($course_info, $session_id, $user_id)
4751
    {
4752
        $tbl_grade_certificate = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
4753
        $tbl_grade_category = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
4754
        $session_id = (int) $session_id;
4755
        $user_id = (int) $user_id;
4756
        $courseId = $course_info['real_id'];
4757
4758
        if (empty($session_id)) {
4759
            $session_condition = ' AND (session_id = "" OR session_id = 0 OR session_id IS NULL )';
4760
        } else {
4761
            $session_condition = " AND session_id = $session_id";
4762
        }
4763
4764
        $sql = 'SELECT * FROM '.$tbl_grade_certificate.'
4765
                WHERE cat_id = (
4766
                    SELECT id FROM '.$tbl_grade_category.'
4767
                    WHERE
4768
                        c_id = "'.$courseId.'" '.$session_condition.'
4769
                    LIMIT 1
4770
                ) AND user_id='.$user_id;
4771
4772
        $rs = Database::query($sql);
4773
        if (Database::num_rows($rs) > 0) {
4774
            $row = Database::fetch_array($rs, 'ASSOC');
4775
            $score = $row['score_certificate'];
4776
            $category_id = $row['cat_id'];
4777
            $cat = Category::load($category_id);
4778
            $displayscore = ScoreDisplay::instance();
4779
            if (isset($cat) && $displayscore->is_custom()) {
4780
                $grade = $displayscore->display_score(
4781
                    [$score, $cat[0]->get_weight()],
4782
                    SCORE_DIV_PERCENT_WITH_CUSTOM
4783
                );
4784
            } else {
4785
                $grade = $displayscore->display_score(
4786
                    [$score, $cat[0]->get_weight()]
4787
                );
4788
            }
4789
            $row['grade'] = $grade;
4790
4791
            return $row;
4792
        }
4793
4794
        return false;
4795
    }
4796
4797
    /**
4798
     * This function check if the user is a coach inside session course.
4799
     *
4800
     * @param int $user_id    User id
4801
     * @param int $courseId
4802
     * @param int $session_id
4803
     *
4804
     * @return bool True if the user is a coach
4805
     */
4806
    public static function is_session_course_coach($user_id, $courseId, $session_id)
4807
    {
4808
        $table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4809
        // Protect data
4810
        $user_id = intval($user_id);
4811
        $courseId = intval($courseId);
4812
        $session_id = intval($session_id);
4813
        $result = false;
4814
4815
        $sql = "SELECT session_id FROM $table
4816
                WHERE
4817
                  session_id = $session_id AND
4818
                  c_id = $courseId AND
4819
                  user_id = $user_id AND
4820
                  status = 2 ";
4821
        $res = Database::query($sql);
4822
4823
        if (Database::num_rows($res) > 0) {
4824
            $result = true;
4825
        }
4826
4827
        return $result;
4828
    }
4829
4830
    /**
4831
     * This function returns an icon path that represents the favicon of the website of which the url given.
4832
     * Defaults to the current Chamilo favicon.
4833
     *
4834
     * @param string $url1 URL of website where to look for favicon.ico
4835
     * @param string $url2 Optional second URL of website where to look for favicon.ico
4836
     *
4837
     * @return string Path of icon to load
4838
     */
4839
    public static function get_favicon_from_url($url1, $url2 = null)
4840
    {
4841
        $icon_link = '';
4842
        $url = $url1;
4843
        if (empty($url1)) {
4844
            $url = $url2;
4845
            if (empty($url)) {
4846
                $url = api_get_access_url(api_get_current_access_url_id());
4847
                $url = $url[0];
4848
            }
4849
        }
4850
        if (!empty($url)) {
4851
            $pieces = parse_url($url);
4852
            $icon_link = $pieces['scheme'].'://'.$pieces['host'].'/favicon.ico';
4853
        }
4854
4855
        return $icon_link;
4856
    }
4857
4858
    public static function addUserAsAdmin(User $user)
4859
    {
4860
        $userId = $user->getId();
4861
4862
        if (!self::is_admin($userId)) {
4863
            $table = Database::get_main_table(TABLE_MAIN_ADMIN);
4864
            $sql = "INSERT INTO $table SET user_id = $userId";
4865
            Database::query($sql);
4866
        }
4867
4868
        $user->addRole('ROLE_SUPER_ADMIN');
4869
        self::getRepository()->updateUser($user, true);
4870
    }
4871
4872
    public static function removeUserAdmin(User $user)
4873
    {
4874
        $userId = (int) $user->getId();
4875
        if (self::is_admin($userId)) {
4876
            $table = Database::get_main_table(TABLE_MAIN_ADMIN);
4877
            $sql = "DELETE FROM $table WHERE user_id = $userId";
4878
            Database::query($sql);
4879
            $user->removeRole('ROLE_SUPER_ADMIN');
4880
            self::getRepository()->updateUser($user, true);
4881
        }
4882
    }
4883
4884
    /**
4885
     * @param string $from
4886
     * @param string $to
4887
     */
4888
    public static function update_all_user_languages($from, $to)
4889
    {
4890
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
4891
        $from = Database::escape_string($from);
4892
        $to = Database::escape_string($to);
4893
4894
        if (!empty($to) && !empty($from)) {
4895
            $sql = "UPDATE $table_user SET language = '$to'
4896
                    WHERE language = '$from'";
4897
            Database::query($sql);
4898
        }
4899
    }
4900
4901
    /**
4902
     * Subscribe boss to students.
4903
     *
4904
     * @param int   $bossId                   The boss id
4905
     * @param array $usersId                  The users array
4906
     * @param bool  $deleteOtherAssignedUsers
4907
     *
4908
     * @return int Affected rows
4909
     */
4910
    public static function subscribeBossToUsers($bossId, $usersId, $deleteOtherAssignedUsers = true)
4911
    {
4912
        return self::subscribeUsersToUser(
4913
            $bossId,
4914
            $usersId,
4915
            UserRelUser::USER_RELATION_TYPE_BOSS,
4916
            false,
4917
            $deleteOtherAssignedUsers
4918
        );
4919
    }
4920
4921
    /**
4922
     * @param int $userId
4923
     *
4924
     * @return bool
4925
     */
4926
    public static function removeAllBossFromStudent($userId)
4927
    {
4928
        $userId = (int) $userId;
4929
4930
        if (empty($userId)) {
4931
            return false;
4932
        }
4933
4934
        $userRelUserTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4935
        $sql = "DELETE FROM $userRelUserTable
4936
                WHERE user_id = $userId AND relation_type = ".UserRelUser::USER_RELATION_TYPE_BOSS;
4937
        Database::query($sql);
4938
4939
        return true;
4940
    }
4941
4942
    /**
4943
     * Subscribe boss to students, if $bossList is empty then the boss list will be empty too.
4944
     *
4945
     * @param int   $studentId
4946
     * @param array $bossList
4947
     * @param bool  $sendNotification
4948
     *
4949
     * @return mixed Affected rows or false on failure
4950
     */
4951
    public static function subscribeUserToBossList(
4952
        $studentId,
4953
        $bossList,
4954
        $sendNotification = false
4955
    ) {
4956
        $inserted = 0;
4957
        if (!empty($bossList)) {
4958
            sort($bossList);
4959
            $studentId = (int) $studentId;
4960
            $studentInfo = api_get_user_info($studentId);
4961
4962
            if (empty($studentInfo)) {
4963
                return false;
4964
            }
4965
4966
            $previousBossList = self::getStudentBossList($studentId);
4967
            $previousBossList = !empty($previousBossList) ? array_column($previousBossList, 'boss_id') : [];
4968
            sort($previousBossList);
4969
4970
            // Boss list is the same, nothing changed.
4971
            if ($bossList == $previousBossList) {
4972
                return false;
4973
            }
4974
4975
            $userRelUserTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4976
            self::removeAllBossFromStudent($studentId);
4977
4978
            foreach ($bossList as $bossId) {
4979
                $bossId = (int) $bossId;
4980
                $bossInfo = api_get_user_info($bossId);
4981
4982
                if (empty($bossInfo)) {
4983
                    continue;
4984
                }
4985
4986
                $bossLanguage = $bossInfo['language'];
4987
                $sql = "INSERT IGNORE INTO $userRelUserTable (user_id, friend_user_id, relation_type)
4988
                        VALUES ($studentId, $bossId, ".UserRelUser::USER_RELATION_TYPE_BOSS.")";
4989
                $insertId = Database::query($sql);
4990
4991
                if ($insertId) {
4992
                    if ($sendNotification) {
4993
                        $name = $studentInfo['complete_name'];
4994
                        $url = api_get_path(WEB_CODE_PATH).'mySpace/myStudents.php?student='.$studentId;
4995
                        $url = Display::url($url, $url);
4996
                        $subject = sprintf(get_lang('You have been assigned the learner %s'), $name);
4997
                        $message = sprintf(get_lang('You have been assigned the learner %sWithUrlX'), $name, $url);
4998
                        MessageManager::send_message_simple(
4999
                            $bossId,
5000
                            $subject,
5001
                            $message
5002
                        );
5003
                    }
5004
                    $inserted++;
5005
                }
5006
            }
5007
        } else {
5008
            self::removeAllBossFromStudent($studentId);
5009
        }
5010
5011
        return $inserted;
5012
    }
5013
5014
    /**
5015
     * Get users followed by student boss.
5016
     *
5017
     * @param int    $userId
5018
     * @param int    $userStatus         (STUDENT, COURSEMANAGER, etc)
5019
     * @param bool   $getOnlyUserId
5020
     * @param bool   $getSql
5021
     * @param bool   $getCount
5022
     * @param int    $from
5023
     * @param int    $numberItems
5024
     * @param int    $column
5025
     * @param string $direction
5026
     * @param int    $active
5027
     * @param string $lastConnectionDate
5028
     *
5029
     * @return array users
5030
     */
5031
    public static function getUsersFollowedByStudentBoss(
5032
        $userId,
5033
        $userStatus = 0,
5034
        $getOnlyUserId = false,
5035
        $getSql = false,
5036
        $getCount = false,
5037
        $from = null,
5038
        $numberItems = null,
5039
        $column = null,
5040
        $direction = null,
5041
        $active = null,
5042
        $lastConnectionDate = null
5043
    ) {
5044
        return self::getUsersFollowedByUser(
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::getUsersFol...tionDate, STUDENT_BOSS) also could return the type string which is incompatible with the documented return type array.
Loading history...
5045
            $userId,
5046
            $userStatus,
5047
            $getOnlyUserId,
5048
            $getSql,
5049
            $getCount,
5050
            $from,
5051
            $numberItems,
5052
            $column,
5053
            $direction,
5054
            $active,
5055
            $lastConnectionDate,
5056
            STUDENT_BOSS
5057
        );
5058
    }
5059
5060
    /**
5061
     * @return array
5062
     */
5063
    public static function getOfficialCodeGrouped()
5064
    {
5065
        $user = Database::get_main_table(TABLE_MAIN_USER);
5066
        $sql = "SELECT DISTINCT official_code
5067
                FROM $user
5068
                GROUP BY official_code";
5069
        $result = Database::query($sql);
5070
        $values = Database::store_result($result, 'ASSOC');
5071
        $result = [];
5072
        foreach ($values as $value) {
5073
            $result[$value['official_code']] = $value['official_code'];
5074
        }
5075
5076
        return $result;
5077
    }
5078
5079
    /**
5080
     * @param string $officialCode
5081
     *
5082
     * @return array
5083
     */
5084
    public static function getUsersByOfficialCode($officialCode)
5085
    {
5086
        $user = Database::get_main_table(TABLE_MAIN_USER);
5087
        $officialCode = Database::escape_string($officialCode);
5088
5089
        $sql = "SELECT DISTINCT id
5090
                FROM $user
5091
                WHERE official_code = '$officialCode'
5092
                ";
5093
        $result = Database::query($sql);
5094
5095
        $users = [];
5096
        while ($row = Database::fetch_array($result)) {
5097
            $users[] = $row['id'];
5098
        }
5099
5100
        return $users;
5101
    }
5102
5103
    /**
5104
     * Calc the expended time (in seconds) by a user in a course.
5105
     *
5106
     * @param int    $userId    The user id
5107
     * @param int    $courseId  The course id
5108
     * @param int    $sessionId Optional. The session id
5109
     * @param string $from      Optional. From date
5110
     * @param string $until     Optional. Until date
5111
     *
5112
     * @return int The time
5113
     */
5114
    public static function getTimeSpentInCourses(
5115
        $userId,
5116
        $courseId,
5117
        $sessionId = 0,
5118
        $from = '',
5119
        $until = ''
5120
    ) {
5121
        $userId = (int) $userId;
5122
        $sessionId = (int) $sessionId;
5123
5124
        $trackCourseAccessTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5125
        $whereConditions = [
5126
            'user_id = ? ' => $userId,
5127
            'AND c_id = ? ' => $courseId,
5128
            'AND session_id = ? ' => $sessionId,
5129
        ];
5130
5131
        if (!empty($from) && !empty($until)) {
5132
            $whereConditions["AND (login_course_date >= '?' "] = $from;
5133
            $whereConditions["AND logout_course_date <= DATE_ADD('?', INTERVAL 1 DAY)) "] = $until;
5134
        }
5135
5136
        $trackResult = Database::select(
5137
            'SUM(UNIX_TIMESTAMP(logout_course_date) - UNIX_TIMESTAMP(login_course_date)) as total_time',
5138
            $trackCourseAccessTable,
5139
            [
5140
                'where' => $whereConditions,
5141
            ],
5142
            'first'
5143
        );
5144
5145
        if (false != $trackResult) {
5146
            return $trackResult['total_time'] ? $trackResult['total_time'] : 0;
5147
        }
5148
5149
        return 0;
5150
    }
5151
5152
    /**
5153
     * Get the boss user ID from a followed user id.
5154
     *
5155
     * @param $userId
5156
     *
5157
     * @return bool
5158
     */
5159
    public static function getFirstStudentBoss($userId)
5160
    {
5161
        $userId = (int) $userId;
5162
        if ($userId > 0) {
5163
            $userRelTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5164
            $row = Database::select(
5165
                'DISTINCT friend_user_id AS boss_id',
5166
                $userRelTable,
5167
                [
5168
                    'where' => [
5169
                        'user_id = ? AND relation_type = ? LIMIT 1' => [
5170
                            $userId,
5171
                            UserRelUser::USER_RELATION_TYPE_BOSS,
5172
                        ],
5173
                    ],
5174
                ]
5175
            );
5176
            if (!empty($row)) {
5177
                return $row[0]['boss_id'];
5178
            }
5179
        }
5180
5181
        return false;
5182
    }
5183
5184
    /**
5185
     * Get the boss user ID from a followed user id.
5186
     *
5187
     * @param int $userId student id
5188
     *
5189
     * @return array
5190
     */
5191
    public static function getStudentBossList($userId)
5192
    {
5193
        $userId = (int) $userId;
5194
5195
        if ($userId > 0) {
5196
            $userRelTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5197
5198
            return Database::select(
5199
                'DISTINCT friend_user_id AS boss_id',
5200
                $userRelTable,
5201
                [
5202
                    'where' => [
5203
                        'user_id = ? AND relation_type = ? ' => [
5204
                            $userId,
5205
                            UserRelUser::USER_RELATION_TYPE_BOSS,
5206
                        ],
5207
                    ],
5208
                ]
5209
            );
5210
        }
5211
5212
        return [];
5213
    }
5214
5215
    /**
5216
     * @param int $bossId
5217
     * @param int $studentId
5218
     *
5219
     * @return bool
5220
     */
5221
    public static function userIsBossOfStudent($bossId, $studentId)
5222
    {
5223
        $result = false;
5224
        $bossList = self::getStudentBossList($studentId);
5225
        if (!empty($bossList)) {
5226
            $bossList = array_column($bossList, 'boss_id');
5227
            if (in_array($bossId, $bossList)) {
5228
                $result = true;
5229
            }
5230
        }
5231
5232
        return $result;
5233
    }
5234
5235
    /**
5236
     * Displays the name of the user and makes the link to the user profile.
5237
     *
5238
     * @param array $userInfo
5239
     *
5240
     * @return string
5241
     */
5242
    public static function getUserProfileLink($userInfo)
5243
    {
5244
        if (isset($userInfo) && isset($userInfo['user_id'])) {
5245
            return Display::url(
5246
                $userInfo['complete_name_with_username'],
5247
                $userInfo['profile_url']
5248
            );
5249
        }
5250
5251
        return get_lang('Anonymous');
5252
    }
5253
5254
    /**
5255
     * Get users whose name matches $firstname and $lastname.
5256
     *
5257
     * @param string $firstname Firstname to search
5258
     * @param string $lastname  Lastname to search
5259
     *
5260
     * @return array The user list
5261
     */
5262
    public static function getUsersByName($firstname, $lastname)
5263
    {
5264
        $firstname = Database::escape_string($firstname);
5265
        $lastname = Database::escape_string($lastname);
5266
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
5267
5268
        $sql = <<<SQL
5269
            SELECT id, username, lastname, firstname
5270
            FROM $userTable
5271
            WHERE
5272
                firstname LIKE '$firstname%' AND
5273
                lastname LIKE '$lastname%'
5274
SQL;
5275
        $result = Database::query($sql);
5276
        $users = [];
5277
        while ($resultData = Database::fetch_object($result)) {
5278
            $users[] = $resultData;
5279
        }
5280
5281
        return $users;
5282
    }
5283
5284
    /**
5285
     * @param int $optionSelected
5286
     *
5287
     * @return string
5288
     */
5289
    public static function getUserSubscriptionTab($optionSelected = 1)
5290
    {
5291
        $allowAdmin = api_get_setting('allow_user_course_subscription_by_course_admin');
5292
        if (('true' === $allowAdmin && api_is_allowed_to_edit()) ||
5293
            api_is_platform_admin()
5294
        ) {
5295
            $userPath = api_get_path(WEB_CODE_PATH).'user/';
5296
5297
            $headers = [
5298
                [
5299
                    'url' => $userPath.'user.php?'.api_get_cidreq().'&type='.STUDENT,
5300
                    'content' => get_lang('Learners'),
5301
                ],
5302
                [
5303
                    'url' => $userPath.'user.php?'.api_get_cidreq().'&type='.COURSEMANAGER,
5304
                    'content' => get_lang('Trainers'),
5305
                ],
5306
                /*[
5307
                    'url' => $userPath.'subscribe_user.php?'.api_get_cidreq(),
5308
                    'content' => get_lang('Learners'),
5309
                ],
5310
                [
5311
                    'url' => $userPath.'subscribe_user.php?type=teacher&'.api_get_cidreq(),
5312
                    'content' => get_lang('Trainers'),
5313
                ],*/
5314
                [
5315
                    'url' => api_get_path(WEB_CODE_PATH).'group/group.php?'.api_get_cidreq(),
5316
                    'content' => get_lang('Groups'),
5317
                ],
5318
                [
5319
                    'url' => $userPath.'class.php?'.api_get_cidreq(),
5320
                    'content' => get_lang('Classes'),
5321
                ],
5322
            ];
5323
5324
            return Display::tabsOnlyLink($headers, $optionSelected);
5325
        }
5326
5327
        return '';
5328
    }
5329
5330
    /**
5331
     * Make sure this function is protected because it does NOT check password!
5332
     *
5333
     * This function defines globals.
5334
     *
5335
     * @param int  $userId
5336
     * @param bool $checkIfUserCanLoginAs
5337
     *
5338
     * @return bool
5339
     *
5340
     * @author Evie Embrechts
5341
     * @author Yannick Warnier <[email protected]>
5342
     */
5343
    public static function loginAsUser($userId, $checkIfUserCanLoginAs = true)
5344
    {
5345
        $userId = (int) $userId;
5346
        $userInfo = api_get_user_info($userId);
5347
5348
        // Check if the user is allowed to 'login_as'
5349
        $canLoginAs = true;
5350
        if ($checkIfUserCanLoginAs) {
5351
            $canLoginAs = api_can_login_as($userId);
5352
        }
5353
5354
        if (!$canLoginAs || empty($userInfo)) {
5355
            return false;
5356
        }
5357
5358
        if ($userId) {
5359
            $logInfo = [
5360
                'tool' => 'logout',
5361
                'tool_id' => 0,
5362
                'tool_id_detail' => 0,
5363
                'action' => '',
5364
                'info' => 'Change user (login as)',
5365
            ];
5366
            Event::registerLog($logInfo);
0 ignored issues
show
Bug introduced by
The method registerLog() does not exist on Event. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

5366
            Event::/** @scrutinizer ignore-call */ 
5367
                   registerLog($logInfo);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
5367
5368
            // Logout the current user
5369
            self::loginDelete(api_get_user_id());
5370
5371
            return true;
5372
5373
            Session::erase('_user');
0 ignored issues
show
Unused Code introduced by
ChamiloSession::erase('_user') is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
5374
            Session::erase('is_platformAdmin');
5375
            Session::erase('is_allowedCreateCourse');
5376
            Session::erase('_uid');
5377
5378
            // Cleaning session variables
5379
            $_user['firstName'] = $userInfo['firstname'];
5380
            $_user['lastName'] = $userInfo['lastname'];
5381
            $_user['mail'] = $userInfo['email'];
5382
            $_user['official_code'] = $userInfo['official_code'];
5383
            $_user['picture_uri'] = $userInfo['picture_uri'];
5384
            $_user['user_id'] = $userId;
5385
            $_user['id'] = $userId;
5386
            $_user['status'] = $userInfo['status'];
5387
5388
            // Filling session variables with new data
5389
            Session::write('_uid', $userId);
5390
            Session::write('_user', $userInfo);
5391
            Session::write('is_platformAdmin', (bool) self::is_admin($userId));
5392
            Session::write('is_allowedCreateCourse', 1 == $userInfo['status']);
5393
            // will be useful later to know if the user is actually an admin or not (example reporting)
5394
            Session::write('login_as', true);
5395
            $logInfo = [
5396
                'tool' => 'login',
5397
                'tool_id' => 0,
5398
                'tool_id_detail' => 0,
5399
                'info' => $userId,
5400
            ];
5401
            Event::registerLog($logInfo);
5402
5403
            return true;
5404
        }
5405
5406
        return false;
5407
    }
5408
5409
    /**
5410
     * Remove all login records from the track_e_online stats table,
5411
     * for the given user ID.
5412
     *
5413
     * @param int $userId User ID
5414
     */
5415
    public static function loginDelete($userId)
5416
    {
5417
        $online_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ONLINE);
5418
        $userId = (int) $userId;
5419
        $query = "DELETE FROM $online_table WHERE login_user_id = $userId";
5420
        Database::query($query);
5421
    }
5422
5423
    /**
5424
     * Login as first admin user registered in the platform.
5425
     *
5426
     * @return array
5427
     */
5428
    public static function logInAsFirstAdmin()
5429
    {
5430
        $adminList = self::get_all_administrators();
5431
5432
        if (!empty($adminList)) {
5433
            $userInfo = current($adminList);
5434
            if (!empty($userInfo)) {
5435
                $result = self::loginAsUser($userInfo['user_id'], false);
5436
                if ($result && api_is_platform_admin()) {
5437
                    return api_get_user_info();
0 ignored issues
show
Bug Best Practice introduced by
The expression return api_get_user_info() could also return false which is incompatible with the documented return type array. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
5438
                }
5439
            }
5440
        }
5441
5442
        return [];
5443
    }
5444
5445
    /**
5446
     * Check if user is teacher of a student based in their courses.
5447
     *
5448
     * @param $teacherId
5449
     * @param $studentId
5450
     *
5451
     * @return array
5452
     */
5453
    public static function getCommonCoursesBetweenTeacherAndStudent($teacherId, $studentId)
5454
    {
5455
        $courses = CourseManager::getCoursesFollowedByUser(
5456
            $teacherId,
5457
            COURSEMANAGER
5458
        );
5459
        if (empty($courses)) {
5460
            return false;
5461
        }
5462
5463
        $coursesFromUser = CourseManager::get_courses_list_by_user_id($studentId);
5464
        if (empty($coursesFromUser)) {
5465
            return false;
5466
        }
5467
5468
        $coursesCodeList = array_column($courses, 'code');
5469
        $coursesCodeFromUserList = array_column($coursesFromUser, 'code');
5470
        $commonCourses = array_intersect($coursesCodeList, $coursesCodeFromUserList);
5471
        $commonCourses = array_filter($commonCourses);
5472
5473
        if (!empty($commonCourses)) {
5474
            return $commonCourses;
5475
        }
5476
5477
        return [];
5478
    }
5479
5480
    /**
5481
     * @param int $teacherId
5482
     * @param int $studentId
5483
     *
5484
     * @return bool
5485
     */
5486
    public static function isTeacherOfStudent($teacherId, $studentId)
5487
    {
5488
        $courses = self::getCommonCoursesBetweenTeacherAndStudent(
5489
            $teacherId,
5490
            $studentId
5491
        );
5492
5493
        if (!empty($courses)) {
5494
            return true;
5495
        }
5496
5497
        return false;
5498
    }
5499
5500
    /**
5501
     * Send user confirmation mail.
5502
     *
5503
     * @throws Exception
5504
     */
5505
    public static function sendUserConfirmationMail(User $user)
5506
    {
5507
        $uniqueId = api_get_unique_id();
5508
        $user->setConfirmationToken($uniqueId);
5509
5510
        Database::getManager()->persist($user);
5511
        Database::getManager()->flush();
5512
5513
        $url = api_get_path(WEB_CODE_PATH).'auth/user_mail_confirmation.php?token='.$uniqueId;
5514
5515
        // Check if the user was originally set for an automated subscription to a course or session
5516
        $courseCodeToRedirect = Session::read('course_redirect');
5517
        $sessionToRedirect = Session::read('session_redirect');
5518
        if (!empty($courseCodeToRedirect)) {
5519
            $url .= '&c='.$courseCodeToRedirect;
5520
        }
5521
        if (!empty($sessionToRedirect)) {
5522
            $url .= '&s='.$sessionToRedirect;
5523
        }
5524
        $mailSubject = get_lang('Registration confirmation');
5525
        $mailBody = get_lang('Registration confirmationEmailMessage')
5526
            .PHP_EOL
5527
            .Display::url($url, $url);
5528
5529
        api_mail_html(
5530
            self::formatUserFullName($user),
5531
            $user->getEmail(),
5532
            $mailSubject,
5533
            $mailBody
5534
        );
5535
        Display::addFlash(Display::return_message(get_lang('Check your e-mail and follow the instructions.')));
5536
    }
5537
5538
    /**
5539
     * Anonymize a user. Replace personal info by anonymous info.
5540
     *
5541
     * @param int  $userId   User id
5542
     * @param bool $deleteIP Whether to replace the IP address in logs tables by 127.0.0.1 or to leave as is
5543
     *
5544
     * @throws \Exception
5545
     *
5546
     * @return bool
5547
     * @assert (0) === false
5548
     */
5549
    public static function anonymize($userId, $deleteIP = true)
5550
    {
5551
        global $debug;
5552
5553
        $userId = (int) $userId;
5554
5555
        if (empty($userId)) {
5556
            return false;
5557
        }
5558
5559
        $em = Database::getManager();
5560
        $user = api_get_user_entity($userId);
5561
        $uniqueId = uniqid('anon', true);
5562
        $user
5563
            ->setFirstname($uniqueId)
5564
            ->setLastname($uniqueId)
5565
            ->setBiography('')
5566
            ->setAddress('')
5567
            //->setCurriculumItems(null)
5568
            ->setDateOfBirth(null)
5569
            ->setCompetences('')
5570
            ->setDiplomas('')
5571
            ->setOpenarea('')
5572
            ->setTeach('')
5573
            ->setProductions(null)
5574
            ->setOpenid('')
5575
            ->setEmailCanonical($uniqueId.'@example.com')
5576
            ->setEmail($uniqueId.'@example.com')
5577
            ->setUsername($uniqueId)
5578
            ->setUsernameCanonical($uniqueId)
5579
            ->setPhone('')
5580
            ->setOfficialCode('')
5581
        ;
5582
5583
        self::deleteUserPicture($userId);
5584
        self::cleanUserRequestsOfRemoval($userId);
5585
5586
        // The IP address is a border-case personal data, as it does
5587
        // not directly allow for personal identification (it is not
5588
        // a completely safe value in most countries - the IP could
5589
        // be used by neighbours and crackers)
5590
        if ($deleteIP) {
5591
            $substitute = '127.0.0.1';
5592
            $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
5593
            $sql = "UPDATE $table set user_ip = '$substitute' WHERE access_user_id = $userId";
5594
            $res = Database::query($sql);
5595
            if (false === $res && $debug > 0) {
5596
                error_log("Could not anonymize IP address for user $userId ($sql)");
5597
            }
5598
5599
            $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5600
            $sql = "UPDATE $table set user_ip = '$substitute' WHERE user_id = $userId";
5601
            $res = Database::query($sql);
5602
            if (false === $res && $debug > 0) {
5603
                error_log("Could not anonymize IP address for user $userId ($sql)");
5604
            }
5605
5606
            $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
5607
            $sql = "UPDATE $table set user_ip = '$substitute' WHERE exe_user_id = $userId";
5608
            $res = Database::query($sql);
5609
            if (false === $res && $debug > 0) {
5610
                error_log("Could not anonymize IP address for user $userId ($sql)");
5611
            }
5612
5613
            $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
5614
            $sql = "UPDATE $table set user_ip = '$substitute' WHERE login_user_id = $userId";
5615
            $res = Database::query($sql);
5616
            if (false === $res && $debug > 0) {
5617
                error_log("Could not anonymize IP address for user $userId ($sql)");
5618
            }
5619
5620
            $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ONLINE);
5621
            $sql = "UPDATE $table set user_ip = '$substitute' WHERE login_user_id = $userId";
5622
            $res = Database::query($sql);
5623
            if (false === $res && $debug > 0) {
5624
                error_log("Could not anonymize IP address for user $userId ($sql)");
5625
            }
5626
5627
            $table = Database::get_course_table(TABLE_WIKI);
5628
            $sql = "UPDATE $table set user_ip = '$substitute' WHERE user_id = $userId";
5629
            $res = Database::query($sql);
5630
            if (false === $res && $debug > 0) {
5631
                error_log("Could not anonymize IP address for user $userId ($sql)");
5632
            }
5633
5634
            $table = Database::get_main_table(TABLE_TICKET_MESSAGE);
5635
            $sql = "UPDATE $table set ip_address = '$substitute' WHERE sys_insert_user_id = $userId";
5636
            $res = Database::query($sql);
5637
            if (false === $res && $debug > 0) {
5638
                error_log("Could not anonymize IP address for user $userId ($sql)");
5639
            }
5640
5641
            $table = Database::get_course_table(TABLE_WIKI);
5642
            $sql = "UPDATE $table set user_ip = '$substitute' WHERE user_id = $userId";
5643
            $res = Database::query($sql);
5644
            if (false === $res && $debug > 0) {
5645
                error_log("Could not anonymize IP address for user $userId ($sql)");
5646
            }
5647
        }
5648
        $em->persist($user);
5649
        $em->flush();
5650
        Event::addEvent(LOG_USER_ANONYMIZE, LOG_USER_ID, $userId);
5651
5652
        return true;
5653
    }
5654
5655
    /**
5656
     * @param int $userId
5657
     *
5658
     * @throws Exception
5659
     *
5660
     * @return string
5661
     */
5662
    public static function anonymizeUserWithVerification($userId)
5663
    {
5664
        $allowDelete = api_get_configuration_value('allow_delete_user_for_session_admin');
5665
5666
        $message = '';
5667
        if (api_is_platform_admin() ||
5668
            ($allowDelete && api_is_session_admin())
5669
        ) {
5670
            $userToUpdateInfo = api_get_user_info($userId);
5671
            $currentUserId = api_get_user_id();
5672
5673
            if ($userToUpdateInfo &&
5674
                api_global_admin_can_edit_admin($userId, null, $allowDelete)
5675
            ) {
5676
                if ($userId != $currentUserId &&
5677
                    self::anonymize($userId)
5678
                ) {
5679
                    $message = Display::return_message(
5680
                        sprintf(get_lang('User %s information anonymized.'), $userToUpdateInfo['complete_name_with_username']),
5681
                        'confirmation'
5682
                    );
5683
                } else {
5684
                    $message = Display::return_message(
5685
                        sprintf(get_lang('We could not anonymize user %s information. Please try again or check the logs.'), $userToUpdateInfo['complete_name_with_username']),
5686
                        'error'
5687
                    );
5688
                }
5689
            } else {
5690
                $message = Display::return_message(
5691
                    sprintf(get_lang('You don\'t have permissions to anonymize user %s. You need the same permissions as to delete users.'), $userToUpdateInfo['complete_name_with_username']),
5692
                    'error'
5693
                );
5694
            }
5695
        }
5696
5697
        return $message;
5698
    }
5699
5700
    /**
5701
     * @param int $userId
5702
     *
5703
     * @throws Exception
5704
     *
5705
     * @return string
5706
     */
5707
    public static function deleteUserWithVerification($userId)
5708
    {
5709
        $allowDelete = api_get_configuration_value('allow_delete_user_for_session_admin');
5710
        $message = Display::return_message(get_lang('You cannot delete this user'), 'error');
5711
        $userToUpdateInfo = api_get_user_info($userId);
5712
5713
        // User must exist.
5714
        if (empty($userToUpdateInfo)) {
5715
            return $message;
5716
        }
5717
5718
        $currentUserId = api_get_user_id();
5719
5720
        // Cannot delete myself.
5721
        if ($userId == $currentUserId) {
5722
            return $message;
5723
        }
5724
5725
        if (api_is_platform_admin() ||
5726
            ($allowDelete && api_is_session_admin())
5727
        ) {
5728
            if (api_global_admin_can_edit_admin($userId, null, $allowDelete)) {
5729
                if (self::delete_user($userId)) {
5730
                    $message = Display::return_message(
5731
                        get_lang('The user has been deleted').': '.$userToUpdateInfo['complete_name_with_username'],
5732
                        'confirmation'
5733
                    );
5734
                } else {
5735
                    $message = Display::return_message(get_lang('You cannot delete this userBecauseOwnsCourse'), 'error');
5736
                }
5737
            }
5738
        }
5739
5740
        return $message;
5741
    }
5742
5743
    /**
5744
     * @return array
5745
     */
5746
    public static function createDataPrivacyExtraFields()
5747
    {
5748
        self::create_extra_field(
5749
            'request_for_legal_agreement_consent_removal_justification',
5750
            1, //text
5751
            'Request for legal agreement consent removal justification	',
5752
            ''
5753
        );
5754
5755
        self::create_extra_field(
5756
            'request_for_delete_account_justification',
5757
            1, //text
5758
            'Request for delete account justification',
5759
            ''
5760
        );
5761
5762
        $extraFieldId = self::create_extra_field(
5763
            'request_for_legal_agreement_consent_removal',
5764
            1, //text
5765
            'Request for legal agreement consent removal',
5766
            ''
5767
        );
5768
5769
        $extraFieldIdDeleteAccount = self::create_extra_field(
5770
            'request_for_delete_account',
5771
            1, //text
5772
            'Request for delete user account',
5773
            ''
5774
        );
5775
5776
        return [
5777
            'delete_account_extra_field' => $extraFieldIdDeleteAccount,
5778
            'delete_legal' => $extraFieldId,
5779
        ];
5780
    }
5781
5782
    /**
5783
     * @param int $userId
5784
     */
5785
    public static function cleanUserRequestsOfRemoval($userId)
5786
    {
5787
        $userId = (int) $userId;
5788
5789
        $extraFieldValue = new ExtraFieldValue('user');
5790
        $extraFieldsToDelete = [
5791
            'legal_accept',
5792
            'request_for_legal_agreement_consent_removal',
5793
            'request_for_legal_agreement_consent_removal_justification',
5794
            'request_for_delete_account_justification', // just in case delete also this
5795
            'request_for_delete_account',
5796
        ];
5797
5798
        foreach ($extraFieldsToDelete as $variable) {
5799
            $value = $extraFieldValue->get_values_by_handler_and_field_variable(
5800
                $userId,
5801
                $variable
5802
            );
5803
            if ($value && isset($value['id'])) {
5804
                $extraFieldValue->delete($value['id']);
5805
            }
5806
        }
5807
    }
5808
5809
    /**
5810
     * @param int $searchYear
5811
     *
5812
     * @throws Exception
5813
     *
5814
     * @return array
5815
     */
5816
    public static function getSubscribedSessionsByYear(array $userInfo, $searchYear)
5817
    {
5818
        $timezone = new DateTimeZone(api_get_timezone());
5819
5820
        $sessions = [];
5821
        if (DRH == $userInfo['status']) {
5822
            $sessions = SessionManager::get_sessions_followed_by_drh($userInfo['id']);
5823
        } elseif (api_is_platform_admin(true)) {
5824
            $sessions = SessionManager::getSessionsForAdmin($userInfo['id']);
5825
        } else {
5826
            $sessionsByCategory = self::get_sessions_by_category($userInfo['id'], false, true, true);
5827
            $sessionsByCategory = array_column($sessionsByCategory, 'sessions');
5828
5829
            foreach ($sessionsByCategory as $sessionsInCategory) {
5830
                $sessions = array_merge($sessions, $sessionsInCategory);
5831
            }
5832
        }
5833
5834
        $sessions = array_map(
5835
            function ($sessionInfo) {
5836
                if (!isset($sessionInfo['session_id'])) {
5837
                    $sessionInfo['session_id'] = $sessionInfo['id'];
5838
                }
5839
                if (!isset($sessionInfo['session_name'])) {
5840
                    $sessionInfo['session_name'] = $sessionInfo['name'];
5841
                }
5842
5843
                return $sessionInfo;
5844
            },
5845
            $sessions
5846
        );
5847
5848
        $calendarSessions = [];
5849
5850
        foreach ($sessions as $sessionInfo) {
5851
            if (!empty($sessionInfo['duration'])) {
5852
                $courseAccess = CourseManager::getFirstCourseAccessPerSessionAndUser(
5853
                    $sessionInfo['session_id'],
5854
                    $userInfo['id']
5855
                );
5856
5857
                if (empty($courseAccess)) {
5858
                    continue;
5859
                }
5860
5861
                $firstAcessDate = new DateTime(api_get_local_time($courseAccess['login_course_date']), $timezone);
5862
                $lastAccessDate = clone $firstAcessDate;
5863
                $lastAccessDate->modify("+{$sessionInfo['duration']} days");
5864
5865
                $firstAccessYear = (int) $firstAcessDate->format('Y');
5866
                $lastAccessYear = (int) $lastAccessDate->format('Y');
5867
5868
                if ($firstAccessYear <= $searchYear && $lastAccessYear >= $searchYear) {
5869
                    $calendarSessions[$sessionInfo['session_id']] = [
5870
                        'name' => $sessionInfo['session_name'],
5871
                        'access_start_date' => $firstAcessDate->format('Y-m-d h:i:s'),
5872
                        'access_end_date' => $lastAccessDate->format('Y-m-d h:i:s'),
5873
                    ];
5874
                }
5875
5876
                continue;
5877
            }
5878
5879
            $accessStartDate = !empty($sessionInfo['access_start_date'])
5880
                ? new DateTime(api_get_local_time($sessionInfo['access_start_date']), $timezone)
5881
                : null;
5882
            $accessEndDate = !empty($sessionInfo['access_end_date'])
5883
                ? new DateTime(api_get_local_time($sessionInfo['access_end_date']), $timezone)
5884
                : null;
5885
            $accessStartYear = $accessStartDate ? (int) $accessStartDate->format('Y') : 0;
5886
            $accessEndYear = $accessEndDate ? (int) $accessEndDate->format('Y') : 0;
5887
5888
            $isValid = false;
5889
5890
            if ($accessStartYear && $accessEndYear) {
5891
                if ($accessStartYear <= $searchYear && $accessEndYear >= $searchYear) {
5892
                    $isValid = true;
5893
                }
5894
            }
5895
5896
            if ($accessStartYear && !$accessEndYear) {
5897
                if ($accessStartYear == $searchYear) {
5898
                    $isValid = true;
5899
                }
5900
            }
5901
5902
            if (!$accessStartYear && $accessEndYear) {
5903
                if ($accessEndYear == $searchYear) {
5904
                    $isValid = true;
5905
                }
5906
            }
5907
5908
            if ($isValid) {
5909
                $calendarSessions[$sessionInfo['session_id']] = [
5910
                    'name' => $sessionInfo['session_name'],
5911
                    'access_start_date' => $accessStartDate ? $accessStartDate->format('Y-m-d h:i:s') : null,
5912
                    'access_end_date' => $accessEndDate ? $accessEndDate->format('Y-m-d h:i:s') : null,
5913
                ];
5914
            }
5915
        }
5916
5917
        return $calendarSessions;
5918
    }
5919
5920
    /**
5921
     * Get sessions info for planification calendar.
5922
     *
5923
     * @param array $sessionsList Session list from UserManager::getSubscribedSessionsByYear
5924
     * @param int   $searchYear
5925
     *
5926
     * @throws Exception
5927
     *
5928
     * @return array
5929
     */
5930
    public static function getSessionsCalendarByYear(array $sessionsList, $searchYear)
5931
    {
5932
        $timezone = new DateTimeZone(api_get_timezone());
5933
        $calendar = [];
5934
5935
        foreach ($sessionsList as $sessionId => $sessionInfo) {
5936
            $startDate = $sessionInfo['access_start_date']
5937
                ? new DateTime(api_get_local_time($sessionInfo['access_start_date']), $timezone)
5938
                : null;
5939
            $endDate = $sessionInfo['access_end_date']
5940
                ? new DateTime(api_get_local_time($sessionInfo['access_end_date']), $timezone)
5941
                : null;
5942
5943
            $startYear = $startDate ? (int) $startDate->format('Y') : 0;
5944
            $startWeekYear = $startDate ? (int) $startDate->format('o') : 0;
5945
            $startWeek = $startDate ? (int) $startDate->format('W') : 0;
5946
            $endYear = $endDate ? (int) $endDate->format('Y') : 0;
5947
            $endWeekYear = $endDate ? (int) $endDate->format('o') : 0;
5948
            $endWeek = $endDate ? (int) $endDate->format('W') : 0;
5949
5950
            $start = $startWeekYear < $searchYear ? 0 : $startWeek - 1;
5951
            $duration = $endWeekYear > $searchYear ? 52 - $start : $endWeek - $start;
5952
5953
            $calendar[] = [
5954
                'id' => $sessionId,
5955
                'name' => $sessionInfo['name'],
5956
                'human_date' => SessionManager::convertSessionDateToString($startDate, $endDate, false, true),
5957
                'start_in_last_year' => $startYear < $searchYear,
5958
                'end_in_next_year' => $endYear > $searchYear,
5959
                'no_start' => !$startWeek,
5960
                'no_end' => !$endWeek,
5961
                'start' => $start,
5962
                'duration' => $duration > 0 ? $duration : 1,
5963
            ];
5964
        }
5965
5966
        usort(
5967
            $calendar,
5968
            function ($sA, $sB) {
5969
                if ($sA['start'] == $sB['start']) {
5970
                    return 0;
5971
                }
5972
5973
                if ($sA['start'] < $sB['start']) {
5974
                    return -1;
5975
                }
5976
5977
                return 1;
5978
            }
5979
        );
5980
5981
        return $calendar;
5982
    }
5983
5984
    /**
5985
     * Return the user's full name. Optionally with the username.
5986
     */
5987
    public static function formatUserFullName(User $user, bool $includeUsername = false): string
5988
    {
5989
        $fullName = api_get_person_name($user->getFirstname(), $user->getLastname());
5990
5991
        if ($includeUsername && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
5992
            $username = $user->getUsername();
5993
5994
            return "$fullName ($username)";
5995
        }
5996
5997
        return $fullName;
5998
    }
5999
6000
    /**
6001
     * @param int $userId
6002
     *
6003
     * @return array
6004
     */
6005
    public static function getUserCareers($userId)
6006
    {
6007
        $table = Database::get_main_table(TABLE_MAIN_USER_CAREER);
6008
        $tableCareer = Database::get_main_table(TABLE_CAREER);
6009
        $userId = (int) $userId;
6010
6011
        $sql = "SELECT c.id, c.name
6012
                FROM $table uc
6013
                INNER JOIN $tableCareer c
6014
                ON uc.career_id = c.id
6015
                WHERE user_id = $userId
6016
                ORDER BY uc.created_at
6017
                ";
6018
        $result = Database::query($sql);
6019
6020
        return Database::store_result($result, 'ASSOC');
6021
    }
6022
6023
    /**
6024
     * @param int $userId
6025
     * @param int $careerId
6026
     */
6027
    public static function addUserCareer($userId, $careerId)
6028
    {
6029
        if (!api_get_configuration_value('allow_career_users')) {
6030
            return false;
6031
        }
6032
6033
        if (false === self::userHasCareer($userId, $careerId)) {
6034
            $params = ['user_id' => $userId, 'career_id' => $careerId, 'created_at' => api_get_utc_datetime(), 'updated_at' => api_get_utc_datetime()];
6035
            $table = Database::get_main_table(TABLE_MAIN_USER_CAREER);
6036
            Database::insert($table, $params);
6037
        }
6038
6039
        return true;
6040
    }
6041
6042
    /**
6043
     * @param int   $userCareerId
6044
     * @param array $data
6045
     *
6046
     * @return bool
6047
     */
6048
    public static function updateUserCareer($userCareerId, $data)
6049
    {
6050
        if (!api_get_configuration_value('allow_career_users')) {
6051
            return false;
6052
        }
6053
6054
        $params = ['extra_data' => $data, 'updated_at' => api_get_utc_datetime()];
6055
        $table = Database::get_main_table(TABLE_MAIN_USER_CAREER);
6056
        Database::update(
6057
            $table,
6058
            $params,
6059
            ['id = ?' => (int) $userCareerId]
6060
        );
6061
6062
        return true;
6063
    }
6064
6065
    /**
6066
     * @param int $userId
6067
     * @param int $careerId
6068
     *
6069
     * @return array
6070
     */
6071
    public static function getUserCareer($userId, $careerId)
6072
    {
6073
        $userId = (int) $userId;
6074
        $careerId = (int) $careerId;
6075
        $table = Database::get_main_table(TABLE_MAIN_USER_CAREER);
6076
6077
        $sql = "SELECT * FROM $table WHERE user_id = $userId AND career_id = $careerId";
6078
        $result = Database::query($sql);
6079
6080
        return Database::fetch_array($result, 'ASSOC');
6081
    }
6082
6083
    /**
6084
     * @param int $userId
6085
     * @param int $careerId
6086
     *
6087
     * @return bool
6088
     */
6089
    public static function userHasCareer($userId, $careerId)
6090
    {
6091
        $userId = (int) $userId;
6092
        $careerId = (int) $careerId;
6093
        $table = Database::get_main_table(TABLE_MAIN_USER_CAREER);
6094
6095
        $sql = "SELECT id FROM $table WHERE user_id = $userId AND career_id = $careerId";
6096
        $result = Database::query($sql);
6097
6098
        return Database::num_rows($result) > 0;
6099
    }
6100
6101
    /**
6102
     * Disables or enables a user.
6103
     *
6104
     * @param int $user_id
6105
     * @param int $active  Enable or disable
6106
     *
6107
     * @return bool True on success, false on failure
6108
     * @assert (-1,0) === false
6109
     * @assert (1,1) === true
6110
     */
6111
    private static function change_active_state($user_id, $active)
6112
    {
6113
        $user_id = (int) $user_id;
6114
        $active = (int) $active;
6115
6116
        if (empty($user_id)) {
6117
            return false;
6118
        }
6119
6120
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
6121
        $sql = "UPDATE $table_user SET active = '$active' WHERE id = $user_id";
6122
        $r = Database::query($sql);
6123
        $ev = LOG_USER_DISABLE;
6124
        if (1 == $active) {
6125
            $ev = LOG_USER_ENABLE;
6126
        }
6127
        if (false !== $r) {
6128
            Event::addEvent($ev, LOG_USER_ID, $user_id);
6129
        }
6130
6131
        return $r;
6132
    }
6133
6134
    /**
6135
     * Get either a Gravatar URL or complete image tag for a specified email address.
6136
     *
6137
     * @param string $email The email address
6138
     * @param int    $s     Size in pixels, defaults to 80px [ 1 - 2048 ]
6139
     * @param string $d     Default imageset to use [ 404 | mm | identicon | monsterid | wavatar ]
6140
     * @param string $r     Maximum rating (inclusive) [ g | pg | r | x ]
6141
     * @param bool   $img   True to return a complete IMG tag False for just the URL
6142
     * @param array  $atts  Optional, additional key/value attributes to include in the IMG tag
6143
     *
6144
     * @return string containing either just a URL or a complete image tag
6145
     * @source http://gravatar.com/site/implement/images/php/
6146
     */
6147
    private static function getGravatar(
0 ignored issues
show
Unused Code introduced by
The method getGravatar() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
6148
        $email,
6149
        $s = 80,
6150
        $d = 'mm',
6151
        $r = 'g',
6152
        $img = false,
6153
        $atts = []
6154
    ) {
6155
        $url = 'http://www.gravatar.com/avatar/';
6156
        if (!empty($_SERVER['HTTPS'])) {
6157
            $url = 'https://secure.gravatar.com/avatar/';
6158
        }
6159
        $url .= md5(strtolower(trim($email)));
6160
        $url .= "?s=$s&d=$d&r=$r";
6161
        if ($img) {
6162
            $url = '<img src="'.$url.'"';
6163
            foreach ($atts as $key => $val) {
6164
                $url .= ' '.$key.'="'.$val.'"';
6165
            }
6166
            $url .= ' />';
6167
        }
6168
6169
        return $url;
6170
    }
6171
}
6172