Passed
Push — master ( 954b89...f7e68c )
by Julito
07:20
created

UserManager::change_active_state()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

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

62
        /** @scrutinizer ignore-call */ 
63
        $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...
63
64
        return $hasher->isPasswordValid($user, $plainPassword);
65
    }
66
67
    /**
68
     * @param int    $userId
69
     * @param string $password
70
     */
71
    public static function updatePassword($userId, $password)
72
    {
73
        $user = api_get_user_entity($userId);
74
        $userManager = self::getRepository();
75
        $user->setPlainPassword($password);
76
        $userManager->updateUser($user, true);
77
    }
78
79
    /**
80
     * Creates a new user for the platform.
81
     *
82
     * @author Hugues Peeters <[email protected]>,
83
     * @author Roan Embrechts <[email protected]>
84
     *
85
     * @param string        $firstName
86
     * @param string        $lastName
87
     * @param int           $status                  (1 for course tutor, 5 for student, 6 for anonymous)
88
     * @param string        $email
89
     * @param string        $loginName
90
     * @param string        $password
91
     * @param string        $official_code           Any official code (optional)
92
     * @param string        $language                User language    (optional)
93
     * @param string        $phone                   Phone number    (optional)
94
     * @param string        $picture_uri             Picture URI        (optional)
95
     * @param string        $authSource              Authentication source (defaults to 'platform', dependind on constant)
96
     * @param string        $expirationDate          Account expiration date (optional, defaults to null)
97
     * @param int           $active                  Whether the account is enabled or disabled by default
98
     * @param int           $hr_dept_id              The department of HR in which the user is registered (defaults to 0)
99
     * @param array         $extra                   Extra fields (labels must be prefixed by "extra_")
100
     * @param string        $encrypt_method          Used if password is given encrypted. Set to an empty string by default
101
     * @param bool          $send_mail
102
     * @param bool          $isAdmin
103
     * @param string        $address
104
     * @param bool          $sendEmailToAllAdmins
105
     * @param FormValidator $form
106
     * @param int           $creatorId
107
     * @param array         $emailTemplate
108
     * @param string        $redirectToURLAfterLogin
109
     *
110
     * @return mixed new user id - if the new user creation succeeds, false otherwise
111
     * @desc The function tries to retrieve user id from the session.
112
     * If it exists, the current user id is the creator id. If a problem arises,
113
     * @assert ('Sam','Gamegie',5,'[email protected]','jo','jo') > 1
114
     * @assert ('Pippin','Took',null,null,'jo','jo') === false
115
     */
116
    public static function create_user(
117
        $firstName,
118
        $lastName,
119
        $status,
120
        $email,
121
        $loginName,
122
        $password,
123
        $official_code = '',
124
        $language = '',
125
        $phone = '',
126
        $picture_uri = '',
127
        $authSource = null,
128
        $expirationDate = null,
129
        $active = 1,
130
        $hr_dept_id = 0,
131
        $extra = [],
132
        $encrypt_method = '',
133
        $send_mail = false,
134
        $isAdmin = false,
135
        $address = '',
136
        $sendEmailToAllAdmins = false,
137
        $form = null,
138
        $creatorId = 0,
139
        $emailTemplate = [],
140
        $redirectToURLAfterLogin = ''
141
    ) {
142
        $authSource = !empty($authSource) ? $authSource : PLATFORM_AUTH_SOURCE;
143
        $creatorId = empty($creatorId) ? api_get_user_id() : 0;
144
145
        if (0 === $creatorId) {
146
            Display::addFlash(
147
                Display::return_message(get_lang('A user creator is needed'))
148
            );
149
150
            return false;
151
        }
152
153
        $creatorInfo = api_get_user_info($creatorId);
154
        $creatorEmail = $creatorInfo['email'] ?? '';
155
156
        // First check if the login exists.
157
        if (!self::is_username_available($loginName)) {
158
            Display::addFlash(
159
                Display::return_message(get_lang('This login is already taken !'))
160
            );
161
162
            return false;
163
        }
164
165
        global $_configuration;
166
        $original_password = $password;
167
168
        $access_url_id = 1;
169
        if (api_get_multiple_access_url()) {
170
            $access_url_id = api_get_current_access_url_id();
171
        } else {
172
            // In some cases, the first access_url ID might be different from 1
173
            // for example when using a DB cluster or hacking the DB manually.
174
            // In this case, we want the first row, not necessarily "1".
175
            $accessUrlRepository = Container::getAccessUrlRepository();
176
            $accessUrl = $accessUrlRepository->getFirstId();
177
            if (!empty($accessUrl[0]) && !empty($accessUrl[0][1])) {
178
                $access_url_id = $accessUrl[0][1];
179
            }
180
        }
181
182
        if (isset($_configuration[$access_url_id]) &&
183
            is_array($_configuration[$access_url_id]) &&
184
            isset($_configuration[$access_url_id]['hosting_limit_users']) &&
185
            $_configuration[$access_url_id]['hosting_limit_users'] > 0) {
186
            $num = self::get_number_of_users();
187
            if ($num >= $_configuration[$access_url_id]['hosting_limit_users']) {
188
                api_warn_hosting_contact('hosting_limit_users');
189
                Display::addFlash(
190
                    Display::return_message(
191
                        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.'),
192
                        'warning'
193
                    )
194
                );
195
196
                return false;
197
            }
198
        }
199
200
        if (1 === $status &&
201
            isset($_configuration[$access_url_id]) &&
202
            is_array($_configuration[$access_url_id]) &&
203
            isset($_configuration[$access_url_id]['hosting_limit_teachers']) &&
204
            $_configuration[$access_url_id]['hosting_limit_teachers'] > 0
205
        ) {
206
            $num = self::get_number_of_users(1);
207
            if ($num >= $_configuration[$access_url_id]['hosting_limit_teachers']) {
208
                Display::addFlash(
209
                    Display::return_message(
210
                        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.'),
211
                        'warning'
212
                    )
213
                );
214
                api_warn_hosting_contact('hosting_limit_teachers');
215
216
                return false;
217
            }
218
        }
219
220
        if (empty($password)) {
221
            if (PLATFORM_AUTH_SOURCE === $authSource) {
222
                Display::addFlash(
223
                    Display::return_message(
224
                        get_lang('Required field').': '.get_lang(
225
                            'Password'
226
                        ),
227
                        'warning'
228
                    )
229
                );
230
231
                return false;
232
            }
233
234
            // We use the authSource as password.
235
            // The real validation will be by processed by the auth
236
            // source not Chamilo
237
            $password = $authSource;
238
        }
239
240
        // Checking the user language
241
        $languages = api_get_languages();
242
243
        // Default to english
244
        if (!in_array($language, array_keys($languages), true)) {
245
            $language = 'en_US';
246
        }
247
248
        $now = new DateTime();
249
        if (empty($expirationDate) || '0000-00-00 00:00:00' === $expirationDate) {
250
            $expirationDate = null;
251
        // Default expiration date
252
            // if there is a default duration of a valid account then
253
            // we have to change the expiration_date accordingly
254
            // Accept 0000-00-00 00:00:00 as a null value to avoid issues with
255
            // third party code using this method with the previous (pre-1.10)
256
            // value of 0000...
257
            /*if ('' != api_get_setting('account_valid_duration')) {
258
                $expirationDate = new DateTime($currentDate);
259
                $days = (int) api_get_setting('account_valid_duration');
260
                $expirationDate->modify('+'.$days.' day');
261
            }*/
262
        } else {
263
            $expirationDate = api_get_utc_datetime($expirationDate, true, true);
264
        }
265
266
        $repo = Container::getUserRepository();
267
        $user = $repo->createUser()
268
            ->setLastname($lastName)
269
            ->setFirstname($firstName)
270
            ->setUsername($loginName)
271
            ->setStatus($status)
272
            ->setPlainPassword($password)
273
            ->setEmail($email)
274
            ->setOfficialCode($official_code)
275
            ->setCreatorId($creatorId)
276
            ->setAuthSource($authSource)
277
            ->setPhone($phone)
278
            ->setAddress($address)
279
            ->setLocale($language)
280
            ->setRegistrationDate($now)
281
            ->setHrDeptId($hr_dept_id)
282
            ->setActive($active)
283
            ->setEnabled($active)
284
            ->setTimezone(api_get_timezone())
285
        ;
286
287
        if (null !== $expirationDate) {
288
            $user->setExpirationDate($expirationDate);
289
        }
290
291
        // Add user to a group
292
        $statusToGroup = [
293
            COURSEMANAGER => 'TEACHER',
294
            STUDENT => 'STUDENT',
295
            DRH => 'RRHH',
296
            SESSIONADMIN => 'SESSION_ADMIN',
297
            STUDENT_BOSS => 'STUDENT_BOSS',
298
            INVITEE => 'INVITEE',
299
        ];
300
301
        if (isset($statusToGroup[$status])) {
302
            $group = Container::$container->get(GroupRepository::class)->findOneBy(['code' => $statusToGroup[$status]]);
303
            if ($group) {
304
                $user->addGroup($group);
305
            }
306
        }
307
308
        $repo->updateUser($user, true);
309
310
        $userId = $user->getId();
311
312
        if (!empty($userId)) {
313
            if ($isAdmin) {
314
                self::addUserAsAdmin($user);
315
            }
316
317
            if (api_get_multiple_access_url()) {
318
                UrlManager::add_user_to_url($userId, api_get_current_access_url_id());
319
            } else {
320
                //we are adding by default the access_url_user table with access_url_id = 1
321
                UrlManager::add_user_to_url($userId, 1);
322
            }
323
324
            if (is_array($extra) && count($extra) > 0) {
325
                $extra['item_id'] = $userId;
326
                $userFieldValue = new ExtraFieldValue('user');
327
                /* Force saving of extra fields (otherwise, if the current
328
                user is not admin, fields not visible to the user - most
329
                of them - are just ignored) */
330
                $userFieldValue->saveFieldValues(
331
                    $extra,
332
                    true,
333
                    null,
334
                    null,
335
                    null,
336
                    true
337
                );
338
            } else {
339
                // Create notify settings by default
340
                self::update_extra_field_value(
341
                    $userId,
342
                    'mail_notify_invitation',
343
                    '1'
344
                );
345
                self::update_extra_field_value(
346
                    $userId,
347
                    'mail_notify_message',
348
                    '1'
349
                );
350
                self::update_extra_field_value(
351
                    $userId,
352
                    'mail_notify_group_message',
353
                    '1'
354
                );
355
            }
356
357
            self::update_extra_field_value(
358
                $userId,
359
                'already_logged_in',
360
                'false'
361
            );
362
363
            if (!empty($redirectToURLAfterLogin) && api_get_configuration_value('plugin_redirection_enabled')) {
364
                RedirectionPlugin::insert($userId, $redirectToURLAfterLogin);
365
            }
366
367
            if (!empty($email) && $send_mail) {
368
                $recipient_name = api_get_person_name(
369
                    $firstName,
370
                    $lastName,
371
                    null,
372
                    PERSON_NAME_EMAIL_ADDRESS
373
                );
374
                $tpl = Container::getTwig();
375
                $emailSubject = $tpl->render('@ChamiloCore/Mailer/Legacy/subject_registration_platform.html.twig');
376
                $sender_name = api_get_person_name(
377
                    api_get_setting('administratorName'),
378
                    api_get_setting('administratorSurname'),
379
                    null,
380
                    PERSON_NAME_EMAIL_ADDRESS
381
                );
382
                $email_admin = api_get_setting('emailAdministrator');
383
384
                $url = api_get_path(WEB_PATH);
385
                if (api_is_multiple_url_enabled()) {
386
                    $access_url_id = api_get_current_access_url_id();
387
                    if (-1 != $access_url_id) {
388
                        $urlInfo = api_get_access_url($access_url_id);
389
                        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...
390
                            $url = $urlInfo['url'];
391
                        }
392
                    }
393
                }
394
395
                // variables for the default template
396
                $params = [
397
                    'complete_name' => stripslashes(api_get_person_name($firstName, $lastName)),
398
                    'login_name' => $loginName,
399
                    'original_password' => stripslashes($original_password),
400
                    'mailWebPath' => $url,
401
                    'new_user' => $user,
402
                ];
403
404
                $emailBody = $tpl->render(
405
                    '@ChamiloCore/Mailer/Legacy/content_registration_platform.html.twig',
406
                    $params
407
                );
408
409
                $userInfo = api_get_user_info($userId);
410
                $mailTemplateManager = new MailTemplateManager();
411
                $phoneNumber = $extra['mobile_phone_number'] ?? null;
412
413
                $additionalParameters = [
414
                    'smsType' => SmsPlugin::WELCOME_LOGIN_PASSWORD,
415
                    'userId' => $userId,
416
                    'mobilePhoneNumber' => $phoneNumber,
417
                    'password' => $original_password,
418
                ];
419
420
                $emailBodyTemplate = '';
421
                if (!empty($emailTemplate)) {
422
                    if (isset($emailTemplate['content_registration_platform.tpl']) &&
423
                        !empty($emailTemplate['content_registration_platform.tpl'])
424
                    ) {
425
                        $emailBodyTemplate = $mailTemplateManager->parseTemplate(
426
                            $emailTemplate['content_registration_platform.tpl'],
427
                            $userInfo
428
                        );
429
                    }
430
                }
431
432
                $twoEmail = api_get_configuration_value('send_two_inscription_confirmation_mail');
433
                if (true === $twoEmail) {
434
                    $emailBody = $tpl->render(
435
                        '@ChamiloCore/Mailer/Legacy/new_user_first_email_confirmation.html.twig'
436
                    );
437
438
                    if (!empty($emailBodyTemplate) &&
439
                        isset($emailTemplate['new_user_first_email_confirmation.tpl']) &&
440
                        !empty($emailTemplate['new_user_first_email_confirmation.tpl'])
441
                    ) {
442
                        $emailBody = $mailTemplateManager->parseTemplate(
443
                            $emailTemplate['new_user_first_email_confirmation.tpl'],
444
                            $userInfo
445
                        );
446
                    }
447
448
                    api_mail_html(
449
                        $recipient_name,
450
                        $email,
451
                        $emailSubject,
452
                        $emailBody,
453
                        $sender_name,
454
                        $email_admin,
455
                        null,
456
                        null,
457
                        null,
458
                        $additionalParameters,
459
                        $creatorEmail
460
                    );
461
462
                    $emailBody = $tpl->render('@ChamiloCore/Mailer/Legacy/new_user_second_email_confirmation.html.twig');
463
464
                    if (!empty($emailBodyTemplate) &&
465
                        isset($emailTemplate['new_user_second_email_confirmation.tpl']) &&
466
                        !empty($emailTemplate['new_user_second_email_confirmation.tpl'])
467
                    ) {
468
                        $emailBody = $mailTemplateManager->parseTemplate(
469
                            $emailTemplate['new_user_second_email_confirmation.tpl'],
470
                            $userInfo
471
                        );
472
                    }
473
474
                    api_mail_html(
475
                        $recipient_name,
476
                        $email,
477
                        $emailSubject,
478
                        $emailBody,
479
                        $sender_name,
480
                        $email_admin,
481
                        null,
482
                        null,
483
                        null,
484
                        $additionalParameters,
485
                        $creatorEmail
486
                    );
487
                } else {
488
                    if (!empty($emailBodyTemplate)) {
489
                        $emailBody = $emailBodyTemplate;
490
                    }
491
                    $sendToInbox = api_get_configuration_value('send_inscription_msg_to_inbox');
492
                    if ($sendToInbox) {
493
                        $adminList = self::get_all_administrators();
494
                        $senderId = 1;
495
                        if (!empty($adminList)) {
496
                            $adminInfo = current($adminList);
497
                            $senderId = $adminInfo['user_id'];
498
                        }
499
500
                        MessageManager::send_message_simple(
501
                            $userId,
502
                            $emailSubject,
503
                            $emailBody,
504
                            $senderId
505
                        );
506
                    } else {
507
                        api_mail_html(
508
                            $recipient_name,
509
                            $email,
510
                            $emailSubject,
511
                            $emailBody,
512
                            $sender_name,
513
                            $email_admin,
514
                            null,
515
                            null,
516
                            null,
517
                            $additionalParameters,
518
                            $creatorEmail
519
                        );
520
                    }
521
                }
522
523
                $notification = api_get_configuration_value('send_notification_when_user_added');
524
                if (!empty($notification) && isset($notification['admins']) && is_array($notification['admins'])) {
525
                    foreach ($notification['admins'] as $adminId) {
526
                        $emailSubjectToAdmin = get_lang('The user has been added').': '.
527
                            api_get_person_name($firstName, $lastName);
528
                        MessageManager::send_message_simple($adminId, $emailSubjectToAdmin, $emailBody, $userId);
529
                    }
530
                }
531
532
                if ($sendEmailToAllAdmins) {
533
                    $adminList = self::get_all_administrators();
534
                    // variables for the default template
535
                    $renderer = FormValidator::getDefaultRenderer();
536
                    // Form template
537
                    $elementTemplate = ' {label}: {element} <br />';
538
                    $renderer->setElementTemplate($elementTemplate);
539
                    /** @var FormValidator $form */
540
                    $form->freeze(null, $elementTemplate);
541
                    $form->removeElement('submit');
542
                    $formData = $form->returnForm();
543
                    $url = api_get_path(WEB_CODE_PATH).'admin/user_information.php?user_id='.$user->getId();
544
                    $params = [
545
                        'complete_name' => stripslashes(api_get_person_name($firstName, $lastName)),
546
                        'user_added' => $user,
547
                        'link' => Display::url($url, $url),
548
                        'form' => $formData,
549
                    ];
550
                    $emailBody = $tpl->render(
551
                        '@ChamiloCore/Mailer/Legacy/content_registration_platform_to_admin.html.twig',
552
                        $params
553
                    );
554
555
                    if (!empty($emailBodyTemplate) &&
556
                        isset($emailTemplate['content_registration_platform_to_admin.tpl']) &&
557
                        !empty($emailTemplate['content_registration_platform_to_admin.tpl'])
558
                    ) {
559
                        $emailBody = $mailTemplateManager->parseTemplate(
560
                            $emailTemplate['content_registration_platform_to_admin.tpl'],
561
                            $userInfo
562
                        );
563
                    }
564
565
                    $subject = get_lang('The user has been added');
566
                    foreach ($adminList as $adminId => $data) {
567
                        MessageManager::send_message_simple(
568
                            $adminId,
569
                            $subject,
570
                            $emailBody,
571
                            $userId
572
                        );
573
                    }
574
                }
575
            }
576
            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

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

1130
            $emailsubject = '['./** @scrutinizer ignore-type */ api_get_setting('siteName').'] '.get_lang('Your registration on').' '.api_get_setting('siteName');
Loading history...
1131
            $sender_name = api_get_person_name(
1132
                api_get_setting('administratorName'),
1133
                api_get_setting('administratorSurname'),
1134
                null,
1135
                PERSON_NAME_EMAIL_ADDRESS
1136
            );
1137
            $email_admin = api_get_setting('emailAdministrator');
1138
            $url = api_get_path(WEB_PATH);
1139
            if (api_is_multiple_url_enabled()) {
1140
                $access_url_id = api_get_current_access_url_id();
1141
                if (-1 != $access_url_id) {
1142
                    $url = api_get_access_url($access_url_id);
1143
                    $url = $url['url'];
1144
                }
1145
            }
1146
1147
            $tplContent = new Template(
1148
                null,
1149
                false,
1150
                false,
1151
                false,
1152
                false,
1153
                false
1154
            );
1155
            // variables for the default template
1156
            $tplContent->assign('complete_name', stripslashes(api_get_person_name($firstname, $lastname)));
1157
            $tplContent->assign('login_name', $username);
1158
1159
            $originalPassword = '';
1160
            if ($reset_password > 0) {
1161
                $originalPassword = stripslashes($original_password);
1162
            }
1163
            $tplContent->assign('original_password', $originalPassword);
1164
            $tplContent->assign('portal_url', $url);
1165
1166
            $layoutContent = $tplContent->get_template('mail/user_edit_content.tpl');
1167
            $emailBody = $tplContent->fetch($layoutContent);
1168
1169
            $mailTemplateManager = new MailTemplateManager();
1170
1171
            if (!empty($emailTemplate) &&
1172
                isset($emailTemplate['user_edit_content.tpl']) &&
1173
                !empty($emailTemplate['user_edit_content.tpl'])
1174
            ) {
1175
                $userInfo = api_get_user_info($user_id);
1176
                $emailBody = $mailTemplateManager->parseTemplate($emailTemplate['user_edit_content.tpl'], $userInfo);
1177
            }
1178
1179
            $creatorInfo = api_get_user_info($creator_id);
1180
            $creatorEmail = isset($creatorInfo['email']) ? $creatorInfo['email'] : '';
1181
1182
            api_mail_html(
1183
                $recipient_name,
1184
                $email,
1185
                $emailsubject,
1186
                $emailBody,
1187
                $sender_name,
1188
                $email_admin,
1189
                null,
1190
                null,
1191
                null,
1192
                null,
1193
                $creatorEmail
1194
            );
1195
        }
