Passed
Push — master ( 26ffea...1a7924 )
by Julito
09:14
created

UserManager::setPasswordEncryption()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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

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

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

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

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

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

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

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

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