Passed
Push — master ( 4ed902...760dff )
by Julito
11:06 queued 11s
created

UserManager::show_menu()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

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

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