1196
1197
        $cacheAvailable = api_get_configuration_value('apc');
1198
        if (true === $cacheAvailable) {
1199
            $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$user_id;
1200
            if (apcu_exists($apcVar)) {
1201
                apcu_delete($apcVar);
1202
            }
1203
        }
1204
1205
        return $user->getId();
1206
    }
1207
1208
    /**
1209
     * Disables a user.
1210
     *
1211
     * @param int User id
1212
     *
1213
     * @return bool
1214
     *
1215
     * @uses \UserManager::change_active_state() to actually disable the user
1216
     * @assert (0) === false
1217
     */
1218
    public static function disable($user_id)
1219
    {
1220
        if (empty($user_id)) {
1221
            return false;
1222
        }
1223
        self::change_active_state($user_id, 0);
1224
1225
        return true;
1226
    }
1227
1228
    /**
1229
     * Enable a user.
1230
     *
1231
     * @param int User id
1232
     *
1233
     * @return bool
1234
     *
1235
     * @uses \UserManager::change_active_state() to actually disable the user
1236
     * @assert (0) === false
1237
     */
1238
    public static function enable($user_id)
1239
    {
1240
        if (empty($user_id)) {
1241
            return false;
1242
        }
1243
        self::change_active_state($user_id, 1);
1244
1245
        return true;
1246
    }
1247
1248
    /**
1249
     * Returns the user's id based on the original id and field name in
1250
     * the extra fields. Returns 0 if no user was found. This function is
1251
     * mostly useful in the context of a web services-based sinchronization.
1252
     *
1253
     * @param string Original user id
1254
     * @param string Original field name
1255
     *
1256
     * @return int User id
1257
     * @assert ('0','---') === 0
1258
     */
1259
    public static function get_user_id_from_original_id(
1260
        $original_user_id_value,
1261
        $original_user_id_name
1262
    ) {
1263
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
1264
        $t_ufv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1265
        $extraFieldType = EntityExtraField::USER_FIELD_TYPE;
1266
1267
        $original_user_id_name = Database::escape_string($original_user_id_name);
1268
        $original_user_id_value = Database::escape_string($original_user_id_value);
1269
1270
        $sql = "SELECT item_id as user_id
1271
                FROM $t_uf uf
1272
                INNER JOIN $t_ufv ufv
1273
                ON ufv.field_id = uf.id
1274
                WHERE
1275
                    variable = '$original_user_id_name' AND
1276
                    value = '$original_user_id_value' AND
1277
                    extra_field_type = $extraFieldType
1278
                ";
1279
        $res = Database::query($sql);
1280
        $row = Database::fetch_object($res);
1281
        if ($row) {
1282
            return $row->user_id;
1283
        }
1284
1285
        return 0;
1286
    }
1287
1288
    /**
1289
     * Check if a username is available.
1290
     *
1291
     * @param string $username the wanted username
1292
     *
1293
     * @return bool true if the wanted username is available
1294
     * @assert ('') === false
1295
     * @assert ('xyzxyzxyz') === true
1296
     */
1297
    public static function is_username_available($username)
1298
    {
1299
        if (empty($username)) {
1300
            return false;
1301
        }
1302
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
1303
        $sql = "SELECT username FROM $table_user
1304
                WHERE username = '".Database::escape_string($username)."'";
1305
        $res = Database::query($sql);
1306
1307
        return 0 == Database::num_rows($res);
1308
    }
1309
1310
    /**
1311
     * Creates a username using person's names, i.e. creates jmontoya from Julio Montoya.
1312
     *
1313
     * @param string $firstname the first name of the user
1314
     * @param string $lastname  the last name of the user
1315
     *
1316
     * @return string suggests a username that contains only ASCII-letters and digits,
1317
     *                without check for uniqueness within the system
1318
     *
1319
     * @author Julio Montoya Armas
1320
     * @author Ivan Tcholakov, 2009 - rework about internationalization.
1321
     * @assert ('','') === false
1322
     * @assert ('a','b') === 'ab'
1323
     */
1324
    public static function create_username($firstname, $lastname)
1325
    {
1326
        if (empty($firstname) && empty($lastname)) {
1327
            return false;
1328
        }
1329
1330
        // The first letter only.
1331
        $firstname = api_substr(
1332
            preg_replace(USERNAME_PURIFIER, '', $firstname),
1333
            0,
1334
            1
1335
        );
1336
        //Looking for a space in the lastname
1337
        $pos = api_strpos($lastname, ' ');
1338
        if (false !== $pos) {
1339
            $lastname = api_substr($lastname, 0, $pos);
1340
        }
1341
1342
        $lastname = preg_replace(USERNAME_PURIFIER, '', $lastname);
1343
        $username = $firstname.$lastname;
1344
        if (empty($username)) {
1345
            $username = 'user';
1346
        }
1347
1348
        $username = URLify::transliterate($username);
1349
1350
        return strtolower(substr($username, 0, User::USERNAME_MAX_LENGTH - 3));
1351
    }
1352
1353
    /**
1354
     * Creates a unique username, using:
1355
     * 1. the first name and the last name of a user;
1356
     * 2. an already created username but not checked for uniqueness yet.
1357
     *
1358
     * @param string $firstname The first name of a given user. If the second parameter $lastname is NULL, then this
1359
     *                          parameter is treated as username which is to be checked f
1360
     *                          or uniqueness and to be modified when it is necessary.
1361
     * @param string $lastname  the last name of the user
1362
     *
1363
     * @return string Returns a username that contains only ASCII-letters and digits and that is unique in the system.
1364
     *                Note: When the method is called several times with same parameters,
1365
     *                its results look like the following sequence: ivan, ivan2, ivan3, ivan4, ...
1366
     *
1367
     * @author Ivan Tcholakov, 2009
1368
     */
1369
    public static function create_unique_username($firstname, $lastname = null)
1370
    {
1371
        if (is_null($lastname)) {
1372
            // In this case the actual input parameter $firstname should contain ASCII-letters and digits only.
1373
            // For making this method tolerant of mistakes,
1374
            // let us transliterate and purify the suggested input username anyway.
1375
            // So, instead of the sentence $username = $firstname; we place the following:
1376
            $username = strtolower(preg_replace(USERNAME_PURIFIER, '', $firstname));
1377
        } else {
1378
            $username = self::create_username($firstname, $lastname);
1379
        }
1380
        if (!self::is_username_available($username)) {
1381
            $i = 2;
1382
            $temp_username = substr($username, 0, User::USERNAME_MAX_LENGTH - strlen((string) $i)).$i;
1383
            while (!self::is_username_available($temp_username)) {
1384
                $i++;
1385
                $temp_username = substr($username, 0, User::USERNAME_MAX_LENGTH - strlen((string) $i)).$i;
1386
            }
1387
            $username = $temp_username;
1388
        }
1389
1390
        $username = URLify::transliterate($username);
1391
1392
        return $username;
1393
    }
1394
1395
    /**
1396
     * Modifies a given username accordingly to the specification for valid characters and length.
1397
     *
1398
     * @param $username string          The input username
1399
     * @param bool $strict (optional)   When this flag is TRUE, the result is guaranteed for full compliance,
1400
     *                     otherwise compliance may be partial. The default value is FALSE.
1401
     *
1402
     * @return string the resulting purified username
1403
     */
1404
    public static function purify_username($username, $strict = false)
1405
    {
1406
        if ($strict) {
1407
            // 1. Conversion of unacceptable letters (latinian letters with accents for example)
1408
            // into ASCII letters in order they not to be totally removed.
1409
            // 2. Applying the strict purifier.
1410
            // 3. Length limitation.
1411
            $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);
1412
            $return = URLify::transliterate($return);
1413
1414
            return $return;
1415
        }
1416
1417
        // 1. Applying the shallow purifier.
1418
        // 2. Length limitation.
1419
        return substr(
1420
            preg_replace(USERNAME_PURIFIER_SHALLOW, '', $username),
1421
            0,
1422
            User::USERNAME_MAX_LENGTH
1423
        );
1424
    }
1425
1426
    /**
1427
     * Checks whether the user id exists in the database.
1428
     *
1429
     * @param int $userId User id
1430
     *
1431
     * @return bool True if user id was found, false otherwise
1432
     */
1433
    public static function is_user_id_valid($userId)
1434
    {
1435
        $resultData = Database::select(
1436
            'COUNT(1) AS count',
1437
            Database::get_main_table(TABLE_MAIN_USER),
1438
            [
1439
                'where' => ['id = ?' => (int) $userId],
1440
            ],
1441
            'first'
1442
        );
1443
1444
        if (false === $resultData) {
1445
            return false;
1446
        }
1447
1448
        return $resultData['count'] > 0;
1449
    }
1450
1451
    /**
1452
     * Checks whether a given username matches to the specification strictly.
1453
     * The empty username is assumed here as invalid.
1454
     * Mostly this function is to be used in the user interface built-in validation routines
1455
     * for providing feedback while usernames are enterd manually.
1456
     *
1457
     * @param string $username the input username
1458
     *
1459
     * @return bool returns TRUE if the username is valid, FALSE otherwise
1460
     */
1461
    public static function is_username_valid($username)
1462
    {
1463
        return !empty($username) && $username == self::purify_username($username, true);
1464
    }
1465
1466
    /**
1467
     * Checks whether a username is empty. If the username contains whitespace characters,
1468
     * such as spaces, tabulators, newlines, etc.,
1469
     * it is assumed as empty too. This function is safe for validation unpurified data (during importing).
1470
     *
1471
     * @param string $username the given username
1472
     *
1473
     * @return bool returns TRUE if length of the username exceeds the limit, FALSE otherwise
1474
     */
1475
    public static function is_username_empty($username)
1476
    {
1477
        return 0 == strlen(self::purify_username($username, false));
1478
    }
1479
1480
    /**
1481
     * Checks whether a username is too long or not.
1482
     *
1483
     * @param string $username the given username, it should contain only ASCII-letters and digits
1484
     *
1485
     * @return bool returns TRUE if length of the username exceeds the limit, FALSE otherwise
1486
     */
1487
    public static function is_username_too_long($username)
1488
    {
1489
        return strlen($username) > User::USERNAME_MAX_LENGTH;
1490
    }
1491
1492
    /**
1493
     * Get the users by ID.
1494
     *
1495
     * @param array  $ids    student ids
1496
     * @param bool   $active
1497
     * @param string $order
1498
     * @param string $limit
1499
     *
1500
     * @return array $result student information
1501
     */
1502
    public static function get_user_list_by_ids($ids = [], $active = null, $order = null, $limit = null)
1503
    {
1504
        if (empty($ids)) {
1505
            return [];
1506
        }
1507
1508
        $ids = is_array($ids) ? $ids : [$ids];
1509
        $ids = array_map('intval', $ids);
1510
        $ids = implode(',', $ids);
1511
1512
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
1513
        $sql = "SELECT * FROM $tbl_user WHERE id IN ($ids)";
1514
        if (!is_null($active)) {
1515
            $sql .= ' AND active='.($active ? '1' : '0');
1516
        }
1517
1518
        if (!is_null($order)) {
1519
            $order = Database::escape_string($order);
1520
            $sql .= ' ORDER BY '.$order;
1521
        }
1522
1523
        if (!is_null($limit)) {
1524
            $limit = Database::escape_string($limit);
1525
            $sql .= ' LIMIT '.$limit;
1526
        }
1527
1528
        $rs = Database::query($sql);
1529
        $result = [];
1530
        while ($row = Database::fetch_array($rs)) {
1531
            $result[] = $row;
1532
        }
1533
1534
        return $result;
1535
    }
1536
1537
    /**
1538
     * Get a list of users of which the given conditions match with an = 'cond'.
1539
     *
1540
     * @param array $conditions a list of condition (example : status=>STUDENT)
1541
     * @param array $order_by   a list of fields on which sort
1542
     *
1543
     * @return array an array with all users of the platform
1544
     *
1545
     * @todo security filter order by
1546
     */
1547
    public static function get_user_list(
1548
        $conditions = [],
1549
        $order_by = [],
1550
        $limit_from = false,
1551
        $limit_to = false,
1552
        $idCampus = null
1553
    ) {
1554
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
1555
        $userUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1556
        $return_array = [];
1557
        $sql = "SELECT user.*, user.id as user_id FROM $user_table user ";
1558
1559
        if (api_is_multiple_url_enabled()) {
1560
            if ($idCampus) {
1561
                $urlId = $idCampus;
1562
            } else {
1563
                $urlId = api_get_current_access_url_id();
1564
            }
1565
            $sql .= " INNER JOIN $userUrlTable url_user
1566
                      ON (user.id = url_user.user_id)
1567
                      WHERE url_user.access_url_id = $urlId";
1568
        } else {
1569
            $sql .= " WHERE 1=1 ";
1570
        }
1571
1572
        if (count($conditions) > 0) {
1573
            foreach ($conditions as $field => $value) {
1574
                $field = Database::escape_string($field);
1575
                $value = Database::escape_string($value);
1576
                $sql .= " AND $field = '$value'";
1577
            }
1578
        }
1579
1580
        if (count($order_by) > 0) {
1581
            $sql .= ' ORDER BY '.Database::escape_string(implode(',', $order_by));
1582
        }
1583
1584
        if (is_numeric($limit_from) && is_numeric($limit_from)) {
1585
            $limit_from = (int) $limit_from;
1586
            $limit_to = (int) $limit_to;
1587
            $sql .= " LIMIT $limit_from, $limit_to";
1588
        }
1589
        $sql_result = Database::query($sql);
1590
        while ($result = Database::fetch_array($sql_result)) {
1591
            $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1592
            $return_array[] = $result;
1593
        }
1594
1595
        return $return_array;
1596
    }
1597
1598
    public static function getUserListExtraConditions(
1599
        $conditions = [],
1600
        $order_by = [],
1601
        $limit_from = false,
1602
        $limit_to = false,
1603
        $idCampus = null,
1604
        $extraConditions = '',
1605
        $getCount = false
1606
    ) {
1607
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
1608
        $userUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1609
        $return_array = [];
1610
        $sql = "SELECT user.*, user.id as user_id FROM $user_table user ";
1611
1612
        if ($getCount) {
1613
            $sql = "SELECT count(user.id) count FROM $user_table user ";
1614
        }
1615
1616
        if (api_is_multiple_url_enabled()) {
1617
            if ($idCampus) {
1618
                $urlId = $idCampus;
1619
            } else {
1620
                $urlId = api_get_current_access_url_id();
1621
            }
1622
            $sql .= " INNER JOIN $userUrlTable url_user
1623
                      ON (user.user_id = url_user.user_id)
1624
                      WHERE url_user.access_url_id = $urlId";
1625
        } else {
1626
            $sql .= " WHERE 1=1 ";
1627
        }
1628
1629
        $sql .= " AND status <> ".ANONYMOUS." ";
1630
1631
        if (count($conditions) > 0) {
1632
            foreach ($conditions as $field => $value) {
1633
                $field = Database::escape_string($field);
1634
                $value = Database::escape_string($value);
1635
                $sql .= " AND $field = '$value'";
1636
            }
1637
        }
1638
1639
        $sql .= str_replace("\'", "'", Database::escape_string($extraConditions));
1640
1641
        if (!empty($order_by) && count($order_by) > 0) {
1642
            $sql .= ' ORDER BY '.Database::escape_string(implode(',', $order_by));
1643
        }
1644
1645
        if (is_numeric($limit_from) && is_numeric($limit_from)) {
1646
            $limit_from = (int) $limit_from;
1647
            $limit_to = (int) $limit_to;
1648
            $sql .= " LIMIT $limit_from, $limit_to";
1649
        }
1650
1651
        $sql_result = Database::query($sql);
1652
1653
        if ($getCount) {
1654
            $result = Database::fetch_array($sql_result);
1655
1656
            return $result['count'];
1657
        }
1658
1659
        while ($result = Database::fetch_array($sql_result)) {
1660
            $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1661
            $return_array[] = $result;
1662
        }
1663
1664
        return $return_array;
1665
    }
1666
1667
    /**
1668
     * Get a list of users of which the given conditions match with a LIKE '%cond%'.
1669
     *
1670
     * @param array  $conditions       a list of condition (exemple : status=>STUDENT)
1671
     * @param array  $order_by         a list of fields on which sort
1672
     * @param bool   $simple_like      Whether we want a simple LIKE 'abc' or a LIKE '%abc%'
1673
     * @param string $condition        Whether we want the filters to be combined by AND or OR
1674
     * @param array  $onlyThisUserList
1675
     *
1676
     * @return array an array with all users of the platform
1677
     *
1678
     * @todo optional course code parameter, optional sorting parameters...
1679
     * @todo security filter order_by
1680
     */
1681
    public static function getUserListLike(
1682
        $conditions = [],
1683
        $order_by = [],
1684
        $simple_like = false,
1685
        $condition = 'AND',
1686
        $onlyThisUserList = []
1687
    ) {
1688
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
1689
        $tblAccessUrlRelUser = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1690
        $return_array = [];
1691
        $sql_query = "SELECT user.id FROM $user_table user ";
1692
1693
        if (api_is_multiple_url_enabled()) {
1694
            $sql_query .= " INNER JOIN $tblAccessUrlRelUser auru ON auru.user_id = user.id ";
1695
        }
1696
1697
        $sql_query .= ' WHERE 1 = 1 ';
1698
        if (count($conditions) > 0) {
1699
            $temp_conditions = [];
1700
            foreach ($conditions as $field => $value) {
1701
                $field = Database::escape_string($field);
1702
                $value = Database::escape_string($value);
1703
                if ($simple_like) {
1704
                    $temp_conditions[] = $field." LIKE '$value%'";
1705
                } else {
1706
                    $temp_conditions[] = $field.' LIKE \'%'.$value.'%\'';
1707
                }
1708
            }
1709
            if (!empty($temp_conditions)) {
1710
                $sql_query .= ' AND '.implode(' '.$condition.' ', $temp_conditions);
1711
            }
1712
1713
            if (api_is_multiple_url_enabled()) {
1714
                $sql_query .= ' AND auru.access_url_id = '.api_get_current_access_url_id();
1715
            }
1716
        } else {
1717
            if (api_is_multiple_url_enabled()) {
1718
                $sql_query .= ' AND auru.access_url_id = '.api_get_current_access_url_id();
1719
            }
1720
        }
1721
1722
        if (!empty($onlyThisUserList)) {
1723
            $onlyThisUserListToString = implode("','", $onlyThisUserList);
1724
            $sql_query .= " AND user.id IN ('$onlyThisUserListToString') ";
1725
        }
1726
1727
        if (count($order_by) > 0) {
1728
            $sql_query .= ' ORDER BY '.Database::escape_string(implode(',', $order_by));
1729
        }
1730
1731
        $sql_result = Database::query($sql_query);
1732
        while ($result = Database::fetch_array($sql_result)) {
1733
            $userInfo = api_get_user_info($result['id']);
1734
            $return_array[] = $userInfo;
1735
        }
1736
1737
        return $return_array;
1738
    }
1739
1740
    /**
1741
     * Gets the current user image.
1742
     *
1743
     * @param string $userId
1744
     * @param int    $size        it can be USER_IMAGE_SIZE_SMALL,
1745
     *                            USER_IMAGE_SIZE_MEDIUM, USER_IMAGE_SIZE_BIG or  USER_IMAGE_SIZE_ORIGINAL
1746
     * @param bool   $addRandomId
1747
     * @param array  $userInfo    to avoid query the DB
1748
     *
1749
     * @todo add gravatar support
1750
     * @todo replace $userId with User entity
1751
     *
1752
     * @return string
1753
     */
1754
    public static function getUserPicture(
1755
        $userId,
1756
        int $size = USER_IMAGE_SIZE_MEDIUM,
1757
        $addRandomId = true,
1758
        $userInfo = []
1759
    ) {
1760
        $user = api_get_user_entity($userId);
1761
        $illustrationRepo = Container::getIllustrationRepository();
1762
1763
        switch ($size) {
1764
            case USER_IMAGE_SIZE_SMALL:
1765
                $width = 32;
1766
                break;
1767
            case USER_IMAGE_SIZE_MEDIUM:
1768
                $width = 64;
1769
                break;
1770
            case USER_IMAGE_SIZE_BIG:
1771
                $width = 128;
1772
                break;
1773
            case USER_IMAGE_SIZE_ORIGINAL:
1774
            default:
1775
                $width = 0;
1776
                break;
1777
        }
1778
1779
        $url = $illustrationRepo->getIllustrationUrl($user);
1780
        $params = [];
1781
        if (!empty($width)) {
1782
            $params['w'] = $width;
1783
        }
1784
1785
        if ($addRandomId) {
1786
            $params['rand'] = uniqid('u_', true);
1787
        }
1788
1789
        $paramsToString = '';
1790
        if (!empty($params)) {
1791
            $paramsToString = '?'.http_build_query($params);
1792
        }
1793
1794
        return $url.$paramsToString;
1795
1796
        /*
1797
        // Make sure userInfo is defined. Otherwise, define it!
1798
        if (empty($userInfo) || !is_array($userInfo) || 0 == count($userInfo)) {
1799
            if (empty($user_id)) {
1800
                return '';
1801
            } else {
1802
                $userInfo = api_get_user_info($user_id);
1803
            }
1804
        }
1805
1806
        $imageWebPath = self::get_user_picture_path_by_id(
1807
            $user_id,
1808
            'web',
1809
            $userInfo
1810
        );
1811
        $pictureWebFile = $imageWebPath['file'];
1812
        $pictureWebDir = $imageWebPath['dir'];
1813
1814
        $pictureAnonymousSize = '128';
1815
        $gravatarSize = 22;
1816
        $realSizeName = 'small_';
1817
1818
        switch ($size) {
1819
            case USER_IMAGE_SIZE_SMALL:
1820
                $pictureAnonymousSize = '32';
1821
                $realSizeName = 'small_';
1822
                $gravatarSize = 32;
1823
                break;
1824
            case USER_IMAGE_SIZE_MEDIUM:
1825
                $pictureAnonymousSize = '64';
1826
                $realSizeName = 'medium_';
1827
                $gravatarSize = 64;
1828
                break;
1829
            case USER_IMAGE_SIZE_ORIGINAL:
1830
                $pictureAnonymousSize = '128';
1831
                $realSizeName = '';
1832
                $gravatarSize = 128;
1833
                break;
1834
            case USER_IMAGE_SIZE_BIG:
1835
                $pictureAnonymousSize = '128';
1836
                $realSizeName = 'big_';
1837
                $gravatarSize = 128;
1838
                break;
1839
        }
1840
1841
        $gravatarEnabled = api_get_setting('gravatar_enabled');
1842
        $anonymousPath = Display::returnIconPath('unknown.png', $pictureAnonymousSize);
1843
        if ('unknown.jpg' == $pictureWebFile || empty($pictureWebFile)) {
1844
            if ('true' === $gravatarEnabled) {
1845
                $file = self::getGravatar(
1846
                    $imageWebPath['email'],
1847
                    $gravatarSize,
1848
                    api_get_setting('gravatar_type')
1849
                );
1850
1851
                if ($addRandomId) {
1852
                    $file .= '&rand='.uniqid();
1853
                }
1854
1855
                return $file;
1856
            }
1857
1858
            return $anonymousPath;
1859
        }
1860
1861
        if ($addRandomId) {
1862
            $picture .= '?rand='.uniqid();
1863
        }
1864
1865
        return $picture;*/
1866
    }
1867
1868
    /**
1869
     * Creates new user photos in various sizes of a user, or deletes user photos.
1870
     * Note: This method relies on configuration setting from main/inc/conf/profile.conf.php.
1871
     *
1872
     * @param int    $user_id the user internal identification number
1873
     * @param string $file    The common file name for the newly created photos.
1874
     *                        It will be checked and modified for compatibility with the file system.
1875
     *                        If full name is provided, path component is ignored.
1876
     *                        If an empty name is provided, then old user photos are deleted only,
1877
     *
1878
     * @see     UserManager::delete_user_picture() as the prefered way for deletion.
1879
     *
1880
     * @param string $source_file    the full system name of the image from which user photos will be created
1881
     * @param string $cropParameters Optional string that contents "x,y,width,height" of a cropped image format
1882
     *
1883
     * @return bool Returns the resulting common file name of created images which usually should be stored in database.
1884
     *              When deletion is requested returns empty string.
1885
     *              In case of internal error or negative validation returns FALSE.
1886
     */
1887
    public static function update_user_picture($userId, UploadedFile $file, string $crop = '')
1888
    {
1889
        if (empty($userId) || empty($file)) {
1890
            return false;
1891
        }
1892
1893
        $repo = Container::getUserRepository();
1894
        $user = $repo->find($userId);
1895
        if ($user) {
1896
            $repoIllustration = Container::getIllustrationRepository();
1897
            $repoIllustration->addIllustration($user, $user, $file, $crop);
1898
        }
1899
    }
1900
1901
    /**
1902
     * Deletes user photos.
1903
     *
1904
     * @param int $userId the user internal identification number
1905
     *
1906
     * @return mixed returns empty string on success, FALSE on error
1907
     */
1908
    public static function deleteUserPicture($userId)
1909
    {
1910
        $repo = Container::getUserRepository();
1911
        $user = $repo->find($userId);
1912
        if ($user) {
1913
            $illustrationRepo = Container::getIllustrationRepository();
1914
            $illustrationRepo->deleteIllustration($user);
1915
        }
1916
    }
1917
1918
    /**
1919
     * Returns an XHTML formatted list of productions for a user, or FALSE if he
1920
     * doesn't have any.
1921
     *
1922
     * If there has been a request to remove a production, the function will return
1923
     * without building the list unless forced to do so by the optional second
1924
     * parameter. This increases performance by avoiding to read through the
1925
     * productions on the filesystem before the removal request has been carried
1926
     * out because they'll have to be re-read afterwards anyway.
1927
     *
1928
     * @param int  $user_id    User id
1929
     * @param bool $force      Optional parameter to force building after a removal request
1930
     * @param bool $showDelete
1931
     *
1932
     * @return string A string containing the XHTML code to display the production list, or FALSE
1933
     */
1934
    public static function build_production_list($user_id, $force = false, $showDelete = false)
1935
    {
1936
        if (!$force && !empty($_POST['remove_production'])) {
1937
            return true; // postpone reading from the filesystem
1938
        }
1939
1940
        $productions = self::get_user_productions($user_id);
1941
1942
        if (empty($productions)) {
1943
            return false;
1944
        }
1945
1946
        return false;
1947
1948
        $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...
1949
        $del_image = Display::returnIconPath('delete.png');
1950
        $add_image = Display::returnIconPath('archive.png');
1951
        $del_text = get_lang('Delete');
1952
        $production_list = '';
1953
        if (count($productions) > 0) {
1954
            $production_list = '<div class="files-production"><ul id="productions">';
1955
            foreach ($productions as $file) {
1956
                $production_list .= '<li>
1957
                    <img src="'.$add_image.'" />
1958
                    <a href="'.$production_dir.urlencode($file).'" target="_blank">
1959
                        '.htmlentities($file).'
1960
                    </a>';
1961
                if ($showDelete) {
1962
                    $production_list .= '&nbsp;&nbsp;
1963
                        <input
1964
                            style="width:16px;"
1965
                            type="image"
1966
                            name="remove_production['.urlencode($file).']"
1967
                            src="'.$del_image.'"
1968
                            alt="'.$del_text.'"
1969
                            title="'.$del_text.' '.htmlentities($file).'"
1970
                            onclick="javascript: return confirmation(\''.htmlentities($file).'\');" /></li>';
1971
                }
1972
            }
1973
            $production_list .= '</ul></div>';
1974
        }
1975
1976
        return $production_list;
1977
    }
1978
1979
    /**
1980
     * Returns an array with the user's productions.
1981
     *
1982
     * @param int $user_id User id
1983
     *
1984
     * @return array An array containing the user's productions
1985
     */
1986
    public static function get_user_productions($user_id)
1987
    {
1988
        return [];
1989
1990
        $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...
1991
        $productions = [];
1992
1993
        if (is_dir($production_repository)) {
1994
            $handle = opendir($production_repository);
1995
            while ($file = readdir($handle)) {
1996
                if ('.' == $file ||
1997
                    '..' == $file ||
1998
                    '.htaccess' == $file ||
1999
                    is_dir($production_repository.$file)
2000
                ) {
2001
                    // skip current/parent directory and .htaccess
2002
                    continue;
2003
                }
2004
2005
                if (preg_match('/('.$user_id.'|[0-9a-f]{13}|saved)_.+\.(png|jpg|jpeg|gif)$/i', $file)) {
2006
                    // User's photos should not be listed as productions.
2007
                    continue;
2008
                }
2009
                $productions[] = $file;
2010
            }
2011
        }
2012
2013
        return $productions;
2014
    }
2015
2016
    /**
2017
     * Remove a user production.
2018
     *
2019
     * @param int    $user_id    User id
2020
     * @param string $production The production to remove
2021
     *
2022
     * @return bool
2023
     */
2024
    public static function remove_user_production($user_id, $production)
2025
    {
2026
        throw new Exception('remove_user_production');
2027
        /*$production_path = self::get_user_picture_path_by_id($user_id, 'system');
2028
        $production_file = $production_path['dir'].$production;
2029
        if (is_file($production_file)) {
2030
            unlink($production_file);
2031
2032
            return true;
2033
        }
2034
2035
        return false;*/
2036
    }
2037
2038
    /**
2039
     * Update an extra field value for a given user.
2040
     *
2041
     * @param int    $userId   User ID
2042
     * @param string $variable Field variable name
2043
     * @param string $value    Field value
2044
     *
2045
     * @return bool true if field updated, false otherwise
2046
     */
2047
    public static function update_extra_field_value($userId, $variable, $value = '')
2048
    {
2049
        $extraFieldValue = new ExtraFieldValue('user');
2050
        $params = [
2051
            'item_id' => $userId,
2052
            'variable' => $variable,
2053
            'value' => $value,
2054
        ];
2055
2056
        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...
2057
    }
2058
2059
    /**
2060
     * Get an array of extra fields with field details (type, default value and options).
2061
     *
2062
     * @param    int    Offset (from which row)
2063
     * @param    int    Number of items
2064
     * @param    int    Column on which sorting is made
2065
     * @param    string    Sorting direction
2066
     * @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...
2067
     * @param    int        Optional. Whether we get all the fields with field_filter 1 or 0 or everything
2068
     *
2069
     * @return array Extra fields details (e.g. $list[2]['type'], $list[4]['options'][2]['title']
2070
     */
2071
    public static function get_extra_fields(
2072
        $from = 0,
2073
        $number_of_items = 0,
2074
        $column = 5,
2075
        $direction = 'ASC',
2076
        $all_visibility = true,
2077
        $field_filter = null
2078
    ) {
2079
        $fields = [];
2080
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
2081
        $t_ufo = Database::get_main_table(TABLE_EXTRA_FIELD_OPTIONS);
2082
        $columns = [
2083
            'id',
2084
            'variable',
2085
            'field_type',
2086
            'display_text',
2087
            'default_value',
2088
            'field_order',
2089
            'filter',
2090
        ];
2091
        $column = (int) $column;
2092
        $sort_direction = '';
2093
        if (in_array(strtoupper($direction), ['ASC', 'DESC'])) {
2094
            $sort_direction = strtoupper($direction);
2095
        }
2096
        $extraFieldType = EntityExtraField::USER_FIELD_TYPE;
2097
        $sqlf = "SELECT * FROM $t_uf WHERE extra_field_type = $extraFieldType ";
2098
        if (!$all_visibility) {
2099
            $sqlf .= " AND visible_to_self = 1 ";
2100
        }
2101
        if (!is_null($field_filter)) {
2102
            $field_filter = (int) $field_filter;
2103
            $sqlf .= " AND filter = $field_filter ";
2104
        }
2105
        $sqlf .= " ORDER BY `".$columns[$column]."` $sort_direction ";
2106
        if (0 != $number_of_items) {
2107
            $sqlf .= " LIMIT ".intval($from).','.intval($number_of_items);
2108
        }
2109
        $resf = Database::query($sqlf);
2110
        if (Database::num_rows($resf) > 0) {
2111
            while ($rowf = Database::fetch_array($resf)) {
2112
                $fields[$rowf['id']] = [
2113
                    0 => $rowf['id'],
2114
                    1 => $rowf['variable'],
2115
                    2 => $rowf['field_type'],
2116
                    3 => empty($rowf['display_text']) ? '' : $rowf['display_text'],
2117
                    4 => $rowf['default_value'],
2118
                    5 => $rowf['field_order'],
2119
                    6 => $rowf['visible_to_self'],
2120
                    7 => $rowf['changeable'],
2121
                    8 => $rowf['filter'],
2122
                    9 => [],
2123
                    10 => '<a name="'.$rowf['id'].'"></a>',
2124
                ];
2125
2126
                $sqlo = "SELECT * FROM $t_ufo
2127
                         WHERE field_id = ".$rowf['id']."
2128
                         ORDER BY option_order ASC";
2129
                $reso = Database::query($sqlo);
2130
                if (Database::num_rows($reso) > 0) {
2131
                    while ($rowo = Database::fetch_array($reso)) {
2132
                        $fields[$rowf['id']][9][$rowo['id']] = [
2133
                            0 => $rowo['id'],
2134
                            1 => $rowo['option_value'],
2135
                            2 => empty($rowo['display_text']) ? '' : $rowo['display_text'],
2136
                            3 => $rowo['option_order'],
2137
                        ];
2138
                    }
2139
                }
2140
            }
2141
        }
2142
2143
        return $fields;
2144
    }
2145
2146
    /**
2147
     * Creates a new extra field.
2148
     *
2149
     * @param string $variable    Field's internal variable name
2150
     * @param int    $fieldType   Field's type
2151
     * @param string $displayText Field's language var name
2152
     * @param string $default     Field's default value
2153
     *
2154
     * @return int
2155
     */
2156
    public static function create_extra_field(
2157
        $variable,
2158
        $fieldType,
2159
        $displayText,
2160
        $default
2161
    ) {
2162
        $extraField = new ExtraField('user');
2163
        $params = [
2164
            'variable' => $variable,
2165
            'field_type' => $fieldType,
2166
            'display_text' => $displayText,
2167
            'default_value' => $default,
2168
        ];
2169
2170
        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...
2171
    }
2172
2173
    /**
2174
     * Check if a field is available.
2175
     *
2176
     * @param string $variable
2177
     *
2178
     * @return bool
2179
     */
2180
    public static function is_extra_field_available($variable)
2181
    {
2182
        $extraField = new ExtraField('user');
2183
        $data = $extraField->get_handler_field_info_by_field_variable($variable);
2184
2185
        return !empty($data) ? true : false;
2186
    }
2187
2188
    /**
2189
     * Gets user extra fields data.
2190
     *
2191
     * @param    int    User ID
2192
     * @param    bool    Whether to prefix the fields indexes with "extra_" (might be used by formvalidator)
2193
     * @param    bool    Whether to return invisible fields as well
2194
     * @param    bool    Whether to split multiple-selection fields or not
2195
     *
2196
     * @return array Array of fields => value for the given user
2197
     */
2198
    public static function get_extra_user_data(
2199
        $user_id,
2200
        $prefix = false,
2201
        $allVisibility = true,
2202
        $splitMultiple = false,
2203
        $fieldFilter = null
2204
    ) {
2205
        $user_id = (int) $user_id;
2206
2207
        if (empty($user_id)) {
2208
            return [];
2209
        }
2210
2211
        $extra_data = [];
2212
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
2213
        $t_ufv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
2214
        $sql = "SELECT f.id as id, f.variable as fvar, f.field_type as type
2215
                FROM $t_uf f
2216
                WHERE
2217
                    extra_field_type = ".EntityExtraField::USER_FIELD_TYPE."
2218
                ";
2219
        $filter_cond = '';
2220
2221
        if (!$allVisibility) {
2222
            if (isset($fieldFilter)) {
2223
                $fieldFilter = (int) $fieldFilter;
2224
                $filter_cond .= " AND filter = $fieldFilter ";
2225
            }
2226
            $sql .= " AND f.visible_to_self = 1 $filter_cond ";
2227
        } else {
2228
            if (isset($fieldFilter)) {
2229
                $fieldFilter = (int) $fieldFilter;
2230
                $sql .= " AND filter = $fieldFilter ";
2231
            }
2232
        }
2233
2234
        $sql .= ' ORDER BY f.field_order';
2235
2236
        $res = Database::query($sql);
2237
        if (Database::num_rows($res) > 0) {
2238
            while ($row = Database::fetch_array($res)) {
2239
                if (self::USER_FIELD_TYPE_TAG == $row['type']) {
2240
                    $tags = self::get_user_tags_to_string($user_id, $row['id'], false);
2241
                    $extra_data['extra_'.$row['fvar']] = $tags;
2242
                } else {
2243
                    $sqlu = "SELECT value as fval
2244
                            FROM $t_ufv
2245
                            WHERE field_id=".$row['id']." AND item_id = ".$user_id;
2246
                    $resu = Database::query($sqlu);
2247
                    // get default value
2248
                    $sql_df = "SELECT default_value as fval_df FROM $t_uf
2249
                               WHERE id=".$row['id'];
2250
                    $res_df = Database::query($sql_df);
2251
2252
                    if (Database::num_rows($resu) > 0) {
2253
                        $rowu = Database::fetch_array($resu);
2254
                        $fval = $rowu['fval'];
2255
                        if (self::USER_FIELD_TYPE_SELECT_MULTIPLE == $row['type']) {
2256
                            $fval = explode(';', $rowu['fval']);
2257
                        }
2258
                    } else {
2259
                        $row_df = Database::fetch_array($res_df);
2260
                        $fval = $row_df['fval_df'];
2261
                    }
2262
                    // We get here (and fill the $extra_data array) even if there
2263
                    // is no user with data (we fill it with default values)
2264
                    if ($prefix) {
2265
                        if (self::USER_FIELD_TYPE_RADIO == $row['type']) {
2266
                            $extra_data['extra_'.$row['fvar']]['extra_'.$row['fvar']] = $fval;
2267
                        } else {
2268
                            $extra_data['extra_'.$row['fvar']] = $fval;
2269
                        }
2270
                    } else {
2271
                        if (self::USER_FIELD_TYPE_RADIO == $row['type']) {
2272
                            $extra_data['extra_'.$row['fvar']]['extra_'.$row['fvar']] = $fval;
2273
                        } else {
2274
                            $extra_data[$row['fvar']] = $fval;
2275
                        }
2276
                    }
2277
                }
2278
            }
2279
        }
2280
2281
        return $extra_data;
2282
    }
2283
2284
    /** Get extra user data by field.
2285
     * @param int    user ID
2286
     * @param string the internal variable name of the field
2287
     *
2288
     * @return array with extra data info of a user i.e array('field_variable'=>'value');
2289
     */
2290
    public static function get_extra_user_data_by_field(
2291
        $user_id,
2292
        $field_variable,
2293
        $prefix = false,
2294
        $all_visibility = true,
2295
        $splitmultiple = false
2296
    ) {
2297
        $user_id = (int) $user_id;
2298
2299
        if (empty($user_id)) {
2300
            return [];
2301
        }
2302
2303
        $extra_data = [];
2304
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
2305
        $t_ufv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
2306
2307
        $sql = "SELECT f.id as id, f.variable as fvar, f.field_type as type
2308
                FROM $t_uf f
2309
                WHERE f.variable = '$field_variable' ";
2310
2311
        if (!$all_visibility) {
2312
            $sql .= " AND f.visible_to_self = 1 ";
2313
        }
2314
2315
        $sql .= " AND extra_field_type = ".EntityExtraField::USER_FIELD_TYPE;
2316
        $sql .= " ORDER BY f.field_order ";
2317
2318
        $res = Database::query($sql);
2319
        if (Database::num_rows($res) > 0) {
2320
            while ($row = Database::fetch_array($res)) {
2321
                $sqlu = "SELECT value as fval FROM $t_ufv v
2322
                         INNER JOIN $t_uf f
2323
                         ON (v.field_id = f.id)
2324
                         WHERE
2325
                            extra_field_type = ".EntityExtraField::USER_FIELD_TYPE." AND
2326
                            field_id = ".$row['id']." AND
2327
                            item_id = ".$user_id;
2328
                $resu = Database::query($sqlu);
2329
                $fval = '';
2330
                if (Database::num_rows($resu) > 0) {
2331
                    $rowu = Database::fetch_array($resu);
2332
                    $fval = $rowu['fval'];
2333
                    if (self::USER_FIELD_TYPE_SELECT_MULTIPLE == $row['type']) {
2334
                        $fval = explode(';', $rowu['fval']);
2335
                    }
2336
                }
2337
                if ($prefix) {
2338
                    $extra_data['extra_'.$row['fvar']] = $fval;
2339
                } else {
2340
                    $extra_data[$row['fvar']] = $fval;
2341
                }
2342
            }
2343
        }
2344
2345
        return $extra_data;
2346
    }
2347
2348
    /**
2349
     * Get the extra field information for a certain field (the options as well).
2350
     *
2351
     * @param int $variable The name of the field we want to know everything about
2352
     *
2353
     * @return array Array containing all the information about the extra profile field
2354
     *               (first level of array contains field details, then 'options' sub-array contains options details,
2355
     *               as returned by the database)
2356
     *
2357
     * @author Julio Montoya
2358
     *
2359
     * @since v1.8.6
2360
     */
2361
    public static function get_extra_field_information_by_name($variable)
2362
    {
2363
        $extraField = new ExtraField('user');
2364
2365
        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...
2366
    }
2367
2368
    /**
2369
     * Get the extra field information for user tag (the options as well).
2370
     *
2371
     * @param int $variable The name of the field we want to know everything about
2372
     *
2373
     * @return array Array containing all the information about the extra profile field
2374
     *               (first level of array contains field details, then 'options' sub-array contains options details,
2375
     *               as returned by the database)
2376
     *
2377
     * @author José Loguercio
2378
     *
2379
     * @since v1.11.0
2380
     */
2381
    public static function get_extra_field_tags_information_by_name($variable)
2382
    {
2383
        $extraField = new ExtraField('user');
2384
2385
        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...
2386
    }
2387
2388
    /**
2389
     * Get all the extra field information of a certain field (also the options).
2390
     *
2391
     * @param int $fieldId the ID of the field we want to know everything of
2392
     *
2393
     * @return array $return containing all th information about the extra profile field
2394
     *
2395
     * @author Julio Montoya
2396
     *
2397
     * @deprecated
2398
     * @since v1.8.6
2399
     */
2400
    public static function get_extra_field_information($fieldId)
2401
    {
2402
        $extraField = new ExtraField('user');
2403
2404
        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...
2405
    }
2406
2407
    /**
2408
     * Get extra user data by value.
2409
     *
2410
     * @param string $variable       the internal variable name of the field
2411
     * @param string $value          the internal value of the field
2412
     * @param bool   $all_visibility
2413
     *
2414
     * @return array with extra data info of a user i.e array('field_variable'=>'value');
2415
     */
2416
    public static function get_extra_user_data_by_value($variable, $value, $all_visibility = true)
2417
    {
2418
        $extraFieldValue = new ExtraFieldValue('user');
2419
        $extraField = new ExtraField('user');
2420
2421
        $info = $extraField->get_handler_field_info_by_field_variable($variable);
2422
2423
        if (false === $info) {
2424
            return [];
2425
        }
2426
2427
        $data = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
2428
            $variable,
2429
            $value,
2430
            false,
2431
            false,
2432
            true
2433
        );
2434
2435
        $result = [];
2436
        if (!empty($data)) {
2437
            foreach ($data as $item) {
2438
                $result[] = $item['item_id'];
2439
            }
2440
        }
2441
2442
        return $result;
2443
    }
2444
2445
    /**
2446
     * Get extra user data by tags value.
2447
     *
2448
     * @param int    $fieldId the ID of the field we want to know everything of
2449
     * @param string $tag     the tag name for search
2450
     *
2451
     * @return array with extra data info of a user
2452
     *
2453
     * @author José Loguercio
2454
     *
2455
     * @since v1.11.0
2456
     */
2457
    public static function get_extra_user_data_by_tags($fieldId, $tag)
2458
    {
2459
        $extraField = new ExtraField('user');
2460
        $result = $extraField->getAllUserPerTag($fieldId, $tag);
2461
        $array = [];
2462
        foreach ($result as $index => $user) {
2463
            $array[] = $user['user_id'];
2464
        }
2465
2466
        return $array;
2467
    }
2468
2469
    /**
2470
     * Get extra user data by field variable.
2471
     *
2472
     * @param string $variable field variable
2473
     *
2474
     * @return array data
2475
     */
2476
    public static function get_extra_user_data_by_field_variable($variable)
2477
    {
2478
        $extraInfo = self::get_extra_field_information_by_name($variable);
2479
        $field_id = (int) $extraInfo['id'];
2480
2481
        $extraField = new ExtraFieldValue('user');
2482
        $data = $extraField->getValuesByFieldId($field_id);
2483
2484
        if (!empty($data)) {
2485
            foreach ($data as $row) {
2486
                $user_id = $row['item_id'];
2487
                $data[$user_id] = $row;
2488
            }
2489
        }
2490
2491
        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...
2492
    }
2493
2494
    /**
2495
     * Get extra user data tags by field variable.
2496
     *
2497
     * @param string $variable field variable
2498
     *
2499
     * @return array
2500
     */
2501
    public static function get_extra_user_data_for_tags($variable)
2502
    {
2503
        $data = self::get_extra_field_tags_information_by_name($variable);
2504
2505
        return $data;
2506
    }
2507
2508
    /**
2509
     * Gives a list of [session_category][session_id] for the current user.
2510
     *
2511
     * @param int  $user_id
2512
     * @param bool $is_time_over                 whether to fill the first element or not
2513
     *                                           (to give space for courses out of categories)
2514
     * @param bool $ignore_visibility_for_admins optional true if limit time from session is over, false otherwise
2515
     * @param bool $ignoreTimeLimit              ignore time start/end
2516
     * @param bool $getCount
2517
     *
2518
     * @return array list of statuses [session_category][session_id]
2519
     *
2520
     * @todo ensure multiple access urls are managed correctly
2521
     */
2522
    public static function get_sessions_by_category(
2523
        $user_id,
2524
        $is_time_over = true,
2525
        $ignore_visibility_for_admins = false,
2526
        $ignoreTimeLimit = false,
2527
        $getCount = false
2528
    ) {
2529
        $user_id = (int) $user_id;
2530
2531
        if (empty($user_id)) {
2532
            return [];
2533
        }
2534
2535
        $allowOrder = api_get_configuration_value('session_list_order');
2536
        $position = '';
2537
        if ($allowOrder) {
2538
            $position = ', s.position AS position ';
2539
        }
2540
2541
        // Get the list of sessions per user
2542
        $now = new DateTime('now', new DateTimeZone('UTC'));
2543
2544
        // LEFT JOIN is used for session_rel_course_rel_user because an inner
2545
        // join would not catch session-courses where the user is general
2546
        // session coach but which do not have students nor coaches registered
2547
        $dqlSelect = ' COUNT(DISTINCT s.id) ';
2548
2549
        if (!$getCount) {
2550
            $dqlSelect = " DISTINCT
2551
                s.id,
2552
                s.name,
2553
                s.accessStartDate AS access_start_date,
2554
                s.accessEndDate AS access_end_date,
2555
                s.duration,
2556
                sc.id AS session_category_id,
2557
                sc.name AS session_category_name,
2558
                sc.dateStart AS session_category_date_start,
2559
                sc.dateEnd AS session_category_date_end,
2560
                s.coachAccessStartDate AS coach_access_start_date,
2561
                s.coachAccessEndDate AS coach_access_end_date,
2562
                CASE WHEN s.accessEndDate IS NULL THEN 1 ELSE 0 END HIDDEN _isFieldNull
2563
                $position
2564
            ";
2565
        }
2566
2567
        $dql = "SELECT $dqlSelect
2568
                FROM ChamiloCoreBundle:Session AS s
2569
                LEFT JOIN ChamiloCoreBundle:SessionRelCourseRelUser AS scu WITH scu.session = s
2570
                INNER JOIN ChamiloCoreBundle:AccessUrlRelSession AS url WITH url.session = s.id
2571
                LEFT JOIN ChamiloCoreBundle:SessionCategory AS sc WITH s.category = sc ";
2572
2573
        // A single OR operation on scu.user = :user OR s.generalCoach = :user
2574
        // is awfully inefficient for large sets of data (1m25s for 58K
2575
        // sessions, BT#14115) but executing a similar query twice and grouping
2576
        // the results afterwards in PHP takes about 1/1000th of the time
2577
        // (0.1s + 0.0s) for the same set of data, so we do it this way...
2578
        $dqlStudent = $dql." WHERE scu.user = :user AND url.url = :url ";
2579
        $dqlCoach = $dql." WHERE s.generalCoach = :user AND url.url = :url ";
2580
2581
        // Default order
2582
        $order = 'ORDER BY sc.name, s.name';
2583
2584
        // Order by date if showing all sessions
2585
        $showAllSessions = true === api_get_configuration_value('show_all_sessions_on_my_course_page');
2586
        if ($showAllSessions) {
2587
            $order = 'ORDER BY s.accessStartDate';
2588
        }
2589
2590
        // Order by position
2591
        if ($allowOrder) {
2592
            $order = 'ORDER BY s.position';
2593
        }
2594
2595
        // Order by dates according to settings
2596
        $orderBySettings = api_get_configuration_value('my_courses_session_order');
2597
        if (!empty($orderBySettings) && isset($orderBySettings['field']) && isset($orderBySettings['order'])) {
2598
            $field = $orderBySettings['field'];
2599
            $orderSetting = $orderBySettings['order'];
2600
            switch ($field) {
2601
                case 'start_date':
2602
                    $order = " ORDER BY s.accessStartDate $orderSetting";
2603
                    break;
2604
                case 'end_date':
2605
                    $order = " ORDER BY s.accessEndDate $orderSetting ";
2606
                    if ('asc' == $orderSetting) {
2607
                        // Put null values at the end
2608
                        // https://stackoverflow.com/questions/12652034/how-can-i-order-by-null-in-dql
2609
                        $order = ' ORDER BY _isFieldNull asc, s.accessEndDate asc';
2610
                    }
2611
                    break;
2612
                case 'name':
2613
                    $order = " ORDER BY s.name $orderSetting ";
2614
                    break;
2615
            }
2616
        }
2617
2618
        $dqlStudent .= $order;
2619
        $dqlCoach .= $order;
2620
2621
        $accessUrlId = api_get_current_access_url_id();
2622
        $dqlStudent = Database::getManager()
2623
            ->createQuery($dqlStudent)
2624
            ->setParameters(
2625
                ['user' => $user_id, 'url' => $accessUrlId]
2626
            )
2627
        ;
2628
        $dqlCoach = Database::getManager()
2629
            ->createQuery($dqlCoach)
2630
            ->setParameters(
2631
                ['user' => $user_id, 'url' => $accessUrlId]
2632
            )
2633
        ;
2634
2635
        if ($getCount) {
2636
            return $dqlStudent->getSingleScalarResult() + $dqlCoach->getSingleScalarResult();
2637
        }
2638
2639
        $sessionDataStudent = $dqlStudent->getResult();
2640
        $sessionDataCoach = $dqlCoach->getResult();
2641
2642
        $sessionData = [];
2643
        // First fill $sessionData with student sessions
2644
        if (!empty($sessionDataStudent)) {
2645
            foreach ($sessionDataStudent as $row) {
2646
                $sessionData[$row['id']] = $row;
2647
            }
2648
        }
2649
        // Overwrite session data of the user as a student with session data
2650
        // of the user as a coach.
2651
        // There shouldn't be such duplicate rows, but just in case...
2652
        if (!empty($sessionDataCoach)) {
2653
            foreach ($sessionDataCoach as $row) {
2654
                $sessionData[$row['id']] = $row;
2655
            }
2656
        }
2657
2658
        $collapsable = api_get_configuration_value('allow_user_session_collapsable');
2659
        $extraField = new ExtraFieldValue('session');
2660
        $collapsableLink = api_get_path(WEB_PATH).'user_portal.php?action=collapse_session';
2661
2662
        if (empty($sessionData)) {
2663
            return [];
2664
        }
2665
        $categories = [];
2666
        foreach ($sessionData as $row) {
2667
            $session_id = $row['id'];
2668
            $coachList = SessionManager::getCoachesBySession($session_id);
2669
            $categoryStart = $row['session_category_date_start'] ? $row['session_category_date_start']->format('Y-m-d') : '';
2670
            $categoryEnd = $row['session_category_date_end'] ? $row['session_category_date_end']->format('Y-m-d') : '';
2671
            $courseList = self::get_courses_list_by_session($user_id, $session_id);
2672
            $daysLeft = SessionManager::getDayLeftInSession($row, $user_id);
2673
2674
            // User portal filters:
2675
            if (false === $ignoreTimeLimit) {
2676
                if ($is_time_over) {
2677
                    // History
2678
                    if ($row['duration']) {
2679
                        if ($daysLeft >= 0) {
2680
                            continue;
2681
                        }
2682
                    } else {
2683
                        if (empty($row['access_end_date'])) {
2684
                            continue;
2685
                        } else {
2686
                            if ($row['access_end_date'] > $now) {
2687
                                continue;
2688
                            }
2689
                        }
2690
                    }
2691
                } else {
2692
                    // Current user portal
2693
                    $isGeneralCoach = SessionManager::user_is_general_coach($user_id, $row['id']);
2694
                    $isCoachOfCourse = in_array($user_id, $coachList);
2695
2696
                    if (api_is_platform_admin() || $isGeneralCoach || $isCoachOfCourse) {
2697
                        // Teachers can access the session depending in the access_coach date
2698
                    } else {
2699
                        if ($row['duration']) {
2700
                            if ($daysLeft <= 0) {
2701
                                continue;
2702
                            }
2703
                        } else {
2704
                            if (isset($row['access_end_date']) &&
2705
                                !empty($row['access_end_date'])
2706
                            ) {
2707
                                if ($row['access_end_date'] <= $now) {
2708
                                    continue;
2709
                                }
2710
                            }
2711
                        }
2712
                    }
2713
                }
2714
            }
2715
2716
            $categories[$row['session_category_id']]['session_category'] = [
2717
                'id' => $row['session_category_id'],
2718
                'name' => $row['session_category_name'],
2719
                'date_start' => $categoryStart,
2720
                'date_end' => $categoryEnd,
2721
            ];
2722
2723
            $visibility = api_get_session_visibility(
2724
                $session_id,
2725
                null,
2726
                $ignore_visibility_for_admins
2727
            );
2728
2729
            if (SESSION_VISIBLE != $visibility) {
2730
                // Course Coach session visibility.
2731
                $blockedCourseCount = 0;
2732
                $closedVisibilityList = [
2733
                    COURSE_VISIBILITY_CLOSED,
2734
                    COURSE_VISIBILITY_HIDDEN,
2735
                ];
2736
2737
                foreach ($courseList as $course) {
2738
                    // Checking session visibility
2739
                    $sessionCourseVisibility = api_get_session_visibility(
2740
                        $session_id,
2741
                        $course['real_id'],
2742
                        $ignore_visibility_for_admins
2743
                    );
2744
2745
                    $courseIsVisible = !in_array($course['visibility'], $closedVisibilityList);
2746
                    if (false === $courseIsVisible || SESSION_INVISIBLE == $sessionCourseVisibility) {
2747
                        $blockedCourseCount++;
2748
                    }
2749
                }
2750
2751
                // If all courses are blocked then no show in the list.
2752
                if ($blockedCourseCount === count($courseList)) {
2753
                    $visibility = SESSION_INVISIBLE;
2754
                } else {
2755
                    $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...
2756
                }
2757
            }
2758
2759
            switch ($visibility) {
2760
                case SESSION_VISIBLE_READ_ONLY:
2761
                case SESSION_VISIBLE:
2762
                case SESSION_AVAILABLE:
2763
                    break;
2764
                case SESSION_INVISIBLE:
2765
                    if (false === $ignore_visibility_for_admins) {
2766
                        continue 2;
2767
                    }
2768
            }
2769
2770
            $collapsed = '';
2771
            $collapsedAction = '';
2772
            if ($collapsable) {
2773
                $collapsableData = SessionManager::getCollapsableData(
2774
                    $user_id,
2775
                    $session_id,
2776
                    $extraField,
2777
                    $collapsableLink
2778
                );
2779
                $collapsed = $collapsableData['collapsed'];
2780
                $collapsedAction = $collapsableData['collapsable_link'];
2781
            }
2782
2783
            $categories[$row['session_category_id']]['sessions'][] = [
2784
                'session_name' => $row['name'],
2785
                'session_id' => $row['id'],
2786
                'access_start_date' => $row['access_start_date'] ? $row['access_start_date']->format('Y-m-d H:i:s') : null,
2787
                'access_end_date' => $row['access_end_date'] ? $row['access_end_date']->format('Y-m-d H:i:s') : null,
2788
                'coach_access_start_date' => $row['coach_access_start_date'] ? $row['coach_access_start_date']->format('Y-m-d H:i:s') : null,
2789
                'coach_access_end_date' => $row['coach_access_end_date'] ? $row['coach_access_end_date']->format('Y-m-d H:i:s') : null,
2790
                'courses' => $courseList,
2791
                'collapsed' => $collapsed,
2792
                'collapsable_link' => $collapsedAction,
2793
                'duration' => $row['duration'],
2794
            ];
2795
        }
2796
2797
        return $categories;
2798
    }
2799
2800
    /**
2801
     * Gives a list of [session_id-course_code] => [status] for the current user.
2802
     *
2803
     * @param int $user_id
2804
     * @param int $sessionLimit
2805
     *
2806
     * @return array list of statuses (session_id-course_code => status)
2807
     */
2808
    public static function get_personal_session_course_list($user_id, $sessionLimit = null)
2809
    {
2810
        // Database Table Definitions
2811
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
2812
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
2813
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2814
        $tbl_session_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
2815
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2816
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2817
        $tblCourseCategory = Database::get_main_table(TABLE_MAIN_CATEGORY);
2818
2819
        $user_id = (int) $user_id;
2820
2821
        if (empty($user_id)) {
2822
            return [];
2823
        }
2824
2825
        // We filter the courses from the URL
2826
        $join_access_url = $where_access_url = '';
2827
        if (api_get_multiple_access_url()) {
2828
            $access_url_id = api_get_current_access_url_id();
2829
            if (-1 != $access_url_id) {
2830
                $tbl_url_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2831
                $join_access_url = "LEFT JOIN $tbl_url_course url_rel_course ON url_rel_course.c_id = course.id";
2832
                $where_access_url = " AND access_url_id = $access_url_id ";
2833
            }
2834
        }
2835
2836
        // Courses in which we subscribed out of any session
2837
2838
        $sql = "SELECT
2839
                    course.code,
2840
                    course_rel_user.status course_rel_status,
2841
                    course_rel_user.sort sort,
2842
                    course_rel_user.user_course_cat user_course_cat
2843
                 FROM $tbl_course_user course_rel_user
2844
                 LEFT JOIN $tbl_course course
2845
                 ON course.id = course_rel_user.c_id
2846
                 $join_access_url
2847
                 WHERE
2848
                    course_rel_user.user_id = '".$user_id."' AND
2849
                    course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH."
2850
                    $where_access_url
2851
                 ORDER BY course_rel_user.sort, course.title ASC";
2852
2853
        $course_list_sql_result = Database::query($sql);
2854
        $personal_course_list = [];
2855
        if (Database::num_rows($course_list_sql_result) > 0) {
2856
            while ($result_row = Database::fetch_array($course_list_sql_result, 'ASSOC')) {
2857
                $course_info = api_get_course_info($result_row['code']);
2858
                $result_row['course_info'] = $course_info;
2859
                $personal_course_list[] = $result_row;
2860
            }
2861
        }
2862
2863
        $coachCourseConditions = '';
2864
        // Getting sessions that are related to a coach in the session_rel_course_rel_user table
2865
        if (api_is_allowed_to_create_course()) {
2866
            $sessionListFromCourseCoach = [];
2867
            $sql = " SELECT DISTINCT session_id
2868
                    FROM $tbl_session_course_user
2869
                    WHERE user_id = $user_id AND status = 2 ";
2870
2871
            $result = Database::query($sql);
2872
            if (Database::num_rows($result)) {
2873
                $result = Database::store_result($result);
2874
                foreach ($result as $session) {
2875
                    $sessionListFromCourseCoach[] = $session['session_id'];
2876
                }
2877
            }
2878
            if (!empty($sessionListFromCourseCoach)) {
2879
                $condition = implode("','", $sessionListFromCourseCoach);
2880
                $coachCourseConditions = " OR ( s.id IN ('$condition'))";
2881
            }
2882
        }
2883
2884
        // Get the list of sessions where the user is subscribed
2885
        // This is divided into two different queries
2886
        $sessions = [];
2887
        $sessionLimitRestriction = '';
2888
        if (!empty($sessionLimit)) {
2889
            $sessionLimit = (int) $sessionLimit;
2890
            $sessionLimitRestriction = "LIMIT $sessionLimit";
2891
        }
2892
2893
        $sql = "SELECT DISTINCT s.id, name, access_start_date, access_end_date
2894
                FROM $tbl_session_user su INNER JOIN $tbl_session s
2895
                ON (s.id = su.session_id)
2896
                WHERE (
2897
                    su.user_id = $user_id AND
2898
                    su.relation_type <> ".SESSION_RELATION_TYPE_RRHH."
2899
                )
2900
                $coachCourseConditions
2901
                ORDER BY access_start_date, access_end_date, name
2902
                $sessionLimitRestriction
2903
        ";
2904
2905
        $result = Database::query($sql);
2906
        if (Database::num_rows($result) > 0) {
2907
            while ($row = Database::fetch_assoc($result)) {
2908
                $sessions[$row['id']] = $row;
2909
            }
2910
        }
2911
2912
        $sql = "SELECT DISTINCT
2913
                id, name, access_start_date, access_end_date
2914
                FROM $tbl_session s
2915
                WHERE (
2916
                    id_coach = $user_id
2917
                )
2918
                $coachCourseConditions
2919
                ORDER BY access_start_date, access_end_date, name";
2920
2921
        $result = Database::query($sql);
2922
        if (Database::num_rows($result) > 0) {
2923
            while ($row = Database::fetch_assoc($result)) {
2924
                if (empty($sessions[$row['id']])) {
2925
                    $sessions[$row['id']] = $row;
2926
                }
2927
            }
2928
        }
2929
2930
        if (api_is_allowed_to_create_course()) {
2931
            foreach ($sessions as $enreg) {
2932
                $session_id = $enreg['id'];
2933
                $session_visibility = api_get_session_visibility($session_id);
2934
2935
                if (SESSION_INVISIBLE == $session_visibility) {
2936
                    continue;
2937
                }
2938
2939
                // This query is horribly slow when more than a few thousand
2940
                // users and just a few sessions to which they are subscribed
2941
                $sql = "SELECT DISTINCT
2942
                        course.code code,
2943
                        course.title i,
2944
                        ".(api_is_western_name_order() ? "CONCAT(user.firstname,' ',user.lastname)" : "CONCAT(user.lastname,' ',user.firstname)")." t,
2945
                        email, course.course_language l,
2946
                        1 sort,
2947
                        course_category.code user_course_cat,
2948
                        access_start_date,
2949
                        access_end_date,
2950
                        session.id as session_id,
2951
                        session.name as session_name
2952
                    FROM $tbl_session_course_user as session_course_user
2953
                    INNER JOIN $tbl_course AS course
2954
                        ON course.id = session_course_user.c_id
2955
                    LEFT JOIN $tblCourseCategory course_category ON course.category_id = course_category.id
2956
                    INNER JOIN $tbl_session as session
2957
                        ON session.id = session_course_user.session_id
2958
                    LEFT JOIN $tbl_user as user
2959
                        ON user.id = session_course_user.user_id OR session.id_coach = user.id
2960
                    WHERE
2961
                        session_course_user.session_id = $session_id AND (
2962
                            (session_course_user.user_id = $user_id AND session_course_user.status = 2)
2963
                            OR session.id_coach = $user_id
2964
                        )
2965
                    ORDER BY i";
2966
                $course_list_sql_result = Database::query($sql);
2967
                while ($result_row = Database::fetch_array($course_list_sql_result, 'ASSOC')) {
2968
                    $result_row['course_info'] = api_get_course_info($result_row['code']);
2969
                    $key = $result_row['session_id'].' - '.$result_row['code'];
2970
                    $personal_course_list[$key] = $result_row;
2971
                }
2972
            }
2973
        }
2974
2975
        foreach ($sessions as $enreg) {
2976
            $session_id = $enreg['id'];
2977
            $session_visibility = api_get_session_visibility($session_id);
2978
            if (SESSION_INVISIBLE == $session_visibility) {
2979
                continue;
2980
            }
2981
2982
            /* This query is very similar to the above query,
2983
               but it will check the session_rel_course_user table if there are courses registered to our user or not */
2984
            $sql = "SELECT DISTINCT
2985
                course.code code,
2986
                course.title i, CONCAT(user.lastname,' ',user.firstname) t,
2987
                email,
2988
                course.course_language l,
2989
                1 sort,
2990
                course_category.code user_course_cat,
2991
                access_start_date,
2992
                access_end_date,
2993
                session.id as session_id,
2994
                session.name as session_name,
2995
                IF((session_course_user.user_id = 3 AND session_course_user.status=2),'2', '5')
2996
            FROM $tbl_session_course_user as session_course_user
2997
            INNER JOIN $tbl_course AS course
2998
            ON course.id = session_course_user.c_id AND session_course_user.session_id = $session_id
2999
            LEFT JOIN $tblCourseCategory course_category ON course.category_id = course_category.id
3000
            INNER JOIN $tbl_session as session
3001
            ON session_course_user.session_id = session.id
3002
            LEFT JOIN $tbl_user as user ON user.id = session_course_user.user_id
3003
            WHERE session_course_user.user_id = $user_id
3004
            ORDER BY i";
3005
3006
            $course_list_sql_result = Database::query($sql);
3007
            while ($result_row = Database::fetch_array($course_list_sql_result, 'ASSOC')) {
3008
                $result_row['course_info'] = api_get_course_info($result_row['code']);
3009
                $key = $result_row['session_id'].' - '.$result_row['code'];
3010
                if (!isset($personal_course_list[$key])) {
3011
                    $personal_course_list[$key] = $result_row;
3012
                }
3013
            }
3014
        }
3015
3016
        return $personal_course_list;
3017
    }
3018
3019
    /**
3020
     * Gives a list of courses for the given user in the given session.
3021
     *
3022
     * @param int $user_id
3023
     * @param int $session_id
3024
     *
3025
     * @return array list of statuses (session_id-course_code => status)
3026
     */
3027
    public static function get_courses_list_by_session($user_id, $session_id)
3028
    {
3029
        // Database Table Definitions
3030
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3031
        $tableCourse = Database::get_main_table(TABLE_MAIN_COURSE);
3032
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3033
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3034
3035
        $user_id = (int) $user_id;
3036
        $session_id = (int) $session_id;
3037
        // We filter the courses from the URL
3038
        $join_access_url = $where_access_url = '';
3039
        if (api_get_multiple_access_url()) {
3040
            $urlId = api_get_current_access_url_id();
3041
            if (-1 != $urlId) {
3042
                $tbl_url_session = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
3043
                $join_access_url = " ,  $tbl_url_session url_rel_session ";
3044
                $where_access_url = " AND access_url_id = $urlId AND url_rel_session.session_id = $session_id ";
3045
            }
3046
        }
3047
3048
        /* This query is very similar to the query below, but it will check the
3049
        session_rel_course_user table if there are courses registered
3050
        to our user or not */
3051
        $sql = "SELECT DISTINCT
3052
                    c.title,
3053
                    c.visibility,
3054
                    c.id as real_id,
3055
                    c.code as course_code,
3056
                    sc.position,
3057
                    c.unsubscribe
3058
                FROM $tbl_session_course_user as scu
3059
                INNER JOIN $tbl_session_course sc
3060
                ON (scu.session_id = sc.session_id AND scu.c_id = sc.c_id)
3061
                INNER JOIN $tableCourse as c
3062
                ON (scu.c_id = c.id)
3063
                $join_access_url
3064
                WHERE
3065
                    scu.user_id = $user_id AND
3066
                    scu.session_id = $session_id
3067
                    $where_access_url
3068
                ORDER BY sc.position ASC";
3069
3070
        $myCourseList = [];
3071
        $courses = [];
3072
        $result = Database::query($sql);
3073
        if (Database::num_rows($result) > 0) {
3074
            while ($result_row = Database::fetch_array($result, 'ASSOC')) {
3075
                $result_row['status'] = 5;
3076
                if (!in_array($result_row['real_id'], $courses)) {
3077
                    $position = $result_row['position'];
3078
                    if (!isset($myCourseList[$position])) {
3079
                        $myCourseList[$position] = $result_row;
3080
                    } else {
3081
                        $myCourseList[] = $result_row;
3082
                    }
3083
                    $courses[] = $result_row['real_id'];
3084
                }
3085
            }
3086
        }
3087
3088
        if (api_is_allowed_to_create_course()) {
3089
            $sql = "SELECT DISTINCT
3090
                        c.title,
3091
                        c.visibility,
3092
                        c.id as real_id,
3093
                        c.code as course_code,
3094
                        sc.position,
3095
                        c.unsubscribe
3096
                    FROM $tbl_session_course_user as scu
3097
                    INNER JOIN $tbl_session as s
3098
                    ON (scu.session_id = s.id)
3099
                    INNER JOIN $tbl_session_course sc
3100
                    ON (scu.session_id = sc.session_id AND scu.c_id = sc.c_id)
3101
                    INNER JOIN $tableCourse as c
3102
                    ON (scu.c_id = c.id)
3103
                    $join_access_url
3104
                    WHERE
3105
                      s.id = $session_id AND
3106
                      (
3107
                        (scu.user_id = $user_id AND scu.status = 2) OR
3108
                        s.id_coach = $user_id
3109
                      )
3110
                    $where_access_url
3111
                    ORDER BY sc.position ASC";
3112
            $result = Database::query($sql);
3113
3114
            if (Database::num_rows($result) > 0) {
3115
                while ($result_row = Database::fetch_array($result, 'ASSOC')) {
3116
                    $result_row['status'] = 2;
3117
                    if (!in_array($result_row['real_id'], $courses)) {
3118
                        $position = $result_row['position'];
3119
                        if (!isset($myCourseList[$position])) {
3120
                            $myCourseList[$position] = $result_row;
3121
                        } else {
3122
                            $myCourseList[] = $result_row;
3123
                        }
3124
                        $courses[] = $result_row['real_id'];
3125
                    }
3126
                }
3127
            }
3128
        }
3129
3130
        if (api_is_drh()) {
3131
            $sessionList = SessionManager::get_sessions_followed_by_drh($user_id);
3132
            $sessionList = array_keys($sessionList);
3133
            if (in_array($session_id, $sessionList)) {
3134
                $courseList = SessionManager::get_course_list_by_session_id($session_id);
3135
                if (!empty($courseList)) {
3136
                    foreach ($courseList as $course) {
3137
                        if (!in_array($course['id'], $courses)) {
3138
                            $position = $course['position'];
3139
                            if (!isset($myCourseList[$position])) {
3140
                                $myCourseList[$position] = $course;
3141
                            } else {
3142
                                $myCourseList[] = $course;
3143
                            }
3144
                        }
3145
                    }
3146
                }
3147
            }
3148
        } else {
3149
            //check if user is general coach for this session
3150
            $sessionInfo = api_get_session_info($session_id);
3151
            if ($sessionInfo['id_coach'] == $user_id) {
3152
                $courseList = SessionManager::get_course_list_by_session_id($session_id);
3153
                if (!empty($courseList)) {
3154
                    foreach ($courseList as $course) {
3155
                        if (!in_array($course['id'], $courses)) {
3156
                            $position = $course['position'];
3157
                            if (!isset($myCourseList[$position])) {
3158
                                $myCourseList[$position] = $course;
3159
                            } else {
3160
                                $myCourseList[] = $course;
3161
                            }
3162
                        }
3163
                    }
3164
                }
3165
            }
3166
        }
3167
3168
        if (!empty($myCourseList)) {
3169
            ksort($myCourseList);
3170
            $checkPosition = array_filter(array_column($myCourseList, 'position'));
3171
            if (empty($checkPosition)) {
3172
                // The session course list doesn't have any position,
3173
                // then order the course list by course code
3174
                $list = array_column($myCourseList, 'course_code');
3175
                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

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

4069
            $form->addHeader(get_lang('Results and feedback').' "'./** @scrutinizer ignore-type */ $query.'"');
Loading history...
4070
        }
4071
4072
        $form->addText(
4073
            'q',
4074
            get_lang('Users, Groups'),
4075
            false,
4076
            [
4077
                'id' => 'q',
4078
            ]
4079
        );
4080
        $options = [
4081
            0 => get_lang('Select'),
4082
            1 => get_lang('User'),
4083
            2 => get_lang('Group'),
4084
        ];
4085
        $form->addSelect(
4086
            'search_type',
4087
            get_lang('Type'),
4088
            $options,
4089
            ['onchange' => 'javascript: extra_field_toogle();', 'id' => 'search_type']
4090
        );
4091
4092
        // Extra fields
4093
        $extraFields = self::getExtraFilterableFields();
4094
        $defaults = [];
4095
        if (is_array($extraFields) && count($extraFields) > 0) {
4096
            foreach ($extraFields as $extraField) {
4097
                $varName = 'field_'.$extraField['variable'];
4098
                $options = [
4099
                    0 => get_lang('Select'),
4100
                ];
4101
                foreach ($extraField['data'] as $option) {
4102
                    if (isset($_GET[$varName])) {
4103
                        if ($_GET[$varName] == $option[1]) {
4104
                            $defaults[$option[1]] = true;
4105
                        }
4106
                    }
4107
4108
                    $options[$option[1]] = $option[1];
4109
                }
4110
                $form->addSelect($varName, $extraField['name'], $options);
4111
            }
4112
        }
4113
4114
        $defaults['search_type'] = (int) $searchType;
4115
        $defaults['q'] = $query;
4116
4117
        if (!empty($defaultParams)) {
4118
            $defaults = array_merge($defaults, $defaultParams);
4119
        }
4120
        $form->setDefaults($defaults);
4121
        $form->addButtonSearch(get_lang('Search'));
4122
4123
        $js = '<script>
4124
        extra_field_toogle();
4125
        function extra_field_toogle() {
4126
            if (jQuery("select[name=search_type]").val() != "1") {
4127
                jQuery(".extra_field").hide();
4128
            } else {
4129
                jQuery(".extra_field").show();
4130
            }
4131
        }
4132
        </script>';
4133
4134
        return $js.$form->returnForm();
4135
    }
4136
4137
    /**
4138
     * Allow to register contact to social network.
4139
     *
4140
     * @param int $friend_id     user friend id
4141
     * @param int $my_user_id    user id
4142
     * @param int $relation_type relation between users see constants definition
4143
     *
4144
     * @return bool
4145
     */
4146
    public static function relate_users($friend_id, $my_user_id, $relation_type)
4147
    {
4148
        $tbl_my_friend = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4149
4150
        $friend_id = (int) $friend_id;
4151
        $my_user_id = (int) $my_user_id;
4152
        $relation_type = (int) $relation_type;
4153
4154
        $sql = 'SELECT COUNT(*) as count FROM '.$tbl_my_friend.'
4155
                WHERE
4156
                    friend_user_id='.$friend_id.' AND
4157
                    user_id='.$my_user_id.' AND
4158
                    relation_type NOT IN('.USER_RELATION_TYPE_RRHH.', '.USER_RELATION_TYPE_BOSS.') ';
4159
        $result = Database::query($sql);
4160
        $row = Database::fetch_array($result, 'ASSOC');
4161
        $current_date = api_get_utc_datetime();
4162
4163
        if (0 == $row['count']) {
4164
            $sql = 'INSERT INTO '.$tbl_my_friend.'(friend_user_id,user_id,relation_type,last_edit)
4165
                    VALUES ('.$friend_id.','.$my_user_id.','.$relation_type.',"'.$current_date.'")';
4166
            Database::query($sql);
4167
4168
            return true;
4169
        }
4170
4171
        $sql = 'SELECT COUNT(*) as count, relation_type  FROM '.$tbl_my_friend.'
4172
                WHERE
4173
                    friend_user_id='.$friend_id.' AND
4174
                    user_id='.$my_user_id.' AND
4175
                    relation_type NOT IN('.USER_RELATION_TYPE_RRHH.', '.USER_RELATION_TYPE_BOSS.') ';
4176
        $result = Database::query($sql);
4177
        $row = Database::fetch_array($result, 'ASSOC');
4178
4179
        if (1 == $row['count']) {
4180
            //only for the case of a RRHH or a Student BOSS
4181
            if ($row['relation_type'] != $relation_type &&
4182
                (USER_RELATION_TYPE_RRHH == $relation_type || USER_RELATION_TYPE_BOSS == $relation_type)
4183
            ) {
4184
                $sql = 'INSERT INTO '.$tbl_my_friend.'(friend_user_id,user_id,relation_type,last_edit)
4185
                        VALUES ('.$friend_id.','.$my_user_id.','.$relation_type.',"'.$current_date.'")';
4186
            } else {
4187
                $sql = 'UPDATE '.$tbl_my_friend.' SET relation_type='.$relation_type.'
4188
                        WHERE friend_user_id='.$friend_id.' AND user_id='.$my_user_id;
4189
            }
4190
            Database::query($sql);
4191
4192
            return true;
4193
        }
4194
4195
        return false;
4196
    }
4197
4198
    /**
4199
     * @param int $userId
4200
     *
4201
     * @return array
4202
     */
4203
    public static function getDrhListFromUser($userId)
4204
    {
4205
        $tblUser = Database::get_main_table(TABLE_MAIN_USER);
4206
        $tblUserRelUser = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4207
        $tblUserRelAccessUrl = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
4208
        $userId = (int) $userId;
4209
4210
        $orderBy = null;
4211
        if (api_is_western_name_order()) {
4212
            $orderBy .= ' ORDER BY firstname, lastname ';
4213
        } else {
4214
            $orderBy .= ' ORDER BY lastname, firstname ';
4215
        }
4216
4217
        $sql = "SELECT u.id, username, u.firstname, u.lastname
4218
                FROM $tblUser u
4219
                INNER JOIN $tblUserRelUser uru ON (uru.friend_user_id = u.id)
4220
                INNER JOIN $tblUserRelAccessUrl a ON (a.user_id = u.id)
4221
                WHERE
4222
                    access_url_id = ".api_get_current_access_url_id()." AND
4223
                    uru.user_id = '$userId' AND
4224
                    relation_type = '".USER_RELATION_TYPE_RRHH."'
4225
                $orderBy
4226
                ";
4227
        $result = Database::query($sql);
4228
4229
        return Database::store_result($result);
4230
    }
4231
4232
    /**
4233
     * get users followed by human resource manager.
4234
     *
4235
     * @param int    $userId
4236
     * @param int    $userStatus         (STUDENT, COURSEMANAGER, etc)
4237
     * @param bool   $getOnlyUserId
4238
     * @param bool   $getSql
4239
     * @param bool   $getCount
4240
     * @param int    $from
4241
     * @param int    $numberItems
4242
     * @param int    $column
4243
     * @param string $direction
4244
     * @param int    $active
4245
     * @param string $lastConnectionDate
4246
     *
4247
     * @return array users
4248
     */
4249
    public static function get_users_followed_by_drh(
4250
        $userId,
4251
        $userStatus = 0,
4252
        $getOnlyUserId = false,
4253
        $getSql = false,
4254
        $getCount = false,
4255
        $from = null,
4256
        $numberItems = null,
4257
        $column = null,
4258
        $direction = null,
4259
        $active = null,
4260
        $lastConnectionDate = null
4261
    ) {
4262
        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...
4263
            $userId,
4264
            $userStatus,
4265
            $getOnlyUserId,
4266
            $getSql,
4267
            $getCount,
4268
            $from,
4269
            $numberItems,
4270
            $column,
4271
            $direction,
4272
            $active,
4273
            $lastConnectionDate,
4274
            DRH
4275
        );
4276
    }
4277
4278
    /**
4279
     * Get users followed by human resource manager.
4280
     *
4281
     * @param int    $userId
4282
     * @param int    $userStatus             Filter users by status (STUDENT, COURSEMANAGER, etc)
4283
     * @param bool   $getOnlyUserId
4284
     * @param bool   $getSql
4285
     * @param bool   $getCount
4286
     * @param int    $from
4287
     * @param int    $numberItems
4288
     * @param int    $column
4289
     * @param string $direction
4290
     * @param int    $active
4291
     * @param string $lastConnectionDate
4292
     * @param int    $status                 the function is called by who? COURSEMANAGER, DRH?
4293
     * @param string $keyword
4294
     * @param bool   $checkSessionVisibility
4295
     *
4296
     * @return mixed Users list (array) or the SQL query if $getSQL was set to true
4297
     */
4298
    public static function getUsersFollowedByUser(
4299
        $userId,
4300
        $userStatus = null,
4301
        $getOnlyUserId = false,
4302
        $getSql = false,
4303
        $getCount = false,
4304
        $from = null,
4305
        $numberItems = null,
4306
        $column = null,
4307
        $direction = null,
4308
        $active = null,
4309
        $lastConnectionDate = null,
4310
        $status = null,
4311
        $keyword = null,
4312
        $checkSessionVisibility = false
4313
    ) {
4314
        // Database Table Definitions
4315
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
4316
        $tbl_user_rel_user = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4317
        $tbl_user_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
4318
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
4319
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4320
        $tbl_session_rel_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4321
        $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
4322
        $tbl_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
4323
4324
        $userId = (int) $userId;
4325
        $limitCondition = '';
4326
4327
        if (isset($from) && isset($numberItems)) {
4328
            $from = (int) $from;
4329
            $numberItems = (int) $numberItems;
4330
            $limitCondition = "LIMIT $from, $numberItems";
4331
        }
4332
4333
        $column = Database::escape_string($column);
4334
        $direction = in_array(strtolower($direction), ['asc', 'desc']) ? $direction : null;
4335
4336
        $userConditions = '';
4337
        if (!empty($userStatus)) {
4338
            $userConditions .= ' AND u.status = '.intval($userStatus);
4339
        }
4340
4341
        $select = " SELECT DISTINCT u.id user_id, u.username, u.lastname, u.firstname, u.email ";
4342
        if ($getOnlyUserId) {
4343
            $select = " SELECT DISTINCT u.id user_id";
4344
        }
4345
4346
        $masterSelect = "SELECT DISTINCT * FROM ";
4347
4348
        if ($getCount) {
4349
            $masterSelect = "SELECT COUNT(DISTINCT(user_id)) as count FROM ";
4350
            $select = " SELECT DISTINCT(u.id) user_id";
4351
        }
4352
4353
        if (!is_null($active)) {
4354
            $active = intval($active);
4355
            $userConditions .= " AND u.active = $active ";
4356
        }
4357
4358
        if (!empty($keyword)) {
4359
            $keyword = trim(Database::escape_string($keyword));
4360
            $keywordParts = array_filter(explode(' ', $keyword));
4361
            $extraKeyword = '';
4362
            if (!empty($keywordParts)) {
4363
                $keywordPartsFixed = Database::escape_string(implode('%', $keywordParts));
4364
                if (!empty($keywordPartsFixed)) {
4365
                    $extraKeyword .= " OR
4366
                        CONCAT(u.firstname, ' ', u.lastname) LIKE '%$keywordPartsFixed%' OR
4367
                        CONCAT(u.lastname, ' ', u.firstname) LIKE '%$keywordPartsFixed%' ";
4368
                }
4369
            }
4370
            $userConditions .= " AND (
4371
                u.username LIKE '%$keyword%' OR
4372
                u.firstname LIKE '%$keyword%' OR
4373
                u.lastname LIKE '%$keyword%' OR
4374
                u.official_code LIKE '%$keyword%' OR
4375
                u.email LIKE '%$keyword%' OR
4376
                CONCAT(u.firstname, ' ', u.lastname) LIKE '%$keyword%' OR
4377
                CONCAT(u.lastname, ' ', u.firstname) LIKE '%$keyword%'
4378
                $extraKeyword
4379
            )";
4380
        }
4381
4382
        if (!empty($lastConnectionDate)) {
4383
            $lastConnectionDate = Database::escape_string($lastConnectionDate);
4384
            $userConditions .= " AND u.last_login <= '$lastConnectionDate' ";
4385
        }
4386
4387
        $sessionConditionsCoach = null;
4388
        $dateCondition = '';
4389
        $drhConditions = null;
4390
        $teacherSelect = null;
4391
        $urlId = api_get_current_access_url_id();
4392
4393
        switch ($status) {
4394
            case DRH:
4395
                $drhConditions .= " AND
4396
                    friend_user_id = '$userId' AND
4397
                    relation_type = '".USER_RELATION_TYPE_RRHH."'
4398
                ";
4399
                break;
4400
            case COURSEMANAGER:
4401
                $drhConditions .= " AND
4402
                    friend_user_id = '$userId' AND
4403
                    relation_type = '".USER_RELATION_TYPE_RRHH."'
4404
                ";
4405
4406
                $sessionConditionsCoach .= " AND
4407
                    (s.id_coach = '$userId')
4408
                ";
4409
4410
                $sessionConditionsTeacher = " AND
4411
                    (scu.status = 2 AND scu.user_id = '$userId')
4412
                ";
4413
4414
                if ($checkSessionVisibility) {
4415
                    $today = api_strtotime('now', 'UTC');
4416
                    $today = date('Y-m-d', $today);
4417
                    $dateCondition = "
4418
                        AND
4419
                        (
4420
                            (s.access_start_date <= '$today' AND '$today' <= s.access_end_date) OR
4421
                            (s.access_start_date IS NULL AND s.access_end_date IS NULL) OR
4422
                            (s.access_start_date <= '$today' AND s.access_end_date IS NULL) OR
4423
                            ('$today' <= s.access_end_date AND s.access_start_date IS NULL)
4424
                        )
4425
					";
4426
                }
4427
4428
                // Use $tbl_session_rel_course_rel_user instead of $tbl_session_rel_user
4429
                /*
4430
                INNER JOIN $tbl_session_rel_user sru
4431
                ON (sru.user_id = u.id)
4432
                INNER JOIN $tbl_session_rel_course_rel_user scu
4433
                ON (scu.user_id = u.id AND scu.c_id IS NOT NULL AND visibility = 1)*/
4434
                $teacherSelect =
4435
                "UNION ALL (
4436
                        $select
4437
                        FROM $tbl_user u
4438
                        INNER JOIN $tbl_session_rel_user sru ON (sru.user_id = u.id)
4439
                        WHERE
4440
                            (
4441
                                sru.session_id IN (
4442
                                    SELECT DISTINCT(s.id) FROM $tbl_session s INNER JOIN
4443
                                    $tbl_session_rel_access_url session_rel_access_rel_user
4444
                                    ON session_rel_access_rel_user.session_id = s.id
4445
                                    WHERE access_url_id = ".$urlId."
4446
                                    $sessionConditionsCoach
4447
                                ) OR sru.session_id IN (
4448
                                    SELECT DISTINCT(s.id) FROM $tbl_session s
4449
                                    INNER JOIN $tbl_session_rel_access_url url
4450
                                    ON (url.session_id = s.id)
4451
                                    INNER JOIN $tbl_session_rel_course_rel_user scu
4452
                                    ON (scu.session_id = s.id)
4453
                                    WHERE access_url_id = ".$urlId."
4454
                                    $sessionConditionsTeacher
4455
                                    $dateCondition
4456
                                )
4457
                            )
4458
                            $userConditions
4459
                    )
4460
                    UNION ALL(
4461
                        $select
4462
                        FROM $tbl_user u
4463
                        INNER JOIN $tbl_course_user cu ON (cu.user_id = u.id)
4464
                        WHERE cu.c_id IN (
4465
                            SELECT DISTINCT(c_id) FROM $tbl_course_user
4466
                            WHERE user_id = $userId AND status = ".COURSEMANAGER."
4467
                        )
4468
                        $userConditions
4469
                    )"
4470
                ;
4471
                break;
4472
            case STUDENT_BOSS:
4473
                $drhConditions = " AND friend_user_id = $userId AND relation_type = ".USER_RELATION_TYPE_BOSS;
4474
                break;
4475
            case HRM_REQUEST:
4476
                $drhConditions .= " AND
4477
                    friend_user_id = '$userId' AND
4478
                    relation_type = '".USER_RELATION_TYPE_HRM_REQUEST."'
4479
                ";
4480
                break;
4481
        }
4482
4483
        $join = null;
4484
        $sql = " $masterSelect
4485
                (
4486
                    (
4487
                        $select
4488
                        FROM $tbl_user u
4489
                        INNER JOIN $tbl_user_rel_user uru ON (uru.user_id = u.id)
4490
                        LEFT JOIN $tbl_user_rel_access_url a ON (a.user_id = u.id)
4491
                        $join
4492
                        WHERE
4493
                            access_url_id = ".$urlId."
4494
                            $drhConditions
4495
                            $userConditions
4496
                    )
4497
                    $teacherSelect
4498
4499
                ) as t1";
4500
4501
        if ($getSql) {
4502
            return $sql;
4503
        }
4504
        if ($getCount) {
4505
            $result = Database::query($sql);
4506
            $row = Database::fetch_array($result);
4507
4508
            return $row['count'];
4509
        }
4510
4511
        $orderBy = null;
4512
        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...
4513
            if (api_is_western_name_order()) {
4514
                $orderBy .= " ORDER BY firstname, lastname ";
4515
            } else {
4516
                $orderBy .= " ORDER BY lastname, firstname ";
4517
            }
4518
4519
            if (!empty($column) && !empty($direction)) {
4520
                // Fixing order due the UNIONs
4521
                $column = str_replace('u.', '', $column);
4522
                $orderBy = " ORDER BY `$column` $direction ";
4523
            }
4524
        }
4525
4526
        $sql .= $orderBy;
4527
        $sql .= $limitCondition;
4528
4529
        $result = Database::query($sql);
4530
        $users = [];
4531
        if (Database::num_rows($result) > 0) {
4532
            while ($row = Database::fetch_array($result)) {
4533
                $users[$row['user_id']] = $row;
4534
            }
4535
        }
4536
4537
        return $users;
4538
    }
4539
4540
    /**
4541
     * Subscribes users to human resource manager (Dashboard feature).
4542
     *
4543
     * @param int   $hr_dept_id
4544
     * @param array $users_id
4545
     * @param bool  $deleteOtherAssignedUsers
4546
     *
4547
     * @return int
4548
     */
4549
    public static function subscribeUsersToHRManager(
4550
        $hr_dept_id,
4551
        $users_id,
4552
        $deleteOtherAssignedUsers = true
4553
    ) {
4554
        return self::subscribeUsersToUser(
4555
            $hr_dept_id,
4556
            $users_id,
4557
            USER_RELATION_TYPE_RRHH,
4558
            false,
4559
            $deleteOtherAssignedUsers
4560
        );
4561
    }
4562
4563
    /**
4564
     * Register request to assign users to HRM.
4565
     *
4566
     * @param int   $hrmId   The HRM ID
4567
     * @param array $usersId The users IDs
4568
     *
4569
     * @return int
4570
     */
4571
    public static function requestUsersToHRManager($hrmId, $usersId)
4572
    {
4573
        return self::subscribeUsersToUser(
4574
            $hrmId,
4575
            $usersId,
4576
            USER_RELATION_TYPE_HRM_REQUEST,
4577
            false,
4578
            false
4579
        );
4580
    }
4581
4582
    /**
4583
     * Remove the requests for assign a user to a HRM.
4584
     *
4585
     * @param array $usersId List of user IDs from whom to remove all relations requests with HRM
4586
     */
4587
    public static function clearHrmRequestsForUser(User $hrmId, $usersId)
4588
    {
4589
        $users = implode(', ', $usersId);
4590
        Database::getManager()
4591
            ->createQuery('
4592
                DELETE FROM ChamiloCoreBundle:UserRelUser uru
4593
                WHERE uru.friendUserId = :hrm_id AND uru.relationType = :relation_type AND uru.userId IN (:users_ids)
4594
            ')
4595
            ->execute(['hrm_id' => $hrmId, 'relation_type' => USER_RELATION_TYPE_HRM_REQUEST, 'users_ids' => $users]);
4596
    }
4597
4598
    /**
4599
     * Add subscribed users to a user by relation type.
4600
     *
4601
     * @param int    $userId                   The user id
4602
     * @param array  $subscribedUsersId        The id of subscribed users
4603
     * @param string $relationType             The relation type
4604
     * @param bool   $deleteUsersBeforeInsert
4605
     * @param bool   $deleteOtherAssignedUsers
4606
     *
4607
     * @return int
4608
     */
4609
    public static function subscribeUsersToUser(
4610
        $userId,
4611
        $subscribedUsersId,
4612
        $relationType,
4613
        $deleteUsersBeforeInsert = false,
4614
        $deleteOtherAssignedUsers = true
4615
    ) {
4616
        $userRelUserTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4617
        $userRelAccessUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
4618
4619
        $userId = (int) $userId;
4620
        $relationType = (int) $relationType;
4621
        $affectedRows = 0;
4622
4623
        if ($deleteOtherAssignedUsers) {
4624
            if (api_get_multiple_access_url()) {
4625
                // Deleting assigned users to hrm_id
4626
                $sql = "SELECT s.user_id
4627
                        FROM $userRelUserTable s
4628
                        INNER JOIN $userRelAccessUrlTable a
4629
                        ON (a.user_id = s.user_id)
4630
                        WHERE
4631
                            friend_user_id = $userId AND
4632
                            relation_type = $relationType AND
4633
                            access_url_id = ".api_get_current_access_url_id();
4634
            } else {
4635
                $sql = "SELECT user_id
4636
                        FROM $userRelUserTable
4637
                        WHERE
4638
                            friend_user_id = $userId AND
4639
                            relation_type = $relationType";
4640
            }
4641
            $result = Database::query($sql);
4642
4643
            if (Database::num_rows($result) > 0) {
4644
                while ($row = Database::fetch_array($result)) {
4645
                    $sql = "DELETE FROM $userRelUserTable
4646
                            WHERE
4647
                                user_id = {$row['user_id']} AND
4648
                                friend_user_id = $userId AND
4649
                                relation_type = $relationType";
4650
                    Database::query($sql);
4651
                }
4652
            }
4653
        }
4654
4655
        if ($deleteUsersBeforeInsert) {
4656
            $sql = "DELETE FROM $userRelUserTable
4657
                    WHERE
4658
                        user_id = $userId AND
4659
                        relation_type = $relationType";
4660
            Database::query($sql);
4661
        }
4662
4663
        // Inserting new user list
4664
        if (is_array($subscribedUsersId)) {
4665
            foreach ($subscribedUsersId as $subscribedUserId) {
4666
                $subscribedUserId = (int) $subscribedUserId;
4667
                $sql = "SELECT id
4668
                        FROM $userRelUserTable
4669
                        WHERE
4670
                            user_id = $subscribedUserId AND
4671
                            friend_user_id = $userId AND
4672
                            relation_type = $relationType";
4673
4674
                $result = Database::query($sql);
4675
                $num = Database::num_rows($result);
4676
                if (0 === $num) {
4677
                    $date = api_get_utc_datetime();
4678
                    $sql = "INSERT INTO $userRelUserTable (user_id, friend_user_id, relation_type, last_edit)
4679
                            VALUES ($subscribedUserId, $userId, $relationType, '$date')";
4680
                    $result = Database::query($sql);
4681
                    $affectedRows += Database::affected_rows($result);
4682
                }
4683
            }
4684
        }
4685
4686
        return $affectedRows;
4687
    }
4688
4689
    /**
4690
     * This function check if an user is followed by human resources manager.
4691
     *
4692
     * @param int $user_id
4693
     * @param int $hr_dept_id Human resources manager
4694
     *
4695
     * @return bool
4696
     */
4697
    public static function is_user_followed_by_drh($user_id, $hr_dept_id)
4698
    {
4699
        $tbl_user_rel_user = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4700
        $user_id = (int) $user_id;
4701
        $hr_dept_id = (int) $hr_dept_id;
4702
        $result = false;
4703
4704
        $sql = "SELECT user_id FROM $tbl_user_rel_user
4705
                WHERE
4706
                    user_id = $user_id AND
4707
                    friend_user_id = $hr_dept_id AND
4708
                    relation_type = ".USER_RELATION_TYPE_RRHH;
4709
        $rs = Database::query($sql);
4710
        if (Database::num_rows($rs) > 0) {
4711
            $result = true;
4712
        }
4713
4714
        return $result;
4715
    }
4716
4717
    /**
4718
     * Return the user id of teacher or session administrator.
4719
     *
4720
     * @param array $courseInfo
4721
     *
4722
     * @return mixed The user id, or false if the session ID was negative
4723
     */
4724
    public static function get_user_id_of_course_admin_or_session_admin($courseInfo)
4725
    {
4726
        $session = api_get_session_id();
4727
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
4728
        $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4729
        $table_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4730
4731
        if (empty($courseInfo)) {
4732
            return false;
4733
        }
4734
4735
        $courseId = $courseInfo['real_id'];
4736
4737
        if (0 == $session || is_null($session)) {
4738
            $sql = 'SELECT u.id uid FROM '.$table_user.' u
4739
                    INNER JOIN '.$table_course_user.' ru
4740
                    ON ru.user_id = u.id
4741
                    WHERE
4742
                        ru.status = 1 AND
4743
                        ru.c_id = "'.$courseId.'" ';
4744
            $rs = Database::query($sql);
4745
            $num_rows = Database::num_rows($rs);
4746
            if (1 == $num_rows) {
4747
                $row = Database::fetch_array($rs);
4748
4749
                return $row['uid'];
4750
            } else {
4751
                $my_num_rows = $num_rows;
4752
                $my_user_id = Database::result($rs, $my_num_rows - 1, 'uid');
4753
4754
                return $my_user_id;
4755
            }
4756
        } elseif ($session > 0) {
4757
            $sql = 'SELECT u.id uid FROM '.$table_user.' u
4758
                    INNER JOIN '.$table_session_course_user.' sru
4759
                    ON sru.user_id=u.id
4760
                    WHERE
4761
                        sru.c_id="'.$courseId.'" AND
4762
                        sru.status=2';
4763
            $rs = Database::query($sql);
4764
            $row = Database::fetch_array($rs);
4765
4766
            return $row['uid'];
4767
        }
4768
4769
        return false;
4770
    }
4771
4772
    /**
4773
     * Determines if a user is a gradebook certified.
4774
     *
4775
     * @param int $cat_id  The category id of gradebook
4776
     * @param int $user_id The user id
4777
     *
4778
     * @return bool
4779
     */
4780
    public static function is_user_certified($cat_id, $user_id)
4781
    {
4782
        $cat_id = (int) $cat_id;
4783
        $user_id = (int) $user_id;
4784
4785
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
4786
        $sql = 'SELECT path_certificate
4787
                FROM '.$table.'
4788
                WHERE
4789
                    cat_id = "'.$cat_id.'" AND
4790
                    user_id = "'.$user_id.'"';
4791
        $rs = Database::query($sql);
4792
        $row = Database::fetch_array($rs);
4793
4794
        if ('' == $row['path_certificate'] || is_null($row['path_certificate'])) {
4795
            return false;
4796
        }
4797
4798
        return true;
4799
    }
4800
4801
    /**
4802
     * Gets the info about a gradebook certificate for a user by course.
4803
     *
4804
     * @param array $course_info The course code
4805
     * @param int   $session_id
4806
     * @param int   $user_id     The user id
4807
     *
4808
     * @return array if there is not information return false
4809
     */
4810
    public static function get_info_gradebook_certificate($course_info, $session_id, $user_id)
4811
    {
4812
        $tbl_grade_certificate = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
4813
        $tbl_grade_category = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
4814
        $session_id = (int) $session_id;
4815
        $user_id = (int) $user_id;
4816
        $courseId = $course_info['real_id'];
4817
4818
        if (empty($session_id)) {
4819
            $session_condition = ' AND (session_id = "" OR session_id = 0 OR session_id IS NULL )';
4820
        } else {
4821
            $session_condition = " AND session_id = $session_id";
4822
        }
4823
4824
        $sql = 'SELECT * FROM '.$tbl_grade_certificate.'
4825
                WHERE cat_id = (
4826
                    SELECT id FROM '.$tbl_grade_category.'
4827
                    WHERE
4828
                        c_id = "'.$courseId.'" '.$session_condition.'
4829
                    LIMIT 1
4830
                ) AND user_id='.$user_id;
4831
4832
        $rs = Database::query($sql);
4833
        if (Database::num_rows($rs) > 0) {
4834
            $row = Database::fetch_array($rs, 'ASSOC');
4835
            $score = $row['score_certificate'];
4836
            $category_id = $row['cat_id'];
4837
            $cat = Category::load($category_id);
4838
            $displayscore = ScoreDisplay::instance();
4839
            if (isset($cat) && $displayscore->is_custom()) {
4840
                $grade = $displayscore->display_score(
4841
                    [$score, $cat[0]->get_weight()],
4842
                    SCORE_DIV_PERCENT_WITH_CUSTOM
4843
                );
4844
            } else {
4845
                $grade = $displayscore->display_score(
4846
                    [$score, $cat[0]->get_weight()]
4847
                );
4848
            }
4849
            $row['grade'] = $grade;
4850
4851
            return $row;
4852
        }
4853
4854
        return false;
4855
    }
4856
4857
    /**
4858
     * This function check if the user is a coach inside session course.
4859
     *
4860
     * @param int $user_id    User id
4861
     * @param int $courseId
4862
     * @param int $session_id
4863
     *
4864
     * @return bool True if the user is a coach
4865
     */
4866
    public static function is_session_course_coach($user_id, $courseId, $session_id)
4867
    {
4868
        $table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4869
        // Protect data
4870
        $user_id = intval($user_id);
4871
        $courseId = intval($courseId);
4872
        $session_id = intval($session_id);
4873
        $result = false;
4874
4875
        $sql = "SELECT session_id FROM $table
4876
                WHERE
4877
                  session_id = $session_id AND
4878
                  c_id = $courseId AND
4879
                  user_id = $user_id AND
4880
                  status = 2 ";
4881
        $res = Database::query($sql);
4882
4883
        if (Database::num_rows($res) > 0) {
4884
            $result = true;
4885
        }
4886
4887
        return $result;
4888
    }
4889
4890
    /**
4891
     * This function returns an icon path that represents the favicon of the website of which the url given.
4892
     * Defaults to the current Chamilo favicon.
4893
     *
4894
     * @param string $url1 URL of website where to look for favicon.ico
4895
     * @param string $url2 Optional second URL of website where to look for favicon.ico
4896
     *
4897
     * @return string Path of icon to load
4898
     */
4899
    public static function get_favicon_from_url($url1, $url2 = null)
4900
    {
4901
        $icon_link = '';
4902
        $url = $url1;
4903
        if (empty($url1)) {
4904
            $url = $url2;
4905
            if (empty($url)) {
4906
                $url = api_get_access_url(api_get_current_access_url_id());
4907
                $url = $url[0];
4908
            }
4909
        }
4910
        if (!empty($url)) {
4911
            $pieces = parse_url($url);
4912
            $icon_link = $pieces['scheme'].'://'.$pieces['host'].'/favicon.ico';
4913
        }
4914
4915
        return $icon_link;
4916
    }
4917
4918
    public static function addUserAsAdmin(User $user)
4919
    {
4920
        $userId = $user->getId();
4921
4922
        if (!self::is_admin($userId)) {
4923
            $table = Database::get_main_table(TABLE_MAIN_ADMIN);
4924
            $sql = "INSERT INTO $table SET user_id = $userId";
4925
            Database::query($sql);
4926
        }
4927
4928
        $user->addRole('ROLE_SUPER_ADMIN');
4929
        self::getRepository()->updateUser($user, true);
4930
    }
4931
4932
    public static function removeUserAdmin(User $user)
4933
    {
4934
        $userId = (int) $user->getId();
4935
        if (self::is_admin($userId)) {
4936
            $table = Database::get_main_table(TABLE_MAIN_ADMIN);
4937
            $sql = "DELETE FROM $table WHERE user_id = $userId";
4938
            Database::query($sql);
4939
            $user->removeRole('ROLE_SUPER_ADMIN');
4940
            self::getRepository()->updateUser($user, true);
4941
        }
4942
    }
4943
4944
    /**
4945
     * @param string $from
4946
     * @param string $to
4947
     */
4948
    public static function update_all_user_languages($from, $to)
4949
    {
4950
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
4951
        $from = Database::escape_string($from);
4952
        $to = Database::escape_string($to);
4953
4954
        if (!empty($to) && !empty($from)) {
4955
            $sql = "UPDATE $table_user SET language = '$to'
4956
                    WHERE language = '$from'";
4957
            Database::query($sql);
4958
        }
4959
    }
4960
4961
    /**
4962
     * Subscribe boss to students.
4963
     *
4964
     * @param int   $bossId                   The boss id
4965
     * @param array $usersId                  The users array
4966
     * @param bool  $deleteOtherAssignedUsers
4967
     *
4968
     * @return int Affected rows
4969
     */
4970
    public static function subscribeBossToUsers($bossId, $usersId, $deleteOtherAssignedUsers = true)
4971
    {
4972
        return self::subscribeUsersToUser(
4973
            $bossId,
4974
            $usersId,
4975
            USER_RELATION_TYPE_BOSS,
4976
            false,
4977
            $deleteOtherAssignedUsers
4978
        );
4979
    }
4980
4981
    /**
4982
     * @param int $userId
4983
     *
4984
     * @return bool
4985
     */
4986
    public static function removeAllBossFromStudent($userId)
4987
    {
4988
        $userId = (int) $userId;
4989
4990
        if (empty($userId)) {
4991
            return false;
4992
        }
4993
4994
        $userRelUserTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4995
        $sql = "DELETE FROM $userRelUserTable
4996
                WHERE user_id = $userId AND relation_type = ".USER_RELATION_TYPE_BOSS;
4997
        Database::query($sql);
4998
4999
        return true;
5000
    }
5001
5002
    /**
5003
     * Subscribe boss to students, if $bossList is empty then the boss list will be empty too.
5004
     *
5005
     * @param int   $studentId
5006
     * @param array $bossList
5007
     * @param bool  $sendNotification
5008
     *
5009
     * @return mixed Affected rows or false on failure
5010
     */
5011
    public static function subscribeUserToBossList(
5012
        $studentId,
5013
        $bossList,
5014
        $sendNotification = false
5015
    ) {
5016
        $inserted = 0;
5017
        if (!empty($bossList)) {
5018
            sort($bossList);
5019
            $studentId = (int) $studentId;
5020
            $studentInfo = api_get_user_info($studentId);
5021
5022
            if (empty($studentInfo)) {
5023
                return false;
5024
            }
5025
5026
            $previousBossList = self::getStudentBossList($studentId);
5027
            $previousBossList = !empty($previousBossList) ? array_column($previousBossList, 'boss_id') : [];
5028
            sort($previousBossList);
5029
5030
            // Boss list is the same, nothing changed.
5031
            if ($bossList == $previousBossList) {
5032
                return false;
5033
            }
5034
5035
            $userRelUserTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5036
            self::removeAllBossFromStudent($studentId);
5037
5038
            foreach ($bossList as $bossId) {
5039
                $bossId = (int) $bossId;
5040
                $bossInfo = api_get_user_info($bossId);
5041
5042
                if (empty($bossInfo)) {
5043
                    continue;
5044
                }
5045
5046
                $bossLanguage = $bossInfo['language'];
5047
                $sql = "INSERT IGNORE INTO $userRelUserTable (user_id, friend_user_id, relation_type)
5048
                        VALUES ($studentId, $bossId, ".USER_RELATION_TYPE_BOSS.")";
5049
                $insertId = Database::query($sql);
5050
5051
                if ($insertId) {
5052
                    if ($sendNotification) {
5053
                        $name = $studentInfo['complete_name'];
5054
                        $url = api_get_path(WEB_CODE_PATH).'mySpace/myStudents.php?student='.$studentId;
5055
                        $url = Display::url($url, $url);
5056
                        $subject = sprintf(get_lang('You have been assigned the learner %s'), $name);
5057
                        $message = sprintf(get_lang('You have been assigned the learner %sWithUrlX'), $name, $url);
5058
                        MessageManager::send_message_simple(
5059
                            $bossId,
5060
                            $subject,
5061
                            $message
5062
                        );
5063
                    }
5064
                    $inserted++;
5065
                }
5066
            }
5067
        } else {
5068
            self::removeAllBossFromStudent($studentId);
5069
        }
5070
5071
        return $inserted;
5072
    }
5073
5074
    /**
5075
     * Get users followed by student boss.
5076
     *
5077
     * @param int    $userId
5078
     * @param int    $userStatus         (STUDENT, COURSEMANAGER, etc)
5079
     * @param bool   $getOnlyUserId
5080
     * @param bool   $getSql
5081
     * @param bool   $getCount
5082
     * @param int    $from
5083
     * @param int    $numberItems
5084
     * @param int    $column
5085
     * @param string $direction
5086
     * @param int    $active
5087
     * @param string $lastConnectionDate
5088
     *
5089
     * @return array users
5090
     */
5091
    public static function getUsersFollowedByStudentBoss(
5092
        $userId,
5093
        $userStatus = 0,
5094
        $getOnlyUserId = false,
5095
        $getSql = false,
5096
        $getCount = false,
5097
        $from = null,
5098
        $numberItems = null,
5099
        $column = null,
5100
        $direction = null,
5101
        $active = null,
5102
        $lastConnectionDate = null
5103
    ) {
5104
        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...
5105
            $userId,
5106
            $userStatus,
5107
            $getOnlyUserId,
5108
            $getSql,
5109
            $getCount,
5110
            $from,
5111
            $numberItems,
5112
            $column,
5113
            $direction,
5114
            $active,
5115
            $lastConnectionDate,
5116
            STUDENT_BOSS
5117
        );
5118
    }
5119
5120
    /**
5121
     * @return array
5122
     */
5123
    public static function getOfficialCodeGrouped()
5124
    {
5125
        $user = Database::get_main_table(TABLE_MAIN_USER);
5126
        $sql = "SELECT DISTINCT official_code
5127
                FROM $user
5128
                GROUP BY official_code";
5129
        $result = Database::query($sql);
5130
        $values = Database::store_result($result, 'ASSOC');
5131
        $result = [];
5132
        foreach ($values as $value) {
5133
            $result[$value['official_code']] = $value['official_code'];
5134
        }
5135
5136
        return $result;
5137
    }
5138
5139
    /**
5140
     * @param string $officialCode
5141
     *
5142
     * @return array
5143
     */
5144
    public static function getUsersByOfficialCode($officialCode)
5145
    {
5146
        $user = Database::get_main_table(TABLE_MAIN_USER);
5147
        $officialCode = Database::escape_string($officialCode);
5148
5149
        $sql = "SELECT DISTINCT id
5150
                FROM $user
5151
                WHERE official_code = '$officialCode'
5152
                ";
5153
        $result = Database::query($sql);
5154
5155
        $users = [];
5156
        while ($row = Database::fetch_array($result)) {
5157
            $users[] = $row['id'];
5158
        }
5159
5160
        return $users;
5161
    }
5162
5163
    /**
5164
     * Calc the expended time (in seconds) by a user in a course.
5165
     *
5166
     * @param int    $userId    The user id
5167
     * @param int    $courseId  The course id
5168
     * @param int    $sessionId Optional. The session id
5169
     * @param string $from      Optional. From date
5170
     * @param string $until     Optional. Until date
5171
     *
5172
     * @return int The time
5173
     */
5174
    public static function getTimeSpentInCourses(
5175
        $userId,
5176
        $courseId,
5177
        $sessionId = 0,
5178
        $from = '',
5179
        $until = ''
5180
    ) {
5181
        $userId = (int) $userId;
5182
        $sessionId = (int) $sessionId;
5183
5184
        $trackCourseAccessTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5185
        $whereConditions = [
5186
            'user_id = ? ' => $userId,
5187
            'AND c_id = ? ' => $courseId,
5188
            'AND session_id = ? ' => $sessionId,
5189
        ];
5190
5191
        if (!empty($from) && !empty($until)) {
5192
            $whereConditions["AND (login_course_date >= '?' "] = $from;
5193
            $whereConditions["AND logout_course_date <= DATE_ADD('?', INTERVAL 1 DAY)) "] = $until;
5194
        }
5195
5196
        $trackResult = Database::select(
5197
            'SUM(UNIX_TIMESTAMP(logout_course_date) - UNIX_TIMESTAMP(login_course_date)) as total_time',
5198
            $trackCourseAccessTable,
5199
            [
5200
                'where' => $whereConditions,
5201
            ],
5202
            'first'
5203
        );
5204
5205
        if (false != $trackResult) {
5206
            return $trackResult['total_time'] ? $trackResult['total_time'] : 0;
5207
        }
5208
5209
        return 0;
5210
    }
5211
5212
    /**
5213
     * Get the boss user ID from a followed user id.
5214
     *
5215
     * @param $userId
5216
     *
5217
     * @return bool
5218
     */
5219
    public static function getFirstStudentBoss($userId)
5220
    {
5221
        $userId = (int) $userId;
5222
        if ($userId > 0) {
5223
            $userRelTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5224
            $row = Database::select(
5225
                'DISTINCT friend_user_id AS boss_id',
5226
                $userRelTable,
5227
                [
5228
                    'where' => [
5229
                        'user_id = ? AND relation_type = ? LIMIT 1' => [
5230
                            $userId,
5231
                            USER_RELATION_TYPE_BOSS,
5232
                        ],
5233
                    ],
5234
                ]
5235
            );
5236
            if (!empty($row)) {
5237
                return $row[0]['boss_id'];
5238
            }
5239
        }
5240
5241
        return false;
5242
    }
5243
5244
    /**
5245
     * Get the boss user ID from a followed user id.
5246
     *
5247
     * @param int $userId student id
5248
     *
5249
     * @return array
5250
     */
5251
    public static function getStudentBossList($userId)
5252
    {
5253
        $userId = (int) $userId;
5254
5255
        if ($userId > 0) {
5256
            $userRelTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5257
5258
            return Database::select(
5259
                'DISTINCT friend_user_id AS boss_id',
5260
                $userRelTable,
5261
                [
5262
                    'where' => [
5263
                        'user_id = ? AND relation_type = ? ' => [
5264
                            $userId,
5265
                            USER_RELATION_TYPE_BOSS,
5266
                        ],
5267
                    ],
5268
                ]
5269
            );
5270
        }
5271
5272
        return [];
5273
    }
5274
5275
    /**
5276
     * @param int $bossId
5277
     * @param int $studentId
5278
     *
5279
     * @return bool
5280
     */
5281
    public static function userIsBossOfStudent($bossId, $studentId)
5282
    {
5283
        $result = false;
5284
        $bossList = self::getStudentBossList($studentId);
5285
        if (!empty($bossList)) {
5286
            $bossList = array_column($bossList, 'boss_id');
5287
            if (in_array($bossId, $bossList)) {
5288
                $result = true;
5289
            }
5290
        }
5291
5292
        return $result;
5293
    }
5294
5295
    /**
5296
     * Displays the name of the user and makes the link to the user profile.
5297
     *
5298
     * @param array $userInfo
5299
     *
5300
     * @return string
5301
     */
5302
    public static function getUserProfileLink($userInfo)
5303
    {
5304
        if (isset($userInfo) && isset($userInfo['user_id'])) {
5305
            return Display::url(
5306
                $userInfo['complete_name_with_username'],
5307
                $userInfo['profile_url']
5308
            );
5309
        }
5310
5311
        return get_lang('Anonymous');
5312
    }
5313
5314
    /**
5315
     * Get users whose name matches $firstname and $lastname.
5316
     *
5317
     * @param string $firstname Firstname to search
5318
     * @param string $lastname  Lastname to search
5319
     *
5320
     * @return array The user list
5321
     */
5322
    public static function getUsersByName($firstname, $lastname)
5323
    {
5324
        $firstname = Database::escape_string($firstname);
5325
        $lastname = Database::escape_string($lastname);
5326
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
5327
5328
        $sql = <<<SQL
5329
            SELECT id, username, lastname, firstname
5330
            FROM $userTable
5331
            WHERE
5332
                firstname LIKE '$firstname%' AND
5333
                lastname LIKE '$lastname%'
5334
SQL;
5335
        $result = Database::query($sql);
5336
        $users = [];
5337
        while ($resultData = Database::fetch_object($result)) {
5338
            $users[] = $resultData;
5339
        }
5340
5341
        return $users;
5342
    }
5343
5344
    /**
5345
     * @param int $optionSelected
5346
     *
5347
     * @return string
5348
     */
5349
    public static function getUserSubscriptionTab($optionSelected = 1)
5350
    {
5351
        $allowAdmin = api_get_setting('allow_user_course_subscription_by_course_admin');
5352
        if (('true' === $allowAdmin && api_is_allowed_to_edit()) ||
5353
            api_is_platform_admin()
5354
        ) {
5355
            $userPath = api_get_path(WEB_CODE_PATH).'user/';
5356
5357
            $headers = [
5358
                [
5359
                    'url' => $userPath.'user.php?'.api_get_cidreq().'&type='.STUDENT,
5360
                    'content' => get_lang('Learners'),
5361
                ],
5362
                [
5363
                    'url' => $userPath.'user.php?'.api_get_cidreq().'&type='.COURSEMANAGER,
5364
                    'content' => get_lang('Trainers'),
5365
                ],
5366
                /*[
5367
                    'url' => $userPath.'subscribe_user.php?'.api_get_cidreq(),
5368
                    'content' => get_lang('Learners'),
5369
                ],
5370
                [
5371
                    'url' => $userPath.'subscribe_user.php?type=teacher&'.api_get_cidreq(),
5372
                    'content' => get_lang('Trainers'),
5373
                ],*/
5374
                [
5375
                    'url' => api_get_path(WEB_CODE_PATH).'group/group.php?'.api_get_cidreq(),
5376
                    'content' => get_lang('Groups'),
5377
                ],
5378
                [
5379
                    'url' => $userPath.'class.php?'.api_get_cidreq(),
5380
                    'content' => get_lang('Classes'),
5381
                ],
5382
            ];
5383
5384
            return Display::tabsOnlyLink($headers, $optionSelected);
5385
        }
5386
5387
        return '';
5388
    }
5389
5390
    /**
5391
     * Make sure this function is protected because it does NOT check password!
5392
     *
5393
     * This function defines globals.
5394
     *
5395
     * @param int  $userId
5396
     * @param bool $checkIfUserCanLoginAs
5397
     *
5398
     * @return bool
5399
     *
5400
     * @author Evie Embrechts
5401
     * @author Yannick Warnier <[email protected]>
5402
     */
5403
    public static function loginAsUser($userId, $checkIfUserCanLoginAs = true)
5404
    {
5405
        $userId = (int) $userId;
5406
        $userInfo = api_get_user_info($userId);
5407
5408
        // Check if the user is allowed to 'login_as'
5409
        $canLoginAs = true;
5410
        if ($checkIfUserCanLoginAs) {
5411
            $canLoginAs = api_can_login_as($userId);
5412
        }
5413
5414
        if (!$canLoginAs || empty($userInfo)) {
5415
            return false;
5416
        }
5417
5418
        if ($userId) {
5419
            $logInfo = [
5420
                'tool' => 'logout',
5421
                'tool_id' => 0,
5422
                'tool_id_detail' => 0,
5423
                'action' => '',
5424
                'info' => 'Change user (login as)',
5425
            ];
5426
            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

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