Passed
Push — master ( a81919...251179 )
by Julito
15:43 queued 07:28
created

UserManager::anonymize()   F

Complexity

Conditions 19
Paths 258

Size

Total Lines 104
Code Lines 74

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 19
eloc 74
nc 258
nop 2
dl 0
loc 104
rs 2.9583
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
    private static $encryptionMethod;
43
44
    /**
45
     * Constructor.
46
     *
47
     * @assert () === null
48
     */
49
    public function __construct()
50
    {
51
    }
52
53
    /**
54
     * Repository is use to query the DB, selects, etc.
55
     *
56
     * @return UserRepository
57
     */
58
    public static function getRepository()
59
    {
60
        return Container::getUserRepository();
61
    }
62
63
    /**
64
     * @param string $encryptionMethod
65
     */
66
    public static function setPasswordEncryption($encryptionMethod)
67
    {
68
        self::$encryptionMethod = $encryptionMethod;
69
    }
70
71
    /**
72
     * @return bool|mixed
73
     */
74
    public static function getPasswordEncryption()
75
    {
76
        $encryptionMethod = self::$encryptionMethod;
77
        if (empty($encryptionMethod)) {
78
            $encryptionMethod = api_get_configuration_value('password_encryption');
79
        }
80
81
        return $encryptionMethod;
82
    }
83
84
    /**
85
     * Validates the password.
86
     *
87
     * @param $encoded
88
     * @param $raw
89
     * @param $salt
90
     *
91
     * @return bool
92
     */
93
    public static function isPasswordValid($encoded, $raw, $salt)
94
    {
95
        $encoder = new \Chamilo\CoreBundle\Security\Encoder(self::getPasswordEncryption());
96
        $validPassword = $encoder->isPasswordValid($encoded, $raw, $salt);
97
98
        return $validPassword;
99
    }
100
101
    /**
102
     * @param int    $userId
103
     * @param string $password
104
     */
105
    public static function updatePassword($userId, $password)
106
    {
107
        $user = api_get_user_entity($userId);
108
        $userManager = self::getRepository();
109
        $user->setPlainPassword($password);
110
        $userManager->updateUser($user, true);
111
    }
112
113
    /**
114
     * Creates a new user for the platform.
115
     *
116
     * @author Hugues Peeters <[email protected]>,
117
     * @author Roan Embrechts <[email protected]>
118
     *
119
     * @param string        $firstName
120
     * @param string        $lastName
121
     * @param int           $status                  (1 for course tutor, 5 for student, 6 for anonymous)
122
     * @param string        $email
123
     * @param string        $loginName
124
     * @param string        $password
125
     * @param string        $official_code           Any official code (optional)
126
     * @param string        $language                User language    (optional)
127
     * @param string        $phone                   Phone number    (optional)
128
     * @param string        $picture_uri             Picture URI        (optional)
129
     * @param string        $authSource              Authentication source (defaults to 'platform', dependind on constant)
130
     * @param string        $expirationDate          Account expiration date (optional, defaults to null)
131
     * @param int           $active                  Whether the account is enabled or disabled by default
132
     * @param int           $hr_dept_id              The department of HR in which the user is registered (defaults to 0)
133
     * @param array         $extra                   Extra fields
134
     * @param string        $encrypt_method          Used if password is given encrypted. Set to an empty string by default
135
     * @param bool          $send_mail
136
     * @param bool          $isAdmin
137
     * @param string        $address
138
     * @param bool          $sendEmailToAllAdmins
139
     * @param FormValidator $form
140
     * @param int           $creatorId
141
     * @param array         $emailTemplate
142
     * @param string        $redirectToURLAfterLogin
143
     * @param bool          $addUserToNode
144
     *
145
     * @return mixed new user id - if the new user creation succeeds, false otherwise
146
     * @desc The function tries to retrieve user id from the session.
147
     * If it exists, the current user id is the creator id. If a problem arises,
148
     * @assert ('Sam','Gamegie',5,'[email protected]','jo','jo') > 1
149
     * @assert ('Pippin','Took',null,null,'jo','jo') === false
150
     */
151
    public static function create_user(
152
        $firstName,
153
        $lastName,
154
        $status,
155
        $email,
156
        $loginName,
157
        $password,
158
        $official_code = '',
159
        $language = '',
160
        $phone = '',
161
        $picture_uri = '',
162
        $authSource = null,
163
        $expirationDate = null,
164
        $active = 1,
165
        $hr_dept_id = 0,
166
        $extra = [],
167
        $encrypt_method = '',
168
        $send_mail = false,
169
        $isAdmin = false,
170
        $address = '',
171
        $sendEmailToAllAdmins = false,
172
        $form = null,
173
        $creatorId = 0,
174
        $emailTemplate = [],
175
        $redirectToURLAfterLogin = '',
176
        $addUserToNode = true,
177
        $addUserToUrl = true
178
    ) {
179
        $authSource = !empty($authSource) ? $authSource : PLATFORM_AUTH_SOURCE;
180
        $creatorId = empty($creatorId) ? api_get_user_id() : 0;
181
        $creatorInfo = api_get_user_info($creatorId);
182
        $creatorEmail = isset($creatorInfo['email']) ? $creatorInfo['email'] : '';
183
184
        // First check wether the login already exists
185
        if (!self::is_username_available($loginName)) {
186
            Display::addFlash(
187
                Display::return_message(get_lang('This login is already taken !'))
188
            );
189
190
            return false;
191
        }
192
193
        global $_configuration;
194
        $original_password = $password;
195
196
        $access_url_id = 1;
197
        if (api_get_multiple_access_url()) {
198
            $access_url_id = api_get_current_access_url_id();
199
        } else {
200
            // In some cases, the first access_url ID might be different from 1
201
            // for example when using a DB cluster or hacking the DB manually.
202
            // In this case, we want the first row, not necessarily "1".
203
            $accessUrlRepository = Container::getAccessUrlRepository();
204
            $accessUrl = $accessUrlRepository->getFirstId();
205
            if (!empty($accessUrl[0]) && !empty($accessUrl[0][1])) {
206
                $access_url_id = $accessUrl[0][1];
207
            }
208
        }
209
210
        if (isset($_configuration[$access_url_id]) &&
211
            is_array($_configuration[$access_url_id]) &&
212
            isset($_configuration[$access_url_id]['hosting_limit_users']) &&
213
            $_configuration[$access_url_id]['hosting_limit_users'] > 0) {
214
            $num = self::get_number_of_users();
215
            if ($num >= $_configuration[$access_url_id]['hosting_limit_users']) {
216
                api_warn_hosting_contact('hosting_limit_users');
217
                Display::addFlash(
218
                    Display::return_message(
219
                        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.'),
220
                        'warning'
221
                    )
222
                );
223
224
                return false;
225
            }
226
        }
227
228
        if (1 === $status &&
229
            isset($_configuration[$access_url_id]) &&
230
            is_array($_configuration[$access_url_id]) &&
231
            isset($_configuration[$access_url_id]['hosting_limit_teachers']) &&
232
            $_configuration[$access_url_id]['hosting_limit_teachers'] > 0
233
        ) {
234
            $num = self::get_number_of_users(1);
235
            if ($num >= $_configuration[$access_url_id]['hosting_limit_teachers']) {
236
                Display::addFlash(
237
                    Display::return_message(
238
                        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.'),
239
                        'warning'
240
                    )
241
                );
242
                api_warn_hosting_contact('hosting_limit_teachers');
243
244
                return false;
245
            }
246
        }
247
248
        if (empty($password)) {
249
            if (PLATFORM_AUTH_SOURCE === $authSource) {
250
                Display::addFlash(
251
                    Display::return_message(
252
                        get_lang('Required field').': '.get_lang(
253
                            'Password'
254
                        ),
255
                        'warning'
256
                    )
257
                );
258
259
                return false;
260
            }
261
262
            // We use the authSource as password.
263
            // The real validation will be by processed by the auth
264
            // source not Chamilo
265
            $password = $authSource;
266
        }
267
268
        // Checking the user language
269
        $languages = api_get_languages();
270
        $language = strtolower($language);
271
272
        // Default to english
273
        if (!in_array($language, array_keys($languages), true)) {
274
            $language = 'en';
275
        }
276
277
        $currentDate = api_get_utc_datetime();
278
        $now = new DateTime();
279
280
        if (empty($expirationDate) || '0000-00-00 00:00:00' === $expirationDate) {
281
            $expirationDate = null;
282
        // Default expiration date
283
            // if there is a default duration of a valid account then
284
            // we have to change the expiration_date accordingly
285
            // Accept 0000-00-00 00:00:00 as a null value to avoid issues with
286
            // third party code using this method with the previous (pre-1.10)
287
            // value of 0000...
288
            /*if ('' != api_get_setting('account_valid_duration')) {
289
                $expirationDate = new DateTime($currentDate);
290
                $days = (int) api_get_setting('account_valid_duration');
291
                $expirationDate->modify('+'.$days.' day');
292
            }*/
293
        } else {
294
            $expirationDate = api_get_utc_datetime($expirationDate);
295
            $expirationDate = new \DateTime($expirationDate, new DateTimeZone('UTC'));
296
        }
297
298
        $user = new User();
299
        $user
300
            ->setLastname($lastName)
301
            ->setFirstname($firstName)
302
            ->setUsername($loginName)
303
            ->setStatus($status)
304
            ->setPlainPassword($password)
305
            ->setEmail($email)
306
            ->setOfficialCode($official_code)
307
            ->setCreatorId($creatorId)
308
            ->setAuthSource($authSource)
309
            ->setPhone($phone)
310
            ->setAddress($address)
311
            ->setLocale($language)
312
            ->setRegistrationDate($now)
313
            ->setHrDeptId($hr_dept_id)
314
            ->setActive($active)
315
            ->setEnabled($active)
316
            ->setTimezone(api_get_timezone())
317
        ;
318
319
        if (!empty($expirationDate)) {
320
            $user->setExpirationDate($expirationDate);
321
        }
322
323
        $em = Database::getManager();
324
        $repo = Container::getUserRepository();
325
        $repo->updateUser($user, false);
326
327
        // Add user as a node
328
        if ($addUserToNode) {
329
            $resourceNode = new ResourceNode();
330
            $resourceNode
331
                ->setTitle($loginName)
332
                ->setCreator(api_get_user_entity($creatorId))
333
                ->setResourceType($repo->getResourceType())
334
            ;
335
            $em->persist($resourceNode);
336
            $user->setResourceNode($resourceNode);
337
        }
338
339
        $em->persist($user);
340
        $em->flush();
341
342
        // Add user to a group
343
        $statusToGroup = [
344
            COURSEMANAGER => 'TEACHER',
345
            STUDENT => 'STUDENT',
346
            DRH => 'RRHH',
347
            SESSIONADMIN => 'SESSION_ADMIN',
348
            STUDENT_BOSS => 'STUDENT_BOSS',
349
            INVITEE => 'INVITEE',
350
        ];
351
352
        if (isset($statusToGroup[$status])) {
353
            $group = Container::$container->get(GroupRepository::class)->findOneBy(['code' => $statusToGroup[$status]]);
354
            if ($group) {
355
                $user->addGroup($group);
356
                $repo->updateUser($user);
357
            }
358
        }
359
360
        $em->flush();
361
362
        $userId = $user->getId();
363
364
        if (!empty($userId)) {
365
            if ($isAdmin) {
366
                self::addUserAsAdmin($user);
367
            }
368
369
            if ($addUserToUrl) {
370
                if (api_get_multiple_access_url()) {
371
                    UrlManager::add_user_to_url($userId, api_get_current_access_url_id());
372
                } else {
373
                    //we are adding by default the access_url_user table with access_url_id = 1
374
                    UrlManager::add_user_to_url($userId, 1);
375
                }
376
            }
377
378
            if (is_array($extra) && count($extra) > 0) {
379
                $extra['item_id'] = $userId;
380
                $courseFieldValue = new ExtraFieldValue('user');
381
                $courseFieldValue->saveFieldValues($extra);
382
            } else {
383
                // Create notify settings by default
384
                self::update_extra_field_value(
385
                    $userId,
386
                    'mail_notify_invitation',
387
                    '1'
388
                );
389
                self::update_extra_field_value(
390
                    $userId,
391
                    'mail_notify_message',
392
                    '1'
393
                );
394
                self::update_extra_field_value(
395
                    $userId,
396
                    'mail_notify_group_message',
397
                    '1'
398
                );
399
            }
400
401
            self::update_extra_field_value(
402
                $userId,
403
                'already_logged_in',
404
                'false'
405
            );
406
407
            if (!empty($redirectToURLAfterLogin) && api_get_configuration_value('plugin_redirection_enabled')) {
408
                RedirectionPlugin::insert($userId, $redirectToURLAfterLogin);
409
            }
410
411
            if (!empty($email) && $send_mail) {
412
                $recipient_name = api_get_person_name(
413
                    $firstName,
414
                    $lastName,
415
                    null,
416
                    PERSON_NAME_EMAIL_ADDRESS
417
                );
418
                $tpl = Container::getTwig();
419
                $emailSubject = $tpl->render('@ChamiloCore/Mailer/Legacy/subject_registration_platform.html.twig');
420
                $sender_name = api_get_person_name(
421
                    api_get_setting('administratorName'),
422
                    api_get_setting('administratorSurname'),
423
                    null,
424
                    PERSON_NAME_EMAIL_ADDRESS
425
                );
426
                $email_admin = api_get_setting('emailAdministrator');
427
428
                $url = api_get_path(WEB_PATH);
429
                if (api_is_multiple_url_enabled()) {
430
                    $access_url_id = api_get_current_access_url_id();
431
                    if (-1 != $access_url_id) {
432
                        $urlInfo = api_get_access_url($access_url_id);
433
                        if ($urlInfo) {
434
                            $url = $urlInfo['url'];
435
                        }
436
                    }
437
                }
438
439
                // variables for the default template
440
                $params = [
441
                    'complete_name' => stripslashes(api_get_person_name($firstName, $lastName)),
442
                    'login_name' => $loginName,
443
                    'original_password' => stripslashes($original_password),
444
                    'mailWebPath' => $url,
445
                    'new_user' => $user,
446
                ];
447
448
                $emailBody = $tpl->render(
449
                    '@ChamiloCore/Mailer/Legacy/content_registration_platform.html.twig',
450
                    $params
451
                );
452
453
                $userInfo = api_get_user_info($userId);
454
                $mailTemplateManager = new MailTemplateManager();
455
                $phoneNumber = $extra['mobile_phone_number'] ?? null;
456
457
                $additionalParameters = [
458
                    'smsType' => SmsPlugin::WELCOME_LOGIN_PASSWORD,
459
                    'userId' => $userId,
460
                    'mobilePhoneNumber' => $phoneNumber,
461
                    'password' => $original_password,
462
                ];
463
464
                $emailBodyTemplate = '';
465
                if (!empty($emailTemplate)) {
466
                    if (isset($emailTemplate['content_registration_platform.tpl']) &&
467
                        !empty($emailTemplate['content_registration_platform.tpl'])
468
                    ) {
469
                        $emailBodyTemplate = $mailTemplateManager->parseTemplate(
470
                            $emailTemplate['content_registration_platform.tpl'],
471
                            $userInfo
472
                        );
473
                    }
474
                }
475
476
                $twoEmail = api_get_configuration_value('send_two_inscription_confirmation_mail');
477
                if (true === $twoEmail) {
478
                    $emailBody = $tpl->render(
479
                        '@ChamiloCore/Mailer/Legacy/new_user_first_email_confirmation.html.twig'
480
                    );
481
482
                    if (!empty($emailBodyTemplate) &&
483
                        isset($emailTemplate['new_user_first_email_confirmation.tpl']) &&
484
                        !empty($emailTemplate['new_user_first_email_confirmation.tpl'])
485
                    ) {
486
                        $emailBody = $mailTemplateManager->parseTemplate(
487
                            $emailTemplate['new_user_first_email_confirmation.tpl'],
488
                            $userInfo
489
                        );
490
                    }
491
492
                    api_mail_html(
493
                        $recipient_name,
494
                        $email,
495
                        $emailSubject,
496
                        $emailBody,
497
                        $sender_name,
498
                        $email_admin,
499
                        null,
500
                        null,
501
                        null,
502
                        $additionalParameters,
503
                        $creatorEmail
504
                    );
505
506
                    $emailBody = $tpl->render('@ChamiloCore/Mailer/Legacy/new_user_second_email_confirmation.html.twig');
507
508
                    if (!empty($emailBodyTemplate) &&
509
                        isset($emailTemplate['new_user_second_email_confirmation.tpl']) &&
510
                        !empty($emailTemplate['new_user_second_email_confirmation.tpl'])
511
                    ) {
512
                        $emailBody = $mailTemplateManager->parseTemplate(
513
                            $emailTemplate['new_user_second_email_confirmation.tpl'],
514
                            $userInfo
515
                        );
516
                    }
517
518
                    api_mail_html(
519
                        $recipient_name,
520
                        $email,
521
                        $emailSubject,
522
                        $emailBody,
523
                        $sender_name,
524
                        $email_admin,
525
                        null,
526
                        null,
527
                        null,
528
                        $additionalParameters,
529
                        $creatorEmail
530
                    );
531
                } else {
532
                    if (!empty($emailBodyTemplate)) {
533
                        $emailBody = $emailBodyTemplate;
534
                    }
535
                    $sendToInbox = api_get_configuration_value('send_inscription_msg_to_inbox');
536
                    if ($sendToInbox) {
537
                        $adminList = self::get_all_administrators();
538
                        $senderId = 1;
539
                        if (!empty($adminList)) {
540
                            $adminInfo = current($adminList);
541
                            $senderId = $adminInfo['user_id'];
542
                        }
543
544
                        MessageManager::send_message_simple(
545
                            $userId,
546
                            $emailSubject,
547
                            $emailBody,
548
                            $senderId
549
                        );
550
                    } else {
551
                        api_mail_html(
552
                            $recipient_name,
553
                            $email,
554
                            $emailSubject,
555
                            $emailBody,
556
                            $sender_name,
557
                            $email_admin,
558
                            null,
559
                            null,
560
                            null,
561
                            $additionalParameters,
562
                            $creatorEmail
563
                        );
564
                    }
565
                }
566
567
                $notification = api_get_configuration_value('send_notification_when_user_added');
568
                if (!empty($notification) && isset($notification['admins']) && is_array($notification['admins'])) {
569
                    foreach ($notification['admins'] as $adminId) {
570
                        $emailSubjectToAdmin = get_lang('The user has been added').': '.
571
                            api_get_person_name($firstName, $lastName);
572
                        MessageManager::send_message_simple($adminId, $emailSubjectToAdmin, $emailBody, $userId);
573
                    }
574
                }
575
576
                if ($sendEmailToAllAdmins) {
577
                    $adminList = self::get_all_administrators();
578
                    // variables for the default template
579
                    $renderer = FormValidator::getDefaultRenderer();
580
                    // Form template
581
                    $elementTemplate = ' {label}: {element} <br />';
582
                    $renderer->setElementTemplate($elementTemplate);
583
                    /** @var FormValidator $form */
584
                    $form->freeze(null, $elementTemplate);
585
                    $form->removeElement('submit');
586
                    $formData = $form->returnForm();
587
                    $url = api_get_path(WEB_CODE_PATH).'admin/user_information.php?user_id='.$user->getId();
588
                    $params = [
589
                        'complete_name' => stripslashes(api_get_person_name($firstName, $lastName)),
590
                        'user_added' => $user,
591
                        'link' => Display::url($url, $url),
592
                        'form' => $formData,
593
                    ];
594
                    $emailBody = $tpl->render(
595
                        '@ChamiloCore/Mailer/Legacy/content_registration_platform_to_admin.html.twig',
596
                        $params
597
                    );
598
599
                    if (!empty($emailBodyTemplate) &&
600
                        isset($emailTemplate['content_registration_platform_to_admin.tpl']) &&
601
                        !empty($emailTemplate['content_registration_platform_to_admin.tpl'])
602
                    ) {
603
                        $emailBody = $mailTemplateManager->parseTemplate(
604
                            $emailTemplate['content_registration_platform_to_admin.tpl'],
605
                            $userInfo
606
                        );
607
                    }
608
609
                    $subject = get_lang('The user has been added');
610
                    foreach ($adminList as $adminId => $data) {
611
                        MessageManager::send_message_simple(
612
                            $adminId,
613
                            $subject,
614
                            $emailBody,
615
                            $userId
616
                        );
617
                    }
618
                }
619
            }
620
            Event::addEvent(LOG_USER_CREATE, LOG_USER_ID, $userId, null, $creatorId);
621
        } else {
622
            Display::addFlash(
623
                Display::return_message(
624
                    get_lang('There happened an unknown error. Please contact the platform administrator.')
625
                )
626
            );
627
628
            return false;
629
        }
630
631
        return $userId;
632
    }
633
634
    /**
635
     * Can user be deleted? This function checks whether there's a course
636
     * in which the given user is the
637
     * only course administrator. If that is the case, the user can't be
638
     * deleted because the course would remain without a course admin.
639
     *
640
     * @param int $user_id The user id
641
     *
642
     * @return bool true if user can be deleted
643
     *
644
     * @assert (null) === false
645
     * @assert (-1) === false
646
     * @assert ('abc') === false
647
     */
648
    public static function canDeleteUser($user_id)
649
    {
650
        $deny = api_get_configuration_value('deny_delete_users');
651
652
        if ($deny) {
653
            return false;
654
        }
655
656
        $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
657
        $user_id = (int) $user_id;
658
659
        if (empty($user_id)) {
660
            return false;
661
        }
662
663
        $sql = "SELECT * FROM $table_course_user
664
                WHERE status = 1 AND user_id = ".$user_id;
665
        $res = Database::query($sql);
666
        while ($course = Database::fetch_object($res)) {
667
            $sql = "SELECT id FROM $table_course_user
668
                    WHERE status=1 AND c_id = ".intval($course->c_id);
669
            $res2 = Database::query($sql);
670
            if (1 == Database::num_rows($res2)) {
671
                return false;
672
            }
673
        }
674
675
        return true;
676
    }
677
678
    /**
679
     * Delete a user from the platform, and all its belongings. This is a
680
     * very dangerous function that should only be accessible by
681
     * super-admins. Other roles should only be able to disable a user,
682
     * which removes access to the platform but doesn't delete anything.
683
     *
684
     * @param int The ID of th user to be deleted
685
     *
686
     * @throws Exception
687
     *
688
     * @return bool true if user is successfully deleted, false otherwise
689
     * @assert (null) === false
690
     * @assert ('abc') === false
691
     */
692
    public static function delete_user($user_id)
693
    {
694
        $user_id = (int) $user_id;
695
696
        if (empty($user_id)) {
697
            return false;
698
        }
699
700
        if (!self::canDeleteUser($user_id)) {
701
            return false;
702
        }
703
704
        $usergroup_rel_user = Database::get_main_table(TABLE_USERGROUP_REL_USER);
705
        $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
706
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
707
        $table_session = Database::get_main_table(TABLE_MAIN_SESSION);
708
        $table_admin = Database::get_main_table(TABLE_MAIN_ADMIN);
709
        $table_session_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
710
        $table_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
711
        $table_group = Database::get_course_table(TABLE_GROUP_USER);
712
        $table_work = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
713
714
        $userInfo = api_get_user_info($user_id);
715
        $repository = Container::getUserRepository();
716
717
        /** @var User $user */
718
        $user = $repository->find($user_id);
719
720
        $repository->deleteUser($user);
721
722
        // Unsubscribe the user from all groups in all his courses
723
        $sql = "SELECT c.id
724
                FROM $table_course c
725
                INNER JOIN $table_course_user cu
726
                ON (c.id = cu.c_id)
727
                WHERE
728
                    cu.user_id = '".$user_id."' AND
729
                    relation_type<>".COURSE_RELATION_TYPE_RRHH."
730
                ";
731
732
        $res = Database::query($sql);
733
        while ($course = Database::fetch_object($res)) {
734
            $sql = "DELETE FROM $table_group
735
                    WHERE c_id = {$course->id} AND user_id = $user_id";
736
            Database::query($sql);
737
        }
738
739
        // Unsubscribe user from usergroup_rel_user
740
        $sql = "DELETE FROM $usergroup_rel_user WHERE user_id = '".$user_id."'";
741
        Database::query($sql);
742
743
        // Unsubscribe user from all courses
744
        $sql = "DELETE FROM $table_course_user WHERE user_id = '".$user_id."'";
745
        Database::query($sql);
746
747
        // Unsubscribe user from all courses in sessions
748
        $sql = "DELETE FROM $table_session_course_user WHERE user_id = '".$user_id."'";
749
        Database::query($sql);
750
751
        // If the user was added as a id_coach then set the current admin as coach see BT#
752
        $currentUserId = api_get_user_id();
753
        $sql = "UPDATE $table_session SET id_coach = $currentUserId
754
                WHERE id_coach = '".$user_id."'";
755
        Database::query($sql);
756
757
        $sql = "UPDATE $table_session SET id_coach = $currentUserId
758
                WHERE session_admin_id = '".$user_id."'";
759
        Database::query($sql);
760
761
        // Unsubscribe user from all sessions
762
        $sql = "DELETE FROM $table_session_user
763
                WHERE user_id = '".$user_id."'";
764
        Database::query($sql);
765
766
        if (api_get_configuration_value('plugin_redirection_enabled')) {
767
            RedirectionPlugin::deleteUserRedirection($user_id);
768
        }
769
770
        // Delete the personal course categories
771
        $course_cat_table = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
772
        $sql = "DELETE FROM $course_cat_table WHERE user_id = '".$user_id."'";
773
        Database::query($sql);
774
775
        // Delete user from the admin table
776
        $sql = "DELETE FROM $table_admin WHERE user_id = '".$user_id."'";
777
        Database::query($sql);
778
779
        // Delete the personal agenda-items from this user
780
        $agenda_table = Database::get_main_table(TABLE_PERSONAL_AGENDA);
781
        $sql = "DELETE FROM $agenda_table WHERE user = '".$user_id."'";
782
        Database::query($sql);
783
784
        $gradebook_results_table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_RESULT);
785
        $sql = 'DELETE FROM '.$gradebook_results_table.' WHERE user_id = '.$user_id;
786
        Database::query($sql);
787
788
        $extraFieldValue = new ExtraFieldValue('user');
789
        $extraFieldValue->deleteValuesByItem($user_id);
790
791
        UrlManager::deleteUserFromAllUrls($user_id);
792
        //UrlManager::deleteUserFromAllUrls($user_id);
793
794
        if ('true' === api_get_setting('allow_social_tool')) {
795
            $userGroup = new UserGroup();
796
            //Delete user from portal groups
797
            $group_list = $userGroup->get_groups_by_user($user_id);
798
            if (!empty($group_list)) {
799
                foreach ($group_list as $group_id => $data) {
800
                    $userGroup->delete_user_rel_group($user_id, $group_id);
801
                }
802
            }
803
804
            // Delete user from friend lists
805
            SocialManager::remove_user_rel_user($user_id, true);
806
        }
807
808
        // Removing survey invitation
809
        SurveyManager::delete_all_survey_invitations_by_user($user_id);
810
811
        // Delete students works
812
        /*$sql = "DELETE FROM $table_work WHERE user_id = $user_id ";
813
        Database::query($sql);*/
814
815
        /*$sql = "UPDATE c_item_property SET to_user_id = NULL
816
                WHERE to_user_id = '".$user_id."'";
817
        Database::query($sql);
818
819
        $sql = "UPDATE c_item_property SET insert_user_id = NULL
820
                WHERE insert_user_id = '".$user_id."'";
821
        Database::query($sql);
822
823
        $sql = "UPDATE c_item_property SET lastedit_user_id = NULL
824
                WHERE lastedit_user_id = '".$user_id."'";
825
        Database::query($sql);*/
826
827
        // Skills
828
        $em = Database::getManager();
829
830
        $criteria = ['user' => $user_id];
831
        $skills = $em->getRepository(SkillRelUser::class)->findBy($criteria);
832
        if ($skills) {
833
            /** @var SkillRelUser $skill */
834
            foreach ($skills as $skill) {
835
                $comments = $skill->getComments();
836
                if ($comments) {
837
                    /** @var SkillRelUserComment $comment */
838
                    foreach ($comments as $comment) {
839
                        $em->remove($comment);
840
                    }
841
                }
842
                $em->remove($skill);
843
            }
844
        }
845
846
        // ExtraFieldSavedSearch
847
        $criteria = ['user' => $user_id];
848
        $searchList = $em->getRepository(ExtraFieldSavedSearch::class)->findBy($criteria);
849
        if ($searchList) {
850
            foreach ($searchList as $search) {
851
                $em->remove($search);
852
            }
853
        }
854
855
        $connection = Database::getManager()->getConnection();
856
        $tableExists = $connection->getSchemaManager()->tablesExist(['plugin_bbb_room']);
857
        if ($tableExists) {
858
            // Delete user from database
859
            $sql = "DELETE FROM plugin_bbb_room WHERE participant_id = $user_id";
860
            Database::query($sql);
861
        }
862
863
        // Delete user/ticket relationships :(
864
        $tableExists = $connection->getSchemaManager()->tablesExist(['ticket_ticket']);
865
        if ($tableExists) {
866
            TicketManager::deleteUserFromTicketSystem($user_id);
867
        }
868
869
        $tableExists = $connection->getSchemaManager()->tablesExist(['c_lp_category_user']);
870
        if ($tableExists) {
871
            $sql = "DELETE FROM c_lp_category_user WHERE user_id = $user_id";
872
            Database::query($sql);
873
        }
874
875
        $app_plugin = new AppPlugin();
876
        $app_plugin->performActionsWhenDeletingItem('user', $user_id);
877
878
        // Add event to system log
879
        $authorId = api_get_user_id();
880
881
        Event::addEvent(
882
            LOG_USER_DELETE,
883
            LOG_USER_ID,
884
            $user_id,
885
            api_get_utc_datetime(),
886
            $authorId
887
        );
888
889
        Event::addEvent(
890
            LOG_USER_DELETE,
891
            LOG_USER_OBJECT,
892
            $userInfo,
893
            api_get_utc_datetime(),
894
            $authorId
895
        );
896
897
        return true;
898
    }
899
900
    /**
901
     * Deletes users completely. Can be called either as:
902
     * - UserManager::delete_users(1, 2, 3); or
903
     * - UserManager::delete_users(array(1, 2, 3));.
904
     *
905
     * @param array|int $ids
906
     *
907
     * @return bool True if at least one user was successfuly deleted. False otherwise.
908
     *
909
     * @author Laurent Opprecht
910
     *
911
     * @uses \UserManager::delete_user() to actually delete each user
912
     * @assert (null) === false
913
     * @assert (-1) === false
914
     * @assert (array(-1)) === false
915
     */
916
    public static function delete_users($ids = [])
917
    {
918
        $result = false;
919
        $ids = is_array($ids) ? $ids : func_get_args();
920
        if (!is_array($ids) || 0 == count($ids)) {
921
            return false;
922
        }
923
        $ids = array_map('intval', $ids);
924
        foreach ($ids as $id) {
925
            if (empty($id) || $id < 1) {
926
                continue;
927
            }
928
            $deleted = self::delete_user($id);
929
            $result = $deleted || $result;
930
        }
931
932
        return $result;
933
    }
934
935
    /**
936
     * Disable users. Can be called either as:
937
     * - UserManager::deactivate_users(1, 2, 3);
938
     * - UserManager::deactivate_users(array(1, 2, 3));.
939
     *
940
     * @param array|int $ids
941
     *
942
     * @return bool
943
     *
944
     * @author Laurent Opprecht
945
     * @assert (null) === false
946
     * @assert (array(-1)) === false
947
     */
948
    public static function deactivate_users($ids = [])
949
    {
950
        if (empty($ids)) {
951
            return false;
952
        }
953
954
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
955
956
        $ids = is_array($ids) ? $ids : func_get_args();
957
        $ids = array_map('intval', $ids);
958
        $ids = implode(',', $ids);
959
960
        $sql = "UPDATE $table_user SET active = 0 WHERE id IN ($ids)";
961
        $r = Database::query($sql);
962
        if (false !== $r) {
963
            Event::addEvent(LOG_USER_DISABLE, LOG_USER_ID, $ids);
964
965
            return true;
966
        }
967
968
        return false;
969
    }
970
971
    /**
972
     * Enable users. Can be called either as:
973
     * - UserManager::activate_users(1, 2, 3);
974
     * - UserManager::activate_users(array(1, 2, 3));.
975
     *
976
     * @param array|int IDs of the users to enable
977
     *
978
     * @return bool
979
     *
980
     * @author Laurent Opprecht
981
     * @assert (null) === false
982
     * @assert (array(-1)) === false
983
     */
984
    public static function activate_users($ids = [])
985
    {
986
        if (empty($ids)) {
987
            return false;
988
        }
989
990
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
991
992
        $ids = is_array($ids) ? $ids : func_get_args();
993
        $ids = array_map('intval', $ids);
994
        $ids = implode(',', $ids);
995
996
        $sql = "UPDATE $table_user SET active = 1 WHERE id IN ($ids)";
997
        $r = Database::query($sql);
998
        if (false !== $r) {
999
            Event::addEvent(LOG_USER_ENABLE, LOG_USER_ID, $ids);
1000
1001
            return true;
1002
        }
1003
1004
        return false;
1005
    }
1006
1007
    /**
1008
     * Update user information with all the parameters passed to this function.
1009
     *
1010
     * @param int    $user_id         The ID of the user to be updated
1011
     * @param string $firstname       The user's firstname
1012
     * @param string $lastname        The user's lastname
1013
     * @param string $username        The user's username (login)
1014
     * @param string $password        The user's password
1015
     * @param string $auth_source     The authentication source (default: "platform")
1016
     * @param string $email           The user's e-mail address
1017
     * @param int    $status          The user's status
1018
     * @param string $official_code   The user's official code (usually just an internal institutional code)
1019
     * @param string $phone           The user's phone number
1020
     * @param string $picture_uri     The user's picture URL (internal to the Chamilo directory)
1021
     * @param string $expiration_date The date at which this user will be automatically disabled
1022
     * @param int    $active          Whether this account needs to be enabled (1) or disabled (0)
1023
     * @param int    $creator_id      The user ID of the person who registered this user (optional, defaults to null)
1024
     * @param int    $hr_dept_id      The department of HR in which the user is registered (optional, defaults to 0)
1025
     * @param array  $extra           Additional fields to add to this user as extra fields (defaults to null)
1026
     * @param string $language        The language to which the user account will be set
1027
     * @param string $encrypt_method  The cipher method. This parameter is deprecated. It will use the system's default
1028
     * @param bool   $send_email      Whether to send an e-mail to the user after the update is complete
1029
     * @param int    $reset_password  Method used to reset password (0, 1, 2 or 3 - see usage examples for details)
1030
     * @param string $address
1031
     * @param array  $emailTemplate
1032
     *
1033
     * @return bool|int False on error, or the user ID if the user information was updated
1034
     * @assert (false, false, false, false, false, false, false, false, false, false, false, false, false) === false
1035
     */
1036
    public static function update_user(
1037
        $user_id,
1038
        $firstname,
1039
        $lastname,
1040
        $username,
1041
        $password,
1042
        $auth_source,
1043
        $email,
1044
        $status,
1045
        $official_code,
1046
        $phone,
1047
        $picture_uri,
1048
        $expiration_date,
1049
        $active,
1050
        $creator_id = null,
1051
        $hr_dept_id = 0,
1052
        $extra = null,
1053
        $language = 'english',
1054
        $encrypt_method = '',
1055
        $send_email = false,
1056
        $reset_password = 0,
1057
        $address = null,
1058
        $emailTemplate = []
1059
    ) {
1060
        $original_password = $password;
1061
        $user_id = (int) $user_id;
1062
        $creator_id = (int) $creator_id;
1063
1064
        if (empty($user_id)) {
1065
            return false;
1066
        }
1067
1068
        $userManager = self::getRepository();
1069
        $user = api_get_user_entity($user_id);
1070
1071
        if (empty($user)) {
1072
            return false;
1073
        }
1074
1075
        if (0 == $reset_password) {
1076
            $password = null;
1077
            $auth_source = $user->getAuthSource();
1078
        } elseif (1 == $reset_password) {
1079
            $original_password = $password = api_generate_password();
1080
            $auth_source = PLATFORM_AUTH_SOURCE;
1081
        } elseif (2 == $reset_password) {
1082
            $password = $password;
1083
            $auth_source = PLATFORM_AUTH_SOURCE;
1084
        } elseif (3 == $reset_password) {
1085
            $password = $password;
1086
            $auth_source = $auth_source;
1087
        }
1088
1089
        // Checking the user language
1090
        $languages = array_keys(api_get_languages());
1091
        if (!in_array($language, $languages)) {
1092
            $language = api_get_setting('platformLanguage');
1093
        }
1094
1095
        $change_active = 0;
1096
        $isUserActive = $user->getActive();
1097
        if ($isUserActive != $active) {
1098
            $change_active = 1;
1099
        }
1100
1101
        $originalUsername = $user->getUsername();
1102
1103
        // If username is different from original then check if it exists.
1104
        if ($originalUsername !== $username) {
1105
            $available = self::is_username_available($username);
1106
            if (false === $available) {
1107
                return false;
1108
            }
1109
        }
1110
1111
        if (!empty($expiration_date)) {
1112
            $expiration_date = api_get_utc_datetime($expiration_date);
1113
            $expiration_date = new \DateTime(
1114
                $expiration_date,
1115
                new DateTimeZone('UTC')
1116
            );
1117
        }
1118
1119
        $user
1120
            ->setLastname($lastname)
1121
            ->setFirstname($firstname)
1122
            ->setUsername($username)
1123
            ->setStatus($status)
1124
            ->setAuthSource($auth_source)
1125
            ->setLocale($language)
1126
            ->setLocale($language)
1127
            ->setEmail($email)
1128
            ->setOfficialCode($official_code)
1129
            ->setPhone($phone)
1130
            ->setAddress($address)
1131
            //->setPictureUri($picture_uri)
1132
            ->setExpirationDate($expiration_date)
1133
            ->setActive($active)
1134
            ->setEnabled($active)
1135
            ->setHrDeptId((int) $hr_dept_id)
1136
        ;
1137
1138
        if (!is_null($password)) {
1139
            $user->setPlainPassword($password);
1140
        }
1141
1142
        $statusToGroup = [
1143
            COURSEMANAGER => 'TEACHER',
1144
            STUDENT => 'STUDENT',
1145
            DRH => 'RRHH',
1146
            SESSIONADMIN => 'SESSION_ADMIN',
1147
            STUDENT_BOSS => 'STUDENT_BOSS',
1148
            INVITEE => 'INVITEE',
1149
        ];
1150
1151
        $group = Container::$container->get(GroupRepository::class)->findOneBy(['code' => $statusToGroup[$status]]);
1152
        if ($group) {
1153
            $user->addGroup($group);
1154
        }
1155
1156
        $userManager->updateUser($user, true);
1157
        Event::addEvent(LOG_USER_UPDATE, LOG_USER_ID, $user_id);
1158
1159
        if (1 == $change_active) {
1160
            if (1 == $active) {
1161
                $event_title = LOG_USER_ENABLE;
1162
            } else {
1163
                $event_title = LOG_USER_DISABLE;
1164
            }
1165
            Event::addEvent($event_title, LOG_USER_ID, $user_id);
1166
        }
1167
1168
        if (is_array($extra) && count($extra) > 0) {
1169
            $res = true;
1170
            foreach ($extra as $fname => $fvalue) {
1171
                $res = $res && self::update_extra_field_value(
1172
                    $user_id,
1173
                    $fname,
1174
                    $fvalue
1175
                );
1176
            }
1177
        }
1178
1179
        if (!empty($email) && $send_email) {
1180
            $recipient_name = api_get_person_name($firstname, $lastname, null, PERSON_NAME_EMAIL_ADDRESS);
1181
            $emailsubject = '['.api_get_setting('siteName').'] '.get_lang('Your registration on').' '.api_get_setting('siteName');
1182
            $sender_name = api_get_person_name(
1183
                api_get_setting('administratorName'),
1184
                api_get_setting('administratorSurname'),
1185
                null,
1186
                PERSON_NAME_EMAIL_ADDRESS
1187
            );
1188
            $email_admin = api_get_setting('emailAdministrator');
1189
            $url = api_get_path(WEB_PATH);
1190
            if (api_is_multiple_url_enabled()) {
1191
                $access_url_id = api_get_current_access_url_id();
1192
                if (-1 != $access_url_id) {
1193
                    $url = api_get_access_url($access_url_id);
1194
                    $url = $url['url'];
1195
                }
1196
            }
1197
1198
            $tplContent = new Template(
1199
                null,
1200
                false,
1201
                false,
1202
                false,
1203
                false,
1204
                false
1205
            );
1206
            // variables for the default template
1207
            $tplContent->assign('complete_name', stripslashes(api_get_person_name($firstname, $lastname)));
1208
            $tplContent->assign('login_name', $username);
1209
1210
            $originalPassword = '';
1211
            if ($reset_password > 0) {
1212
                $originalPassword = stripslashes($original_password);
1213
            }
1214
            $tplContent->assign('original_password', $originalPassword);
1215
            $tplContent->assign('portal_url', $url);
1216
1217
            $layoutContent = $tplContent->get_template('mail/user_edit_content.tpl');
1218
            $emailBody = $tplContent->fetch($layoutContent);
1219
1220
            $mailTemplateManager = new MailTemplateManager();
1221
1222
            if (!empty($emailTemplate) &&
1223
                isset($emailTemplate['user_edit_content.tpl']) &&
1224
                !empty($emailTemplate['user_edit_content.tpl'])
1225
            ) {
1226
                $userInfo = api_get_user_info($user_id);
1227
                $emailBody = $mailTemplateManager->parseTemplate($emailTemplate['user_edit_content.tpl'], $userInfo);
1228
            }
1229
1230
            $creatorInfo = api_get_user_info($creator_id);
1231
            $creatorEmail = isset($creatorInfo['email']) ? $creatorInfo['email'] : '';
1232
1233
            api_mail_html(
1234
                $recipient_name,
1235
                $email,
1236
                $emailsubject,
1237
                $emailBody,
1238
                $sender_name,
1239
                $email_admin,
1240
                null,
1241
                null,
1242
                null,
1243
                null,
1244
                $creatorEmail
1245
            );
1246
        }
1247
1248
        $cacheAvailable = api_get_configuration_value('apc');
1249
        if (true === $cacheAvailable) {
1250
            $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$user_id;
1251
            if (apcu_exists($apcVar)) {
1252
                apcu_delete($apcVar);
1253
            }
1254
        }
1255
1256
        return $user->getId();
1257
    }
1258
1259
    /**
1260
     * Disables a user.
1261
     *
1262
     * @param int User id
1263
     *
1264
     * @return bool
1265
     *
1266
     * @uses \UserManager::change_active_state() to actually disable the user
1267
     * @assert (0) === false
1268
     */
1269
    public static function disable($user_id)
1270
    {
1271
        if (empty($user_id)) {
1272
            return false;
1273
        }
1274
        self::change_active_state($user_id, 0);
1275
1276
        return true;
1277
    }
1278
1279
    /**
1280
     * Enable a user.
1281
     *
1282
     * @param int User id
1283
     *
1284
     * @return bool
1285
     *
1286
     * @uses \UserManager::change_active_state() to actually disable the user
1287
     * @assert (0) === false
1288
     */
1289
    public static function enable($user_id)
1290
    {
1291
        if (empty($user_id)) {
1292
            return false;
1293
        }
1294
        self::change_active_state($user_id, 1);
1295
1296
        return true;
1297
    }
1298
1299
    /**
1300
     * Returns the user's id based on the original id and field name in
1301
     * the extra fields. Returns 0 if no user was found. This function is
1302
     * mostly useful in the context of a web services-based sinchronization.
1303
     *
1304
     * @param string Original user id
1305
     * @param string Original field name
1306
     *
1307
     * @return int User id
1308
     * @assert ('0','---') === 0
1309
     */
1310
    public static function get_user_id_from_original_id(
1311
        $original_user_id_value,
1312
        $original_user_id_name
1313
    ) {
1314
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
1315
        $t_ufv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1316
        $extraFieldType = EntityExtraField::USER_FIELD_TYPE;
1317
1318
        $original_user_id_name = Database::escape_string($original_user_id_name);
1319
        $original_user_id_value = Database::escape_string($original_user_id_value);
1320
1321
        $sql = "SELECT item_id as user_id
1322
                FROM $t_uf uf
1323
                INNER JOIN $t_ufv ufv
1324
                ON ufv.field_id = uf.id
1325
                WHERE
1326
                    variable = '$original_user_id_name' AND
1327
                    value = '$original_user_id_value' AND
1328
                    extra_field_type = $extraFieldType
1329
                ";
1330
        $res = Database::query($sql);
1331
        $row = Database::fetch_object($res);
1332
        if ($row) {
1333
            return $row->user_id;
1334
        }
1335
1336
        return 0;
1337
    }
1338
1339
    /**
1340
     * Check if a username is available.
1341
     *
1342
     * @param string $username the wanted username
1343
     *
1344
     * @return bool true if the wanted username is available
1345
     * @assert ('') === false
1346
     * @assert ('xyzxyzxyz') === true
1347
     */
1348
    public static function is_username_available($username)
1349
    {
1350
        if (empty($username)) {
1351
            return false;
1352
        }
1353
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
1354
        $sql = "SELECT username FROM $table_user
1355
                WHERE username = '".Database::escape_string($username)."'";
1356
        $res = Database::query($sql);
1357
1358
        return 0 == Database::num_rows($res);
1359
    }
1360
1361
    /**
1362
     * Creates a username using person's names, i.e. creates jmontoya from Julio Montoya.
1363
     *
1364
     * @param string $firstname the first name of the user
1365
     * @param string $lastname  the last name of the user
1366
     *
1367
     * @return string suggests a username that contains only ASCII-letters and digits,
1368
     *                without check for uniqueness within the system
1369
     *
1370
     * @author Julio Montoya Armas
1371
     * @author Ivan Tcholakov, 2009 - rework about internationalization.
1372
     * @assert ('','') === false
1373
     * @assert ('a','b') === 'ab'
1374
     */
1375
    public static function create_username($firstname, $lastname)
1376
    {
1377
        if (empty($firstname) && empty($lastname)) {
1378
            return false;
1379
        }
1380
1381
        // The first letter only.
1382
        $firstname = api_substr(
1383
            preg_replace(USERNAME_PURIFIER, '', $firstname),
1384
            0,
1385
            1
1386
        );
1387
        //Looking for a space in the lastname
1388
        $pos = api_strpos($lastname, ' ');
1389
        if (false !== $pos) {
1390
            $lastname = api_substr($lastname, 0, $pos);
1391
        }
1392
1393
        $lastname = preg_replace(USERNAME_PURIFIER, '', $lastname);
1394
        $username = $firstname.$lastname;
1395
        if (empty($username)) {
1396
            $username = 'user';
1397
        }
1398
1399
        $username = URLify::transliterate($username);
1400
1401
        return strtolower(substr($username, 0, USERNAME_MAX_LENGTH - 3));
1402
    }
1403
1404
    /**
1405
     * Creates a unique username, using:
1406
     * 1. the first name and the last name of a user;
1407
     * 2. an already created username but not checked for uniqueness yet.
1408
     *
1409
     * @param string $firstname The first name of a given user. If the second parameter $lastname is NULL, then this
1410
     *                          parameter is treated as username which is to be checked f
1411
     *                          or uniqueness and to be modified when it is necessary.
1412
     * @param string $lastname  the last name of the user
1413
     *
1414
     * @return string Returns a username that contains only ASCII-letters and digits and that is unique in the system.
1415
     *                Note: When the method is called several times with same parameters,
1416
     *                its results look like the following sequence: ivan, ivan2, ivan3, ivan4, ...
1417
     *
1418
     * @author Ivan Tcholakov, 2009
1419
     */
1420
    public static function create_unique_username($firstname, $lastname = null)
1421
    {
1422
        if (is_null($lastname)) {
1423
            // In this case the actual input parameter $firstname should contain ASCII-letters and digits only.
1424
            // For making this method tolerant of mistakes,
1425
            // let us transliterate and purify the suggested input username anyway.
1426
            // So, instead of the sentence $username = $firstname; we place the following:
1427
            $username = strtolower(preg_replace(USERNAME_PURIFIER, '', $firstname));
1428
        } else {
1429
            $username = self::create_username($firstname, $lastname);
1430
        }
1431
        if (!self::is_username_available($username)) {
1432
            $i = 2;
1433
            $temp_username = substr($username, 0, USERNAME_MAX_LENGTH - strlen((string) $i)).$i;
1434
            while (!self::is_username_available($temp_username)) {
1435
                $i++;
1436
                $temp_username = substr($username, 0, USERNAME_MAX_LENGTH - strlen((string) $i)).$i;
1437
            }
1438
            $username = $temp_username;
1439
        }
1440
1441
        $username = URLify::transliterate($username);
1442
1443
        return $username;
1444
    }
1445
1446
    /**
1447
     * Modifies a given username accordingly to the specification for valid characters and length.
1448
     *
1449
     * @param $username string          The input username
1450
     * @param bool $strict (optional)   When this flag is TRUE, the result is guaranteed for full compliance,
1451
     *                     otherwise compliance may be partial. The default value is FALSE.
1452
     *
1453
     * @return string the resulting purified username
1454
     */
1455
    public static function purify_username($username, $strict = false)
1456
    {
1457
        if ($strict) {
1458
            // 1. Conversion of unacceptable letters (latinian letters with accents for example)
1459
            // into ASCII letters in order they not to be totally removed.
1460
            // 2. Applying the strict purifier.
1461
            // 3. Length limitation.
1462
            $return = 'true' === api_get_setting('login_is_email') ? substr(preg_replace(USERNAME_PURIFIER_MAIL, '', $username), 0, USERNAME_MAX_LENGTH) : substr(preg_replace(USERNAME_PURIFIER, '', $username), 0, USERNAME_MAX_LENGTH);
1463
            $return = URLify::transliterate($return);
1464
1465
            return $return;
1466
        }
1467
1468
        // 1. Applying the shallow purifier.
1469
        // 2. Length limitation.
1470
        return substr(
1471
            preg_replace(USERNAME_PURIFIER_SHALLOW, '', $username),
1472
            0,
1473
            USERNAME_MAX_LENGTH
1474
        );
1475
    }
1476
1477
    /**
1478
     * Checks whether the user id exists in the database.
1479
     *
1480
     * @param int $userId User id
1481
     *
1482
     * @return bool True if user id was found, false otherwise
1483
     */
1484
    public static function is_user_id_valid($userId)
1485
    {
1486
        $resultData = Database::select(
1487
            'COUNT(1) AS count',
1488
            Database::get_main_table(TABLE_MAIN_USER),
1489
            [
1490
                'where' => ['id = ?' => (int) $userId],
1491
            ],
1492
            'first'
1493
        );
1494
1495
        if (false === $resultData) {
1496
            return false;
1497
        }
1498
1499
        return $resultData['count'] > 0;
1500
    }
1501
1502
    /**
1503
     * Checks whether a given username matches to the specification strictly.
1504
     * The empty username is assumed here as invalid.
1505
     * Mostly this function is to be used in the user interface built-in validation routines
1506
     * for providing feedback while usernames are enterd manually.
1507
     *
1508
     * @param string $username the input username
1509
     *
1510
     * @return bool returns TRUE if the username is valid, FALSE otherwise
1511
     */
1512
    public static function is_username_valid($username)
1513
    {
1514
        return !empty($username) && $username == self::purify_username($username, true);
1515
    }
1516
1517
    /**
1518
     * Checks whether a username is empty. If the username contains whitespace characters,
1519
     * such as spaces, tabulators, newlines, etc.,
1520
     * it is assumed as empty too. This function is safe for validation unpurified data (during importing).
1521
     *
1522
     * @param string $username the given username
1523
     *
1524
     * @return bool returns TRUE if length of the username exceeds the limit, FALSE otherwise
1525
     */
1526
    public static function is_username_empty($username)
1527
    {
1528
        return 0 == strlen(self::purify_username($username, false));
1529
    }
1530
1531
    /**
1532
     * Checks whether a username is too long or not.
1533
     *
1534
     * @param string $username the given username, it should contain only ASCII-letters and digits
1535
     *
1536
     * @return bool returns TRUE if length of the username exceeds the limit, FALSE otherwise
1537
     */
1538
    public static function is_username_too_long($username)
1539
    {
1540
        return strlen($username) > USERNAME_MAX_LENGTH;
1541
    }
1542
1543
    /**
1544
     * Get the users by ID.
1545
     *
1546
     * @param array  $ids    student ids
1547
     * @param string $active
1548
     * @param string $order
1549
     * @param string $limit
1550
     *
1551
     * @return array $result student information
1552
     */
1553
    public static function get_user_list_by_ids($ids = [], $active = null, $order = null, $limit = null)
1554
    {
1555
        if (empty($ids)) {
1556
            return [];
1557
        }
1558
1559
        $ids = is_array($ids) ? $ids : [$ids];
1560
        $ids = array_map('intval', $ids);
1561
        $ids = implode(',', $ids);
1562
1563
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
1564
        $sql = "SELECT * FROM $tbl_user WHERE id IN ($ids)";
1565
        if (!is_null($active)) {
1566
            $sql .= ' AND active='.($active ? '1' : '0');
1567
        }
1568
1569
        if (!is_null($order)) {
1570
            $order = Database::escape_string($order);
1571
            $sql .= ' ORDER BY '.$order;
1572
        }
1573
1574
        if (!is_null($limit)) {
1575
            $limit = Database::escape_string($limit);
1576
            $sql .= ' LIMIT '.$limit;
1577
        }
1578
1579
        $rs = Database::query($sql);
1580
        $result = [];
1581
        while ($row = Database::fetch_array($rs)) {
1582
            $result[] = $row;
1583
        }
1584
1585
        return $result;
1586
    }
1587
1588
    /**
1589
     * Get a list of users of which the given conditions match with an = 'cond'.
1590
     *
1591
     * @param array $conditions a list of condition (example : status=>STUDENT)
1592
     * @param array $order_by   a list of fields on which sort
1593
     *
1594
     * @return array an array with all users of the platform
1595
     *
1596
     * @todo security filter order by
1597
     */
1598
    public static function get_user_list(
1599
        $conditions = [],
1600
        $order_by = [],
1601
        $limit_from = false,
1602
        $limit_to = false,
1603
        $idCampus = null
1604
    ) {
1605
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
1606
        $userUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1607
        $return_array = [];
1608
        $sql = "SELECT user.*, user.id as user_id FROM $user_table user ";
1609
1610
        if (api_is_multiple_url_enabled()) {
1611
            if ($idCampus) {
1612
                $urlId = $idCampus;
1613
            } else {
1614
                $urlId = api_get_current_access_url_id();
1615
            }
1616
            $sql .= " INNER JOIN $userUrlTable url_user
1617
                      ON (user.id = url_user.user_id)
1618
                      WHERE url_user.access_url_id = $urlId";
1619
        } else {
1620
            $sql .= " WHERE 1=1 ";
1621
        }
1622
1623
        if (count($conditions) > 0) {
1624
            foreach ($conditions as $field => $value) {
1625
                $field = Database::escape_string($field);
1626
                $value = Database::escape_string($value);
1627
                $sql .= " AND $field = '$value'";
1628
            }
1629
        }
1630
1631
        if (count($order_by) > 0) {
1632
            $sql .= ' ORDER BY '.Database::escape_string(implode(',', $order_by));
1633
        }
1634
1635
        if (is_numeric($limit_from) && is_numeric($limit_from)) {
1636
            $limit_from = (int) $limit_from;
1637
            $limit_to = (int) $limit_to;
1638
            $sql .= " LIMIT $limit_from, $limit_to";
1639
        }
1640
        $sql_result = Database::query($sql);
1641
        while ($result = Database::fetch_array($sql_result)) {
1642
            $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1643
            $return_array[] = $result;
1644
        }
1645
1646
        return $return_array;
1647
    }
1648
1649
    public static function getUserListExtraConditions(
1650
        $conditions = [],
1651
        $order_by = [],
1652
        $limit_from = false,
1653
        $limit_to = false,
1654
        $idCampus = null,
1655
        $extraConditions = '',
1656
        $getCount = false
1657
    ) {
1658
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
1659
        $userUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1660
        $return_array = [];
1661
        $sql = "SELECT user.*, user.id as user_id FROM $user_table user ";
1662
1663
        if ($getCount) {
1664
            $sql = "SELECT count(user.id) count FROM $user_table user ";
1665
        }
1666
1667
        if (api_is_multiple_url_enabled()) {
1668
            if ($idCampus) {
1669
                $urlId = $idCampus;
1670
            } else {
1671
                $urlId = api_get_current_access_url_id();
1672
            }
1673
            $sql .= " INNER JOIN $userUrlTable url_user
1674
                      ON (user.user_id = url_user.user_id)
1675
                      WHERE url_user.access_url_id = $urlId";
1676
        } else {
1677
            $sql .= " WHERE 1=1 ";
1678
        }
1679
1680
        $sql .= " AND status <> ".ANONYMOUS." ";
1681
1682
        if (count($conditions) > 0) {
1683
            foreach ($conditions as $field => $value) {
1684
                $field = Database::escape_string($field);
1685
                $value = Database::escape_string($value);
1686
                $sql .= " AND $field = '$value'";
1687
            }
1688
        }
1689
1690
        $sql .= str_replace("\'", "'", Database::escape_string($extraConditions));
1691
1692
        if (!empty($order_by) && count($order_by) > 0) {
1693
            $sql .= ' ORDER BY '.Database::escape_string(implode(',', $order_by));
1694
        }
1695
1696
        if (is_numeric($limit_from) && is_numeric($limit_from)) {
1697
            $limit_from = (int) $limit_from;
1698
            $limit_to = (int) $limit_to;
1699
            $sql .= " LIMIT $limit_from, $limit_to";
1700
        }
1701
1702
        $sql_result = Database::query($sql);
1703
1704
        if ($getCount) {
1705
            $result = Database::fetch_array($sql_result);
1706
1707
            return $result['count'];
1708
        }
1709
1710
        while ($result = Database::fetch_array($sql_result)) {
1711
            $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1712
            $return_array[] = $result;
1713
        }
1714
1715
        return $return_array;
1716
    }
1717
1718
    /**
1719
     * Get a list of users of which the given conditions match with a LIKE '%cond%'.
1720
     *
1721
     * @param array  $conditions       a list of condition (exemple : status=>STUDENT)
1722
     * @param array  $order_by         a list of fields on which sort
1723
     * @param bool   $simple_like      Whether we want a simple LIKE 'abc' or a LIKE '%abc%'
1724
     * @param string $condition        Whether we want the filters to be combined by AND or OR
1725
     * @param array  $onlyThisUserList
1726
     *
1727
     * @return array an array with all users of the platform
1728
     *
1729
     * @todo optional course code parameter, optional sorting parameters...
1730
     * @todo security filter order_by
1731
     */
1732
    public static function getUserListLike(
1733
        $conditions = [],
1734
        $order_by = [],
1735
        $simple_like = false,
1736
        $condition = 'AND',
1737
        $onlyThisUserList = []
1738
    ) {
1739
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
1740
        $tblAccessUrlRelUser = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1741
        $return_array = [];
1742
        $sql_query = "SELECT user.id FROM $user_table user ";
1743
1744
        if (api_is_multiple_url_enabled()) {
1745
            $sql_query .= " INNER JOIN $tblAccessUrlRelUser auru ON auru.user_id = user.id ";
1746
        }
1747
1748
        $sql_query .= ' WHERE 1 = 1 ';
1749
        if (count($conditions) > 0) {
1750
            $temp_conditions = [];
1751
            foreach ($conditions as $field => $value) {
1752
                $field = Database::escape_string($field);
1753
                $value = Database::escape_string($value);
1754
                if ($simple_like) {
1755
                    $temp_conditions[] = $field." LIKE '$value%'";
1756
                } else {
1757
                    $temp_conditions[] = $field.' LIKE \'%'.$value.'%\'';
1758
                }
1759
            }
1760
            if (!empty($temp_conditions)) {
1761
                $sql_query .= ' AND '.implode(' '.$condition.' ', $temp_conditions);
1762
            }
1763
1764
            if (api_is_multiple_url_enabled()) {
1765
                $sql_query .= ' AND auru.access_url_id = '.api_get_current_access_url_id();
1766
            }
1767
        } else {
1768
            if (api_is_multiple_url_enabled()) {
1769
                $sql_query .= ' AND auru.access_url_id = '.api_get_current_access_url_id();
1770
            }
1771
        }
1772
1773
        if (!empty($onlyThisUserList)) {
1774
            $onlyThisUserListToString = implode("','", $onlyThisUserList);
1775
            $sql_query .= " AND user.id IN ('$onlyThisUserListToString') ";
1776
        }
1777
1778
        if (count($order_by) > 0) {
1779
            $sql_query .= ' ORDER BY '.Database::escape_string(implode(',', $order_by));
1780
        }
1781
1782
        $sql_result = Database::query($sql_query);
1783
        while ($result = Database::fetch_array($sql_result)) {
1784
            $userInfo = api_get_user_info($result['id']);
1785
            $return_array[] = $userInfo;
1786
        }
1787
1788
        return $return_array;
1789
    }
1790
1791
    /**
1792
     * Gets the current user image.
1793
     *
1794
     * @param string $userId
1795
     * @param int    $size        it can be USER_IMAGE_SIZE_SMALL,
1796
     *                            USER_IMAGE_SIZE_MEDIUM, USER_IMAGE_SIZE_BIG or  USER_IMAGE_SIZE_ORIGINAL
1797
     * @param bool   $addRandomId
1798
     * @param array  $userInfo    to avoid query the DB
1799
     *
1800
     * @todo add gravatar support
1801
     * @todo replace $userId with User entity
1802
     *
1803
     * @return string
1804
     */
1805
    public static function getUserPicture(
1806
        $userId,
1807
        int $size = USER_IMAGE_SIZE_MEDIUM,
1808
        $addRandomId = true,
1809
        $userInfo = []
1810
    ) {
1811
        $user = api_get_user_entity($userId);
1812
        $illustrationRepo = Container::getIllustrationRepository();
1813
1814
        switch ($size) {
1815
            case USER_IMAGE_SIZE_SMALL:
1816
                $width = 32;
1817
                break;
1818
            case USER_IMAGE_SIZE_MEDIUM:
1819
                $width = 64;
1820
                break;
1821
            case USER_IMAGE_SIZE_BIG:
1822
                $width = 128;
1823
                break;
1824
            case USER_IMAGE_SIZE_ORIGINAL:
1825
            default:
1826
                $width = 0;
1827
                break;
1828
        }
1829
1830
        $url = $illustrationRepo->getIllustrationUrl($user);
1831
        $params = [];
1832
        if (!empty($width)) {
1833
            $params['w'] = $width;
1834
        }
1835
1836
        if ($addRandomId) {
1837
            $params['rand'] = uniqid('u_', true);
1838
        }
1839
1840
        $paramsToString = '';
1841
        if (!empty($params)) {
1842
            $paramsToString = '?'.http_build_query($params);
1843
        }
1844
1845
        return $url.$paramsToString;
1846
1847
        /*
1848
        // Make sure userInfo is defined. Otherwise, define it!
1849
        if (empty($userInfo) || !is_array($userInfo) || 0 == count($userInfo)) {
1850
            if (empty($user_id)) {
1851
                return '';
1852
            } else {
1853
                $userInfo = api_get_user_info($user_id);
1854
            }
1855
        }
1856
1857
        $imageWebPath = self::get_user_picture_path_by_id(
1858
            $user_id,
1859
            'web',
1860
            $userInfo
1861
        );
1862
        $pictureWebFile = $imageWebPath['file'];
1863
        $pictureWebDir = $imageWebPath['dir'];
1864
1865
        $pictureAnonymousSize = '128';
1866
        $gravatarSize = 22;
1867
        $realSizeName = 'small_';
1868
1869
        switch ($size) {
1870
            case USER_IMAGE_SIZE_SMALL:
1871
                $pictureAnonymousSize = '32';
1872
                $realSizeName = 'small_';
1873
                $gravatarSize = 32;
1874
                break;
1875
            case USER_IMAGE_SIZE_MEDIUM:
1876
                $pictureAnonymousSize = '64';
1877
                $realSizeName = 'medium_';
1878
                $gravatarSize = 64;
1879
                break;
1880
            case USER_IMAGE_SIZE_ORIGINAL:
1881
                $pictureAnonymousSize = '128';
1882
                $realSizeName = '';
1883
                $gravatarSize = 128;
1884
                break;
1885
            case USER_IMAGE_SIZE_BIG:
1886
                $pictureAnonymousSize = '128';
1887
                $realSizeName = 'big_';
1888
                $gravatarSize = 128;
1889
                break;
1890
        }
1891
1892
        $gravatarEnabled = api_get_setting('gravatar_enabled');
1893
        $anonymousPath = Display::returnIconPath('unknown.png', $pictureAnonymousSize);
1894
        if ('unknown.jpg' == $pictureWebFile || empty($pictureWebFile)) {
1895
            if ('true' === $gravatarEnabled) {
1896
                $file = self::getGravatar(
1897
                    $imageWebPath['email'],
1898
                    $gravatarSize,
1899
                    api_get_setting('gravatar_type')
1900
                );
1901
1902
                if ($addRandomId) {
1903
                    $file .= '&rand='.uniqid();
1904
                }
1905
1906
                return $file;
1907
            }
1908
1909
            return $anonymousPath;
1910
        }
1911
1912
        if ($addRandomId) {
1913
            $picture .= '?rand='.uniqid();
1914
        }
1915
1916
        return $picture;*/
1917
    }
1918
1919
    /**
1920
     * Creates new user photos in various sizes of a user, or deletes user photos.
1921
     * Note: This method relies on configuration setting from main/inc/conf/profile.conf.php.
1922
     *
1923
     * @param int    $user_id the user internal identification number
1924
     * @param string $file    The common file name for the newly created photos.
1925
     *                        It will be checked and modified for compatibility with the file system.
1926
     *                        If full name is provided, path component is ignored.
1927
     *                        If an empty name is provided, then old user photos are deleted only,
1928
     *
1929
     * @see     UserManager::delete_user_picture() as the prefered way for deletion.
1930
     *
1931
     * @param string $source_file    the full system name of the image from which user photos will be created
1932
     * @param string $cropParameters Optional string that contents "x,y,width,height" of a cropped image format
1933
     *
1934
     * @return bool Returns the resulting common file name of created images which usually should be stored in database.
1935
     *              When deletion is requested returns empty string.
1936
     *              In case of internal error or negative validation returns FALSE.
1937
     */
1938
    public static function update_user_picture($userId, UploadedFile $file, $crop = '')
1939
    {
1940
        if (empty($userId) || empty($file)) {
1941
            return false;
1942
        }
1943
1944
        $repo = Container::getUserRepository();
1945
        $user = $repo->find($userId);
1946
        if ($user) {
1947
            $repoIllustration = Container::getIllustrationRepository();
1948
            $repoIllustration->addIllustration($user, $user, $file, $crop);
1949
        }
1950
    }
1951
1952
    /**
1953
     * Deletes user photos.
1954
     *
1955
     * @param int $userId the user internal identification number
1956
     *
1957
     * @return mixed returns empty string on success, FALSE on error
1958
     */
1959
    public static function deleteUserPicture($userId)
1960
    {
1961
        $repo = Container::getUserRepository();
1962
        $user = $repo->find($userId);
1963
        if ($user) {
1964
            $illustrationRepo = Container::getIllustrationRepository();
1965
            $illustrationRepo->deleteIllustration($user);
1966
        }
1967
    }
1968
1969
    /**
1970
     * Returns an XHTML formatted list of productions for a user, or FALSE if he
1971
     * doesn't have any.
1972
     *
1973
     * If there has been a request to remove a production, the function will return
1974
     * without building the list unless forced to do so by the optional second
1975
     * parameter. This increases performance by avoiding to read through the
1976
     * productions on the filesystem before the removal request has been carried
1977
     * out because they'll have to be re-read afterwards anyway.
1978
     *
1979
     * @param int  $user_id    User id
1980
     * @param bool $force      Optional parameter to force building after a removal request
1981
     * @param bool $showDelete
1982
     *
1983
     * @return string A string containing the XHTML code to display the production list, or FALSE
1984
     */
1985
    public static function build_production_list($user_id, $force = false, $showDelete = false)
1986
    {
1987
        if (!$force && !empty($_POST['remove_production'])) {
1988
            return true; // postpone reading from the filesystem
1989
        }
1990
1991
        $productions = self::get_user_productions($user_id);
1992
1993
        if (empty($productions)) {
1994
            return false;
1995
        }
1996
1997
        return false;
1998
1999
        $production_dir = self::getUserPathById($user_id, 'web');
2000
        $del_image = Display::returnIconPath('delete.png');
2001
        $add_image = Display::returnIconPath('archive.png');
2002
        $del_text = get_lang('Delete');
2003
        $production_list = '';
2004
        if (count($productions) > 0) {
2005
            $production_list = '<div class="files-production"><ul id="productions">';
2006
            foreach ($productions as $file) {
2007
                $production_list .= '<li>
2008
                    <img src="'.$add_image.'" />
2009
                    <a href="'.$production_dir.urlencode($file).'" target="_blank">
2010
                        '.htmlentities($file).'
2011
                    </a>';
2012
                if ($showDelete) {
2013
                    $production_list .= '&nbsp;&nbsp;
2014
                        <input
2015
                            style="width:16px;"
2016
                            type="image"
2017
                            name="remove_production['.urlencode($file).']"
2018
                            src="'.$del_image.'"
2019
                            alt="'.$del_text.'"
2020
                            title="'.$del_text.' '.htmlentities($file).'"
2021
                            onclick="javascript: return confirmation(\''.htmlentities($file).'\');" /></li>';
2022
                }
2023
            }
2024
            $production_list .= '</ul></div>';
2025
        }
2026
2027
        return $production_list;
2028
    }
2029
2030
    /**
2031
     * Returns an array with the user's productions.
2032
     *
2033
     * @param int $user_id User id
2034
     *
2035
     * @return array An array containing the user's productions
2036
     */
2037
    public static function get_user_productions($user_id)
2038
    {
2039
        return [];
2040
2041
        $production_repository = self::getUserPathById($user_id, 'system');
2042
        $productions = [];
2043
2044
        if (is_dir($production_repository)) {
2045
            $handle = opendir($production_repository);
2046
            while ($file = readdir($handle)) {
2047
                if ('.' == $file ||
2048
                    '..' == $file ||
2049
                    '.htaccess' == $file ||
2050
                    is_dir($production_repository.$file)
2051
                ) {
2052
                    // skip current/parent directory and .htaccess
2053
                    continue;
2054
                }
2055
2056
                if (preg_match('/('.$user_id.'|[0-9a-f]{13}|saved)_.+\.(png|jpg|jpeg|gif)$/i', $file)) {
2057
                    // User's photos should not be listed as productions.
2058
                    continue;
2059
                }
2060
                $productions[] = $file;
2061
            }
2062
        }
2063
2064
        return $productions;
2065
    }
2066
2067
    /**
2068
     * Remove a user production.
2069
     *
2070
     * @param int    $user_id    User id
2071
     * @param string $production The production to remove
2072
     *
2073
     * @return bool
2074
     */
2075
    public static function remove_user_production($user_id, $production)
2076
    {
2077
        throw new Exception('remove_user_production');
2078
        /*$production_path = self::get_user_picture_path_by_id($user_id, 'system');
2079
        $production_file = $production_path['dir'].$production;
2080
        if (is_file($production_file)) {
2081
            unlink($production_file);
2082
2083
            return true;
2084
        }
2085
2086
        return false;*/
2087
    }
2088
2089
    /**
2090
     * Update an extra field value for a given user.
2091
     *
2092
     * @param int    $userId   User ID
2093
     * @param string $variable Field variable name
2094
     * @param string $value    Field value
2095
     *
2096
     * @return bool true if field updated, false otherwise
2097
     */
2098
    public static function update_extra_field_value($userId, $variable, $value = '')
2099
    {
2100
        $extraFieldValue = new ExtraFieldValue('user');
2101
        $params = [
2102
            'item_id' => $userId,
2103
            'variable' => $variable,
2104
            'value' => $value,
2105
        ];
2106
2107
        return $extraFieldValue->save($params);
2108
    }
2109
2110
    /**
2111
     * Get an array of extra fields with field details (type, default value and options).
2112
     *
2113
     * @param    int    Offset (from which row)
2114
     * @param    int    Number of items
2115
     * @param    int    Column on which sorting is made
2116
     * @param    string    Sorting direction
2117
     * @param    bool    Optional. Whether we get all the fields or just the visible ones
2118
     * @param    int        Optional. Whether we get all the fields with field_filter 1 or 0 or everything
2119
     *
2120
     * @return array Extra fields details (e.g. $list[2]['type'], $list[4]['options'][2]['title']
2121
     */
2122
    public static function get_extra_fields(
2123
        $from = 0,
2124
        $number_of_items = 0,
2125
        $column = 5,
2126
        $direction = 'ASC',
2127
        $all_visibility = true,
2128
        $field_filter = null
2129
    ) {
2130
        $fields = [];
2131
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
2132
        $t_ufo = Database::get_main_table(TABLE_EXTRA_FIELD_OPTIONS);
2133
        $columns = [
2134
            'id',
2135
            'variable',
2136
            'field_type',
2137
            'display_text',
2138
            'default_value',
2139
            'field_order',
2140
            'filter',
2141
        ];
2142
        $column = (int) $column;
2143
        $sort_direction = '';
2144
        if (in_array(strtoupper($direction), ['ASC', 'DESC'])) {
2145
            $sort_direction = strtoupper($direction);
2146
        }
2147
        $extraFieldType = EntityExtraField::USER_FIELD_TYPE;
2148
        $sqlf = "SELECT * FROM $t_uf WHERE extra_field_type = $extraFieldType ";
2149
        if (!$all_visibility) {
2150
            $sqlf .= " AND visible_to_self = 1 ";
2151
        }
2152
        if (!is_null($field_filter)) {
2153
            $field_filter = (int) $field_filter;
2154
            $sqlf .= " AND filter = $field_filter ";
2155
        }
2156
        $sqlf .= " ORDER BY ".$columns[$column]." $sort_direction ";
2157
        if (0 != $number_of_items) {
2158
            $sqlf .= " LIMIT ".intval($from).','.intval($number_of_items);
2159
        }
2160
        $resf = Database::query($sqlf);
2161
        if (Database::num_rows($resf) > 0) {
2162
            while ($rowf = Database::fetch_array($resf)) {
2163
                $fields[$rowf['id']] = [
2164
                    0 => $rowf['id'],
2165
                    1 => $rowf['variable'],
2166
                    2 => $rowf['field_type'],
2167
                    3 => empty($rowf['display_text']) ? '' : $rowf['display_text'],
2168
                    4 => $rowf['default_value'],
2169
                    5 => $rowf['field_order'],
2170
                    6 => $rowf['visible_to_self'],
2171
                    7 => $rowf['changeable'],
2172
                    8 => $rowf['filter'],
2173
                    9 => [],
2174
                    10 => '<a name="'.$rowf['id'].'"></a>',
2175
                ];
2176
2177
                $sqlo = "SELECT * FROM $t_ufo
2178
                         WHERE field_id = ".$rowf['id']."
2179
                         ORDER BY option_order ASC";
2180
                $reso = Database::query($sqlo);
2181
                if (Database::num_rows($reso) > 0) {
2182
                    while ($rowo = Database::fetch_array($reso)) {
2183
                        $fields[$rowf['id']][9][$rowo['id']] = [
2184
                            0 => $rowo['id'],
2185
                            1 => $rowo['option_value'],
2186
                            2 => empty($rowo['display_text']) ? '' : $rowo['display_text'],
2187
                            3 => $rowo['option_order'],
2188
                        ];
2189
                    }
2190
                }
2191
            }
2192
        }
2193
2194
        return $fields;
2195
    }
2196
2197
    /**
2198
     * Creates a new extra field.
2199
     *
2200
     * @param string $variable    Field's internal variable name
2201
     * @param int    $fieldType   Field's type
2202
     * @param string $displayText Field's language var name
2203
     * @param string $default     Field's default value
2204
     *
2205
     * @return int
2206
     */
2207
    public static function create_extra_field(
2208
        $variable,
2209
        $fieldType,
2210
        $displayText,
2211
        $default
2212
    ) {
2213
        $extraField = new ExtraField('user');
2214
        $params = [
2215
            'variable' => $variable,
2216
            'field_type' => $fieldType,
2217
            'display_text' => $displayText,
2218
            'default_value' => $default,
2219
        ];
2220
2221
        return $extraField->save($params);
2222
    }
2223
2224
    /**
2225
     * Check if a field is available.
2226
     *
2227
     * @param string $variable
2228
     *
2229
     * @return bool
2230
     */
2231
    public static function is_extra_field_available($variable)
2232
    {
2233
        $extraField = new ExtraField('user');
2234
        $data = $extraField->get_handler_field_info_by_field_variable($variable);
2235
2236
        return !empty($data) ? true : false;
2237
    }
2238
2239
    /**
2240
     * Gets user extra fields data.
2241
     *
2242
     * @param    int    User ID
2243
     * @param    bool    Whether to prefix the fields indexes with "extra_" (might be used by formvalidator)
2244
     * @param    bool    Whether to return invisible fields as well
2245
     * @param    bool    Whether to split multiple-selection fields or not
2246
     *
2247
     * @return array Array of fields => value for the given user
2248
     */
2249
    public static function get_extra_user_data(
2250
        $user_id,
2251
        $prefix = false,
2252
        $allVisibility = true,
2253
        $splitMultiple = false,
2254
        $fieldFilter = null
2255
    ) {
2256
        $user_id = (int) $user_id;
2257
2258
        if (empty($user_id)) {
2259
            return [];
2260
        }
2261
2262
        $extra_data = [];
2263
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
2264
        $t_ufv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
2265
        $user_id = (int) $user_id;
2266
        $sql = "SELECT f.id as id, f.variable as fvar, f.field_type as type
2267
                FROM $t_uf f
2268
                WHERE
2269
                    extra_field_type = ".EntityExtraField::USER_FIELD_TYPE."
2270
                ";
2271
        $filter_cond = '';
2272
2273
        if (!$allVisibility) {
2274
            if (isset($fieldFilter)) {
2275
                $fieldFilter = (int) $fieldFilter;
2276
                $filter_cond .= " AND filter = $fieldFilter ";
2277
            }
2278
            $sql .= " AND f.visible_to_self = 1 $filter_cond ";
2279
        } else {
2280
            if (isset($fieldFilter)) {
2281
                $fieldFilter = (int) $fieldFilter;
2282
                $sql .= " AND filter = $fieldFilter ";
2283
            }
2284
        }
2285
2286
        $sql .= ' ORDER BY f.field_order';
2287
2288
        $res = Database::query($sql);
2289
        if (Database::num_rows($res) > 0) {
2290
            while ($row = Database::fetch_array($res)) {
2291
                if (self::USER_FIELD_TYPE_TAG == $row['type']) {
2292
                    $tags = self::get_user_tags_to_string($user_id, $row['id'], false);
2293
                    $extra_data['extra_'.$row['fvar']] = $tags;
2294
                } else {
2295
                    $sqlu = "SELECT value as fval
2296
                            FROM $t_ufv
2297
                            WHERE field_id=".$row['id']." AND item_id = ".$user_id;
2298
                    $resu = Database::query($sqlu);
2299
                    // get default value
2300
                    $sql_df = "SELECT default_value as fval_df FROM $t_uf
2301
                               WHERE id=".$row['id'];
2302
                    $res_df = Database::query($sql_df);
2303
2304
                    if (Database::num_rows($resu) > 0) {
2305
                        $rowu = Database::fetch_array($resu);
2306
                        $fval = $rowu['fval'];
2307
                        if (self::USER_FIELD_TYPE_SELECT_MULTIPLE == $row['type']) {
2308
                            $fval = explode(';', $rowu['fval']);
2309
                        }
2310
                    } else {
2311
                        $row_df = Database::fetch_array($res_df);
2312
                        $fval = $row_df['fval_df'];
2313
                    }
2314
                    // We get here (and fill the $extra_data array) even if there
2315
                    // is no user with data (we fill it with default values)
2316
                    if ($prefix) {
2317
                        if (self::USER_FIELD_TYPE_RADIO == $row['type']) {
2318
                            $extra_data['extra_'.$row['fvar']]['extra_'.$row['fvar']] = $fval;
2319
                        } else {
2320
                            $extra_data['extra_'.$row['fvar']] = $fval;
2321
                        }
2322
                    } else {
2323
                        if (self::USER_FIELD_TYPE_RADIO == $row['type']) {
2324
                            $extra_data['extra_'.$row['fvar']]['extra_'.$row['fvar']] = $fval;
2325
                        } else {
2326
                            $extra_data[$row['fvar']] = $fval;
2327
                        }
2328
                    }
2329
                }
2330
            }
2331
        }
2332
2333
        return $extra_data;
2334
    }
2335
2336
    /** Get extra user data by field.
2337
     * @param int    user ID
2338
     * @param string the internal variable name of the field
2339
     *
2340
     * @return array with extra data info of a user i.e array('field_variable'=>'value');
2341
     */
2342
    public static function get_extra_user_data_by_field(
2343
        $user_id,
2344
        $field_variable,
2345
        $prefix = false,
2346
        $all_visibility = true,
2347
        $splitmultiple = false
2348
    ) {
2349
        $user_id = (int) $user_id;
2350
2351
        if (empty($user_id)) {
2352
            return [];
2353
        }
2354
2355
        $extra_data = [];
2356
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
2357
        $t_ufv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
2358
2359
        $sql = "SELECT f.id as id, f.variable as fvar, f.field_type as type
2360
                FROM $t_uf f
2361
                WHERE f.variable = '$field_variable' ";
2362
2363
        if (!$all_visibility) {
2364
            $sql .= " AND f.visible_to_self = 1 ";
2365
        }
2366
2367
        $sql .= " AND extra_field_type = ".EntityExtraField::USER_FIELD_TYPE;
2368
        $sql .= " ORDER BY f.field_order ";
2369
2370
        $res = Database::query($sql);
2371
        if (Database::num_rows($res) > 0) {
2372
            while ($row = Database::fetch_array($res)) {
2373
                $sqlu = "SELECT value as fval FROM $t_ufv v
2374
                         INNER JOIN $t_uf f
2375
                         ON (v.field_id = f.id)
2376
                         WHERE
2377
                            extra_field_type = ".EntityExtraField::USER_FIELD_TYPE." AND
2378
                            field_id = ".$row['id']." AND
2379
                            item_id = ".$user_id;
2380
                $resu = Database::query($sqlu);
2381
                $fval = '';
2382
                if (Database::num_rows($resu) > 0) {
2383
                    $rowu = Database::fetch_array($resu);
2384
                    $fval = $rowu['fval'];
2385
                    if (self::USER_FIELD_TYPE_SELECT_MULTIPLE == $row['type']) {
2386
                        $fval = explode(';', $rowu['fval']);
2387
                    }
2388
                }
2389
                if ($prefix) {
2390
                    $extra_data['extra_'.$row['fvar']] = $fval;
2391
                } else {
2392
                    $extra_data[$row['fvar']] = $fval;
2393
                }
2394
            }
2395
        }
2396
2397
        return $extra_data;
2398
    }
2399
2400
    /**
2401
     * Get the extra field information for a certain field (the options as well).
2402
     *
2403
     * @param int $variable The name of the field we want to know everything about
2404
     *
2405
     * @return array Array containing all the information about the extra profile field
2406
     *               (first level of array contains field details, then 'options' sub-array contains options details,
2407
     *               as returned by the database)
2408
     *
2409
     * @author Julio Montoya
2410
     *
2411
     * @since v1.8.6
2412
     */
2413
    public static function get_extra_field_information_by_name($variable)
2414
    {
2415
        $extraField = new ExtraField('user');
2416
2417
        return $extraField->get_handler_field_info_by_field_variable($variable);
2418
    }
2419
2420
    /**
2421
     * Get the extra field information for user tag (the options as well).
2422
     *
2423
     * @param int $variable The name of the field we want to know everything about
2424
     *
2425
     * @return array Array containing all the information about the extra profile field
2426
     *               (first level of array contains field details, then 'options' sub-array contains options details,
2427
     *               as returned by the database)
2428
     *
2429
     * @author José Loguercio
2430
     *
2431
     * @since v1.11.0
2432
     */
2433
    public static function get_extra_field_tags_information_by_name($variable)
2434
    {
2435
        $extraField = new ExtraField('user');
2436
2437
        return $extraField->get_handler_field_info_by_tags($variable);
2438
    }
2439
2440
    /**
2441
     * Get all the extra field information of a certain field (also the options).
2442
     *
2443
     * @param int $fieldId the ID of the field we want to know everything of
2444
     *
2445
     * @return array $return containing all th information about the extra profile field
2446
     *
2447
     * @author Julio Montoya
2448
     *
2449
     * @deprecated
2450
     * @since v1.8.6
2451
     */
2452
    public static function get_extra_field_information($fieldId)
2453
    {
2454
        $extraField = new ExtraField('user');
2455
2456
        return $extraField->getFieldInfoByFieldId($fieldId);
2457
    }
2458
2459
    /**
2460
     * Get extra user data by value.
2461
     *
2462
     * @param string $variable       the internal variable name of the field
2463
     * @param string $value          the internal value of the field
2464
     * @param bool   $all_visibility
2465
     *
2466
     * @return array with extra data info of a user i.e array('field_variable'=>'value');
2467
     */
2468
    public static function get_extra_user_data_by_value($variable, $value, $all_visibility = true)
2469
    {
2470
        $extraFieldValue = new ExtraFieldValue('user');
2471
        $extraField = new ExtraField('user');
2472
2473
        $info = $extraField->get_handler_field_info_by_field_variable($variable);
2474
2475
        if (false === $info) {
2476
            return [];
2477
        }
2478
2479
        $data = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
2480
            $variable,
2481
            $value,
2482
            false,
2483
            false,
2484
            true
2485
        );
2486
2487
        $result = [];
2488
        if (!empty($data)) {
2489
            foreach ($data as $item) {
2490
                $result[] = $item['item_id'];
2491
            }
2492
        }
2493
2494
        return $result;
2495
    }
2496
2497
    /**
2498
     * Get extra user data by tags value.
2499
     *
2500
     * @param int    $fieldId the ID of the field we want to know everything of
2501
     * @param string $tag     the tag name for search
2502
     *
2503
     * @return array with extra data info of a user
2504
     *
2505
     * @author José Loguercio
2506
     *
2507
     * @since v1.11.0
2508
     */
2509
    public static function get_extra_user_data_by_tags($fieldId, $tag)
2510
    {
2511
        $extraField = new ExtraField('user');
2512
        $result = $extraField->getAllUserPerTag($fieldId, $tag);
2513
        $array = [];
2514
        foreach ($result as $index => $user) {
2515
            $array[] = $user['user_id'];
2516
        }
2517
2518
        return $array;
2519
    }
2520
2521
    /**
2522
     * Get extra user data by field variable.
2523
     *
2524
     * @param string $variable field variable
2525
     *
2526
     * @return array data
2527
     */
2528
    public static function get_extra_user_data_by_field_variable($variable)
2529
    {
2530
        $extraInfo = self::get_extra_field_information_by_name($variable);
2531
        $field_id = (int) $extraInfo['id'];
2532
2533
        $extraField = new ExtraFieldValue('user');
2534
        $data = $extraField->getValuesByFieldId($field_id);
2535
2536
        if (!empty($data)) {
2537
            foreach ($data as $row) {
2538
                $user_id = $row['item_id'];
2539
                $data[$user_id] = $row;
2540
            }
2541
        }
2542
2543
        return $data;
2544
    }
2545
2546
    /**
2547
     * Get extra user data tags by field variable.
2548
     *
2549
     * @param string $variable field variable
2550
     *
2551
     * @return array
2552
     */
2553
    public static function get_extra_user_data_for_tags($variable)
2554
    {
2555
        $data = self::get_extra_field_tags_information_by_name($variable);
2556
2557
        return $data;
2558
    }
2559
2560
    /**
2561
     * Gives a list of [session_category][session_id] for the current user.
2562
     *
2563
     * @param int  $user_id
2564
     * @param bool $is_time_over                 whether to fill the first element or not
2565
     *                                           (to give space for courses out of categories)
2566
     * @param bool $ignore_visibility_for_admins optional true if limit time from session is over, false otherwise
2567
     * @param bool $ignoreTimeLimit              ignore time start/end
2568
     * @param bool $getCount
2569
     *
2570
     * @return array list of statuses [session_category][session_id]
2571
     *
2572
     * @todo ensure multiple access urls are managed correctly
2573
     */
2574
    public static function get_sessions_by_category(
2575
        $user_id,
2576
        $is_time_over = true,
2577
        $ignore_visibility_for_admins = false,
2578
        $ignoreTimeLimit = false,
2579
        $getCount = false
2580
    ) {
2581
        $user_id = (int) $user_id;
2582
2583
        if (empty($user_id)) {
2584
            return [];
2585
        }
2586
2587
        $allowOrder = api_get_configuration_value('session_list_order');
2588
        $position = '';
2589
        if ($allowOrder) {
2590
            $position = ', s.position AS position ';
2591
        }
2592
2593
        // Get the list of sessions per user
2594
        $now = new DateTime('now', new DateTimeZone('UTC'));
2595
2596
        // LEFT JOIN is used for session_rel_course_rel_user because an inner
2597
        // join would not catch session-courses where the user is general
2598
        // session coach but which do not have students nor coaches registered
2599
        $dqlSelect = ' COUNT(DISTINCT s.id) ';
2600
2601
        if (!$getCount) {
2602
            $dqlSelect = " DISTINCT
2603
                s.id,
2604
                s.name,
2605
                s.accessStartDate AS access_start_date,
2606
                s.accessEndDate AS access_end_date,
2607
                s.duration,
2608
                sc.id AS session_category_id,
2609
                sc.name AS session_category_name,
2610
                sc.dateStart AS session_category_date_start,
2611
                sc.dateEnd AS session_category_date_end,
2612
                s.coachAccessStartDate AS coach_access_start_date,
2613
                s.coachAccessEndDate AS coach_access_end_date,
2614
                CASE WHEN s.accessEndDate IS NULL THEN 1 ELSE 0 END HIDDEN _isFieldNull
2615
                $position
2616
            ";
2617
        }
2618
2619
        $dql = "SELECT $dqlSelect
2620
                FROM ChamiloCoreBundle:Session AS s
2621
                LEFT JOIN ChamiloCoreBundle:SessionRelCourseRelUser AS scu WITH scu.session = s
2622
                INNER JOIN ChamiloCoreBundle:AccessUrlRelSession AS url WITH url.session = s.id
2623
                LEFT JOIN ChamiloCoreBundle:SessionCategory AS sc WITH s.category = sc ";
2624
2625
        // A single OR operation on scu.user = :user OR s.generalCoach = :user
2626
        // is awfully inefficient for large sets of data (1m25s for 58K
2627
        // sessions, BT#14115) but executing a similar query twice and grouping
2628
        // the results afterwards in PHP takes about 1/1000th of the time
2629
        // (0.1s + 0.0s) for the same set of data, so we do it this way...
2630
        $dqlStudent = $dql." WHERE scu.user = :user AND url.url = :url ";
2631
        $dqlCoach = $dql." WHERE s.generalCoach = :user AND url.url = :url ";
2632
2633
        // Default order
2634
        $order = 'ORDER BY sc.name, s.name';
2635
2636
        // Order by date if showing all sessions
2637
        $showAllSessions = true === api_get_configuration_value('show_all_sessions_on_my_course_page');
2638
        if ($showAllSessions) {
2639
            $order = 'ORDER BY s.accessStartDate';
2640
        }
2641
2642
        // Order by position
2643
        if ($allowOrder) {
2644
            $order = 'ORDER BY s.position';
2645
        }
2646
2647
        // Order by dates according to settings
2648
        $orderBySettings = api_get_configuration_value('my_courses_session_order');
2649
        if (!empty($orderBySettings) && isset($orderBySettings['field']) && isset($orderBySettings['order'])) {
2650
            $field = $orderBySettings['field'];
2651
            $orderSetting = $orderBySettings['order'];
2652
            switch ($field) {
2653
                case 'start_date':
2654
                    $order = " ORDER BY s.accessStartDate $orderSetting";
2655
                    break;
2656
                case 'end_date':
2657
                    $order = " ORDER BY s.accessEndDate $orderSetting ";
2658
                    if ('asc' == $orderSetting) {
2659
                        // Put null values at the end
2660
                        // https://stackoverflow.com/questions/12652034/how-can-i-order-by-null-in-dql
2661
                        $order = ' ORDER BY _isFieldNull asc, s.accessEndDate asc';
2662
                    }
2663
                    break;
2664
                case 'name':
2665
                    $order = " ORDER BY s.name $orderSetting ";
2666
                    break;
2667
            }
2668
        }
2669
2670
        $dqlStudent .= $order;
2671
        $dqlCoach .= $order;
2672
2673
        $accessUrlId = api_get_current_access_url_id();
2674
        $dqlStudent = Database::getManager()
2675
            ->createQuery($dqlStudent)
2676
            ->setParameters(
2677
                ['user' => $user_id, 'url' => $accessUrlId]
2678
            )
2679
        ;
2680
        $dqlCoach = Database::getManager()
2681
            ->createQuery($dqlCoach)
2682
            ->setParameters(
2683
                ['user' => $user_id, 'url' => $accessUrlId]
2684
            )
2685
        ;
2686
2687
        if ($getCount) {
2688
            return $dqlStudent->getSingleScalarResult() + $dqlCoach->getSingleScalarResult();
2689
        }
2690
2691
        $sessionDataStudent = $dqlStudent->getResult();
2692
        $sessionDataCoach = $dqlCoach->getResult();
2693
2694
        $sessionData = [];
2695
        // First fill $sessionData with student sessions
2696
        if (!empty($sessionDataStudent)) {
2697
            foreach ($sessionDataStudent as $row) {
2698
                $sessionData[$row['id']] = $row;
2699
            }
2700
        }
2701
        // Overwrite session data of the user as a student with session data
2702
        // of the user as a coach.
2703
        // There shouldn't be such duplicate rows, but just in case...
2704
        if (!empty($sessionDataCoach)) {
2705
            foreach ($sessionDataCoach as $row) {
2706
                $sessionData[$row['id']] = $row;
2707
            }
2708
        }
2709
2710
        $collapsable = api_get_configuration_value('allow_user_session_collapsable');
2711
        $extraField = new ExtraFieldValue('session');
2712
        $collapsableLink = api_get_path(WEB_PATH).'user_portal.php?action=collapse_session';
2713
2714
        if (empty($sessionData)) {
2715
            return [];
2716
        }
2717
        $categories = [];
2718
        foreach ($sessionData as $row) {
2719
            $session_id = $row['id'];
2720
            $coachList = SessionManager::getCoachesBySession($session_id);
2721
            $categoryStart = $row['session_category_date_start'] ? $row['session_category_date_start']->format('Y-m-d') : '';
2722
            $categoryEnd = $row['session_category_date_end'] ? $row['session_category_date_end']->format('Y-m-d') : '';
2723
            $courseList = self::get_courses_list_by_session($user_id, $session_id);
2724
            $daysLeft = SessionManager::getDayLeftInSession($row, $user_id);
2725
2726
            // User portal filters:
2727
            if (false === $ignoreTimeLimit) {
2728
                if ($is_time_over) {
2729
                    // History
2730
                    if ($row['duration']) {
2731
                        if ($daysLeft >= 0) {
2732
                            continue;
2733
                        }
2734
                    } else {
2735
                        if (empty($row['access_end_date'])) {
2736
                            continue;
2737
                        } else {
2738
                            if ($row['access_end_date'] > $now) {
2739
                                continue;
2740
                            }
2741
                        }
2742
                    }
2743
                } else {
2744
                    // Current user portal
2745
                    $isGeneralCoach = SessionManager::user_is_general_coach($user_id, $row['id']);
2746
                    $isCoachOfCourse = in_array($user_id, $coachList);
2747
2748
                    if (api_is_platform_admin() || $isGeneralCoach || $isCoachOfCourse) {
2749
                        // Teachers can access the session depending in the access_coach date
2750
                    } else {
2751
                        if ($row['duration']) {
2752
                            if ($daysLeft <= 0) {
2753
                                continue;
2754
                            }
2755
                        } else {
2756
                            if (isset($row['access_end_date']) &&
2757
                                !empty($row['access_end_date'])
2758
                            ) {
2759
                                if ($row['access_end_date'] <= $now) {
2760
                                    continue;
2761
                                }
2762
                            }
2763
                        }
2764
                    }
2765
                }
2766
            }
2767
2768
            $categories[$row['session_category_id']]['session_category'] = [
2769
                'id' => $row['session_category_id'],
2770
                'name' => $row['session_category_name'],
2771
                'date_start' => $categoryStart,
2772
                'date_end' => $categoryEnd,
2773
            ];
2774
2775
            $visibility = api_get_session_visibility(
2776
                $session_id,
2777
                null,
2778
                $ignore_visibility_for_admins
2779
            );
2780
2781
            if (SESSION_VISIBLE != $visibility) {
2782
                // Course Coach session visibility.
2783
                $blockedCourseCount = 0;
2784
                $closedVisibilityList = [
2785
                    COURSE_VISIBILITY_CLOSED,
2786
                    COURSE_VISIBILITY_HIDDEN,
2787
                ];
2788
2789
                foreach ($courseList as $course) {
2790
                    // Checking session visibility
2791
                    $sessionCourseVisibility = api_get_session_visibility(
2792
                        $session_id,
2793
                        $course['real_id'],
2794
                        $ignore_visibility_for_admins
2795
                    );
2796
2797
                    $courseIsVisible = !in_array($course['visibility'], $closedVisibilityList);
2798
                    if (false === $courseIsVisible || SESSION_INVISIBLE == $sessionCourseVisibility) {
2799
                        $blockedCourseCount++;
2800
                    }
2801
                }
2802
2803
                // If all courses are blocked then no show in the list.
2804
                if ($blockedCourseCount === count($courseList)) {
2805
                    $visibility = SESSION_INVISIBLE;
2806
                } else {
2807
                    $visibility = $sessionCourseVisibility;
2808
                }
2809
            }
2810
2811
            switch ($visibility) {
2812
                case SESSION_VISIBLE_READ_ONLY:
2813
                case SESSION_VISIBLE:
2814
                case SESSION_AVAILABLE:
2815
                    break;
2816
                case SESSION_INVISIBLE:
2817
                    if (false === $ignore_visibility_for_admins) {
2818
                        continue 2;
2819
                    }
2820
            }
2821
2822
            $collapsed = '';
2823
            $collapsedAction = '';
2824
            if ($collapsable) {
2825
                $collapsableData = SessionManager::getCollapsableData(
2826
                    $user_id,
2827
                    $session_id,
2828
                    $extraField,
2829
                    $collapsableLink
2830
                );
2831
                $collapsed = $collapsableData['collapsed'];
2832
                $collapsedAction = $collapsableData['collapsable_link'];
2833
            }
2834
2835
            $categories[$row['session_category_id']]['sessions'][] = [
2836
                'session_name' => $row['name'],
2837
                'session_id' => $row['id'],
2838
                'access_start_date' => $row['access_start_date'] ? $row['access_start_date']->format('Y-m-d H:i:s') : null,
2839
                'access_end_date' => $row['access_end_date'] ? $row['access_end_date']->format('Y-m-d H:i:s') : null,
2840
                'coach_access_start_date' => $row['coach_access_start_date'] ? $row['coach_access_start_date']->format('Y-m-d H:i:s') : null,
2841
                'coach_access_end_date' => $row['coach_access_end_date'] ? $row['coach_access_end_date']->format('Y-m-d H:i:s') : null,
2842
                'courses' => $courseList,
2843
                'collapsed' => $collapsed,
2844
                'collapsable_link' => $collapsedAction,
2845
                'duration' => $row['duration'],
2846
            ];
2847
        }
2848
2849
        return $categories;
2850
    }
2851
2852
    /**
2853
     * Gives a list of [session_id-course_code] => [status] for the current user.
2854
     *
2855
     * @param int $user_id
2856
     * @param int $sessionLimit
2857
     *
2858
     * @return array list of statuses (session_id-course_code => status)
2859
     */
2860
    public static function get_personal_session_course_list($user_id, $sessionLimit = null)
2861
    {
2862
        // Database Table Definitions
2863
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
2864
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
2865
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2866
        $tbl_session_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
2867
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2868
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2869
        $tblCourseCategory = Database::get_main_table(TABLE_MAIN_CATEGORY);
2870
2871
        $user_id = (int) $user_id;
2872
2873
        if (empty($user_id)) {
2874
            return [];
2875
        }
2876
2877
        // We filter the courses from the URL
2878
        $join_access_url = $where_access_url = '';
2879
        if (api_get_multiple_access_url()) {
2880
            $access_url_id = api_get_current_access_url_id();
2881
            if (-1 != $access_url_id) {
2882
                $tbl_url_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2883
                $join_access_url = "LEFT JOIN $tbl_url_course url_rel_course ON url_rel_course.c_id = course.id";
2884
                $where_access_url = " AND access_url_id = $access_url_id ";
2885
            }
2886
        }
2887
2888
        // Courses in which we subscribed out of any session
2889
        $tbl_user_course_category = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
2890
2891
        $sql = "SELECT
2892
                    course.code,
2893
                    course_rel_user.status course_rel_status,
2894
                    course_rel_user.sort sort,
2895
                    course_rel_user.user_course_cat user_course_cat
2896
                 FROM $tbl_course_user course_rel_user
2897
                 LEFT JOIN $tbl_course course
2898
                 ON course.id = course_rel_user.c_id
2899
                 LEFT JOIN $tbl_user_course_category user_course_category
2900
                 ON course_rel_user.user_course_cat = user_course_category.id
2901
                 $join_access_url
2902
                 WHERE
2903
                    course_rel_user.user_id = '".$user_id."' AND
2904
                    course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH."
2905
                    $where_access_url
2906
                 ORDER BY user_course_category.sort, course_rel_user.sort, course.title ASC";
2907
2908
        $course_list_sql_result = Database::query($sql);
2909
2910
        $personal_course_list = [];
2911
        if (Database::num_rows($course_list_sql_result) > 0) {
2912
            while ($result_row = Database::fetch_array($course_list_sql_result, 'ASSOC')) {
2913
                $course_info = api_get_course_info($result_row['code']);
2914
                $result_row['course_info'] = $course_info;
2915
                $personal_course_list[] = $result_row;
2916
            }
2917
        }
2918
2919
        $coachCourseConditions = '';
2920
        // Getting sessions that are related to a coach in the session_rel_course_rel_user table
2921
        if (api_is_allowed_to_create_course()) {
2922
            $sessionListFromCourseCoach = [];
2923
            $sql = " SELECT DISTINCT session_id
2924
                    FROM $tbl_session_course_user
2925
                    WHERE user_id = $user_id AND status = 2 ";
2926
2927
            $result = Database::query($sql);
2928
            if (Database::num_rows($result)) {
2929
                $result = Database::store_result($result);
2930
                foreach ($result as $session) {
2931
                    $sessionListFromCourseCoach[] = $session['session_id'];
2932
                }
2933
            }
2934
            if (!empty($sessionListFromCourseCoach)) {
2935
                $condition = implode("','", $sessionListFromCourseCoach);
2936
                $coachCourseConditions = " OR ( s.id IN ('$condition'))";
2937
            }
2938
        }
2939
2940
        // Get the list of sessions where the user is subscribed
2941
        // This is divided into two different queries
2942
        $sessions = [];
2943
        $sessionLimitRestriction = '';
2944
        if (!empty($sessionLimit)) {
2945
            $sessionLimit = (int) $sessionLimit;
2946
            $sessionLimitRestriction = "LIMIT $sessionLimit";
2947
        }
2948
2949
        $sql = "SELECT DISTINCT s.id, name, access_start_date, access_end_date
2950
                FROM $tbl_session_user su INNER JOIN $tbl_session s
2951
                ON (s.id = su.session_id)
2952
                WHERE (
2953
                    su.user_id = $user_id AND
2954
                    su.relation_type <> ".SESSION_RELATION_TYPE_RRHH."
2955
                )
2956
                $coachCourseConditions
2957
                ORDER BY access_start_date, access_end_date, name
2958
                $sessionLimitRestriction
2959
        ";
2960
2961
        $result = Database::query($sql);
2962
        if (Database::num_rows($result) > 0) {
2963
            while ($row = Database::fetch_assoc($result)) {
2964
                $sessions[$row['id']] = $row;
2965
            }
2966
        }
2967
2968
        $sql = "SELECT DISTINCT
2969
                id, name, access_start_date, access_end_date
2970
                FROM $tbl_session s
2971
                WHERE (
2972
                    id_coach = $user_id
2973
                )
2974
                $coachCourseConditions
2975
                ORDER BY access_start_date, access_end_date, name";
2976
2977
        $result = Database::query($sql);
2978
        if (Database::num_rows($result) > 0) {
2979
            while ($row = Database::fetch_assoc($result)) {
2980
                if (empty($sessions[$row['id']])) {
2981
                    $sessions[$row['id']] = $row;
2982
                }
2983
            }
2984
        }
2985
2986
        if (api_is_allowed_to_create_course()) {
2987
            foreach ($sessions as $enreg) {
2988
                $session_id = $enreg['id'];
2989
                $session_visibility = api_get_session_visibility($session_id);
2990
2991
                if (SESSION_INVISIBLE == $session_visibility) {
2992
                    continue;
2993
                }
2994
2995
                // This query is horribly slow when more than a few thousand
2996
                // users and just a few sessions to which they are subscribed
2997
                $sql = "SELECT DISTINCT
2998
                        course.code code,
2999
                        course.title i,
3000
                        ".(api_is_western_name_order() ? "CONCAT(user.firstname,' ',user.lastname)" : "CONCAT(user.lastname,' ',user.firstname)")." t,
3001
                        email, course.course_language l,
3002
                        1 sort,
3003
                        course_category.code user_course_cat,
3004
                        access_start_date,
3005
                        access_end_date,
3006
                        session.id as session_id,
3007
                        session.name as session_name
3008
                    FROM $tbl_session_course_user as session_course_user
3009
                    INNER JOIN $tbl_course AS course
3010
                        ON course.id = session_course_user.c_id
3011
                    LEFT JOIN $tblCourseCategory course_category ON course.category_id = course_category.id
3012
                    INNER JOIN $tbl_session as session
3013
                        ON session.id = session_course_user.session_id
3014
                    LEFT JOIN $tbl_user as user
3015
                        ON user.id = session_course_user.user_id OR session.id_coach = user.id
3016
                    WHERE
3017
                        session_course_user.session_id = $session_id AND (
3018
                            (session_course_user.user_id = $user_id AND session_course_user.status = 2)
3019
                            OR session.id_coach = $user_id
3020
                        )
3021
                    ORDER BY i";
3022
                $course_list_sql_result = Database::query($sql);
3023
                while ($result_row = Database::fetch_array($course_list_sql_result, 'ASSOC')) {
3024
                    $result_row['course_info'] = api_get_course_info($result_row['code']);
3025
                    $key = $result_row['session_id'].' - '.$result_row['code'];
3026
                    $personal_course_list[$key] = $result_row;
3027
                }
3028
            }
3029
        }
3030
3031
        foreach ($sessions as $enreg) {
3032
            $session_id = $enreg['id'];
3033
            $session_visibility = api_get_session_visibility($session_id);
3034
            if (SESSION_INVISIBLE == $session_visibility) {
3035
                continue;
3036
            }
3037
3038
            /* This query is very similar to the above query,
3039
               but it will check the session_rel_course_user table if there are courses registered to our user or not */
3040
            $sql = "SELECT DISTINCT
3041
                course.code code,
3042
                course.title i, CONCAT(user.lastname,' ',user.firstname) t,
3043
                email,
3044
                course.course_language l,
3045
                1 sort,
3046
                course_category.code user_course_cat,
3047
                access_start_date,
3048
                access_end_date,
3049
                session.id as session_id,
3050
                session.name as session_name,
3051
                IF((session_course_user.user_id = 3 AND session_course_user.status=2),'2', '5')
3052
            FROM $tbl_session_course_user as session_course_user
3053
            INNER JOIN $tbl_course AS course
3054
            ON course.id = session_course_user.c_id AND session_course_user.session_id = $session_id
3055
            LEFT JOIN $tblCourseCategory course_category ON course.category_id = course_category.id
3056
            INNER JOIN $tbl_session as session
3057
            ON session_course_user.session_id = session.id
3058
            LEFT JOIN $tbl_user as user ON user.id = session_course_user.user_id
3059
            WHERE session_course_user.user_id = $user_id
3060
            ORDER BY i";
3061
3062
            $course_list_sql_result = Database::query($sql);
3063
            while ($result_row = Database::fetch_array($course_list_sql_result, 'ASSOC')) {
3064
                $result_row['course_info'] = api_get_course_info($result_row['code']);
3065
                $key = $result_row['session_id'].' - '.$result_row['code'];
3066
                if (!isset($personal_course_list[$key])) {
3067
                    $personal_course_list[$key] = $result_row;
3068
                }
3069
            }
3070
        }
3071
3072
        return $personal_course_list;
3073
    }
3074
3075
    /**
3076
     * Gives a list of courses for the given user in the given session.
3077
     *
3078
     * @param int $user_id
3079
     * @param int $session_id
3080
     *
3081
     * @return array list of statuses (session_id-course_code => status)
3082
     */
3083
    public static function get_courses_list_by_session($user_id, $session_id)
3084
    {
3085
        // Database Table Definitions
3086
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3087
        $tableCourse = Database::get_main_table(TABLE_MAIN_COURSE);
3088
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3089
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3090
3091
        $user_id = (int) $user_id;
3092
        $session_id = (int) $session_id;
3093
        // We filter the courses from the URL
3094
        $join_access_url = $where_access_url = '';
3095
        if (api_get_multiple_access_url()) {
3096
            $urlId = api_get_current_access_url_id();
3097
            if (-1 != $urlId) {
3098
                $tbl_url_session = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
3099
                $join_access_url = " ,  $tbl_url_session url_rel_session ";
3100
                $where_access_url = " AND access_url_id = $urlId AND url_rel_session.session_id = $session_id ";
3101
            }
3102
        }
3103
3104
        /* This query is very similar to the query below, but it will check the
3105
        session_rel_course_user table if there are courses registered
3106
        to our user or not */
3107
        $sql = "SELECT DISTINCT
3108
                    c.title,
3109
                    c.visibility,
3110
                    c.id as real_id,
3111
                    c.code as course_code,
3112
                    sc.position,
3113
                    c.unsubscribe
3114
                FROM $tbl_session_course_user as scu
3115
                INNER JOIN $tbl_session_course sc
3116
                ON (scu.session_id = sc.session_id AND scu.c_id = sc.c_id)
3117
                INNER JOIN $tableCourse as c
3118
                ON (scu.c_id = c.id)
3119
                $join_access_url
3120
                WHERE
3121
                    scu.user_id = $user_id AND
3122
                    scu.session_id = $session_id
3123
                    $where_access_url
3124
                ORDER BY sc.position ASC";
3125
3126
        $myCourseList = [];
3127
        $courses = [];
3128
        $result = Database::query($sql);
3129
        if (Database::num_rows($result) > 0) {
3130
            while ($result_row = Database::fetch_array($result, 'ASSOC')) {
3131
                $result_row['status'] = 5;
3132
                if (!in_array($result_row['real_id'], $courses)) {
3133
                    $position = $result_row['position'];
3134
                    if (!isset($myCourseList[$position])) {
3135
                        $myCourseList[$position] = $result_row;
3136
                    } else {
3137
                        $myCourseList[] = $result_row;
3138
                    }
3139
                    $courses[] = $result_row['real_id'];
3140
                }
3141
            }
3142
        }
3143
3144
        if (api_is_allowed_to_create_course()) {
3145
            $sql = "SELECT DISTINCT
3146
                        c.title,
3147
                        c.visibility,
3148
                        c.id as real_id,
3149
                        c.code as course_code,
3150
                        sc.position,
3151
                        c.unsubscribe
3152
                    FROM $tbl_session_course_user as scu
3153
                    INNER JOIN $tbl_session as s
3154
                    ON (scu.session_id = s.id)
3155
                    INNER JOIN $tbl_session_course sc
3156
                    ON (scu.session_id = sc.session_id AND scu.c_id = sc.c_id)
3157
                    INNER JOIN $tableCourse as c
3158
                    ON (scu.c_id = c.id)
3159
                    $join_access_url
3160
                    WHERE
3161
                      s.id = $session_id AND
3162
                      (
3163
                        (scu.user_id = $user_id AND scu.status = 2) OR
3164
                        s.id_coach = $user_id
3165
                      )
3166
                    $where_access_url
3167
                    ORDER BY sc.position ASC";
3168
            $result = Database::query($sql);
3169
3170
            if (Database::num_rows($result) > 0) {
3171
                while ($result_row = Database::fetch_array($result, 'ASSOC')) {
3172
                    $result_row['status'] = 2;
3173
                    if (!in_array($result_row['real_id'], $courses)) {
3174
                        $position = $result_row['position'];
3175
                        if (!isset($myCourseList[$position])) {
3176
                            $myCourseList[$position] = $result_row;
3177
                        } else {
3178
                            $myCourseList[] = $result_row;
3179
                        }
3180
                        $courses[] = $result_row['real_id'];
3181
                    }
3182
                }
3183
            }
3184
        }
3185
3186
        if (api_is_drh()) {
3187
            $sessionList = SessionManager::get_sessions_followed_by_drh($user_id);
3188
            $sessionList = array_keys($sessionList);
3189
            if (in_array($session_id, $sessionList)) {
3190
                $courseList = SessionManager::get_course_list_by_session_id($session_id);
3191
                if (!empty($courseList)) {
3192
                    foreach ($courseList as $course) {
3193
                        if (!in_array($course['id'], $courses)) {
3194
                            $position = $course['position'];
3195
                            if (!isset($myCourseList[$position])) {
3196
                                $myCourseList[$position] = $course;
3197
                            } else {
3198
                                $myCourseList[] = $course;
3199
                            }
3200
                        }
3201
                    }
3202
                }
3203
            }
3204
        } else {
3205
            //check if user is general coach for this session
3206
            $sessionInfo = api_get_session_info($session_id);
3207
            if ($sessionInfo['id_coach'] == $user_id) {
3208
                $courseList = SessionManager::get_course_list_by_session_id($session_id);
3209
                if (!empty($courseList)) {
3210
                    foreach ($courseList as $course) {
3211
                        if (!in_array($course['id'], $courses)) {
3212
                            $position = $course['position'];
3213
                            if (!isset($myCourseList[$position])) {
3214
                                $myCourseList[$position] = $course;
3215
                            } else {
3216
                                $myCourseList[] = $course;
3217
                            }
3218
                        }
3219
                    }
3220
                }
3221
            }
3222
        }
3223
3224
        if (!empty($myCourseList)) {
3225
            ksort($myCourseList);
3226
            $checkPosition = array_filter(array_column($myCourseList, 'position'));
3227
            if (empty($checkPosition)) {
3228
                // The session course list doesn't have any position,
3229
                // then order the course list by course code
3230
                $list = array_column($myCourseList, 'course_code');
3231
                array_multisort($myCourseList, SORT_ASC, $list);
3232
            }
3233
        }
3234
3235
        return $myCourseList;
3236
    }
3237
3238
    /**
3239
     * Get user id from a username.
3240
     *
3241
     * @param string $username
3242
     *
3243
     * @return int User ID (or false if not found)
3244
     */
3245
    public static function get_user_id_from_username($username)
3246
    {
3247
        if (empty($username)) {
3248
            return false;
3249
        }
3250
        $username = trim($username);
3251
        $username = Database::escape_string($username);
3252
        $t_user = Database::get_main_table(TABLE_MAIN_USER);
3253
        $sql = "SELECT id FROM $t_user WHERE username = '$username'";
3254
        $res = Database::query($sql);
3255
3256
        if (false === $res) {
3257
            return false;
3258
        }
3259
        if (1 !== Database::num_rows($res)) {
3260
            return false;
3261
        }
3262
        $row = Database::fetch_array($res);
3263
3264
        return $row['id'];
3265
    }
3266
3267
    /**
3268
     * Get the users files upload from his share_folder.
3269
     *
3270
     * @param string $user_id      User ID
3271
     * @param string $course       course directory
3272
     * @param string $resourceType resource type: images, all
3273
     *
3274
     * @return string
3275
     */
3276
    public static function get_user_upload_files_by_course(
3277
        $user_id,
3278
        $course,
3279
        $resourceType = 'all'
3280
    ) {
3281
        $return = '';
3282
        $user_id = (int) $user_id;
3283
3284
        if (!empty($user_id) && !empty($course)) {
3285
            $path = api_get_path(SYS_COURSE_PATH).$course.'/document/shared_folder/sf_user_'.$user_id.'/';
3286
            $web_path = api_get_path(WEB_COURSE_PATH).$course.'/document/shared_folder/sf_user_'.$user_id.'/';
3287
            $file_list = [];
3288
3289
            if (is_dir($path)) {
3290
                $handle = opendir($path);
3291
                while ($file = readdir($handle)) {
3292
                    if ('.' == $file || '..' == $file || '.htaccess' == $file || is_dir($path.$file)) {
3293
                        continue; // skip current/parent directory and .htaccess
3294
                    }
3295
                    $file_list[] = $file;
3296
                }
3297
                if (count($file_list) > 0) {
3298
                    $return = "<h4>$course</h4>";
3299
                    $return .= '<ul class="thumbnails">';
3300
                }
3301
                $extensionList = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'tif'];
3302
                foreach ($file_list as $file) {
3303
                    if ('all' == $resourceType) {
3304
                        $return .= '<li>
3305
                            <a href="'.$web_path.urlencode($file).'" target="_blank">'.htmlentities($file).'</a></li>';
3306
                    } elseif ('images' == $resourceType) {
3307
                        //get extension
3308
                        $ext = explode('.', $file);
3309
                        if (isset($ext[1]) && in_array($ext[1], $extensionList)) {
3310
                            $return .= '<li class="span2">
3311
                                            <a class="thumbnail" href="'.$web_path.urlencode($file).'" target="_blank">
3312
                                                <img src="'.$web_path.urlencode($file).'" >
3313
                                            </a>
3314
                                        </li>';
3315
                        }
3316
                    }
3317
                }
3318
                if (count($file_list) > 0) {
3319
                    $return .= '</ul>';
3320
                }
3321
            }
3322
        }
3323
3324
        return $return;
3325
    }
3326
3327
    /**
3328
     * Gets the API key (or keys) and return them into an array.
3329
     *
3330
     * @param int     Optional user id (defaults to the result of api_get_user_id())
3331
     * @param string $api_service
3332
     *
3333
     * @return mixed Non-indexed array containing the list of API keys for this user, or FALSE on error
3334
     */
3335
    public static function get_api_keys($user_id = null, $api_service = 'dokeos')
3336
    {
3337
        if ($user_id != strval(intval($user_id))) {
3338
            return false;
3339
        }
3340
        if (empty($user_id)) {
3341
            $user_id = api_get_user_id();
3342
        }
3343
        if (false === $user_id) {
3344
            return false;
3345
        }
3346
        $service_name = Database::escape_string($api_service);
3347
        if (false === is_string($service_name)) {
3348
            return false;
3349
        }
3350
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3351
        $sql = "SELECT * FROM $t_api WHERE user_id = $user_id AND api_service='$api_service';";
3352
        $res = Database::query($sql);
3353
        if (false === $res) {
3354
            return false;
3355
        } //error during query
3356
        $num = Database::num_rows($res);
3357
        if (0 == $num) {
3358
            return false;
3359
        }
3360
        $list = [];
3361
        while ($row = Database::fetch_array($res)) {
3362
            $list[$row['id']] = $row['api_key'];
3363
        }
3364
3365
        return $list;
3366
    }
3367
3368
    /**
3369
     * Adds a new API key to the users' account.
3370
     *
3371
     * @param   int     Optional user ID (defaults to the results of api_get_user_id())
3372
     * @param string $api_service
3373
     *
3374
     * @return bool True on success, false on failure
3375
     */
3376
    public static function add_api_key($user_id = null, $api_service = 'dokeos')
3377
    {
3378
        if ($user_id != strval(intval($user_id))) {
3379
            return false;
3380
        }
3381
        if (empty($user_id)) {
3382
            $user_id = api_get_user_id();
3383
        }
3384
        if (false === $user_id) {
3385
            return false;
3386
        }
3387
        $service_name = Database::escape_string($api_service);
3388
        if (false === is_string($service_name)) {
3389
            return false;
3390
        }
3391
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3392
        $md5 = md5((time() + ($user_id * 5)) - rand(10000, 10000)); //generate some kind of random key
3393
        $sql = "INSERT INTO $t_api (user_id, api_key,api_service) VALUES ($user_id,'$md5','$service_name')";
3394
        $res = Database::query($sql);
3395
        if (false === $res) {
3396
            return false;
3397
        } //error during query
3398
        $num = Database::insert_id();
3399
3400
        return 0 == $num ? false : $num;
3401
    }
3402
3403
    /**
3404
     * Deletes an API key from the user's account.
3405
     *
3406
     * @param   int     API key's internal ID
3407
     *
3408
     * @return bool True on success, false on failure
3409
     */
3410
    public static function delete_api_key($key_id)
3411
    {
3412
        if ($key_id != strval(intval($key_id))) {
3413
            return false;
3414
        }
3415
        if (false === $key_id) {
3416
            return false;
3417
        }
3418
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3419
        $sql = "SELECT * FROM $t_api WHERE id = ".$key_id;
3420
        $res = Database::query($sql);
3421
        if (false === $res) {
3422
            return false;
3423
        } //error during query
3424
        $num = Database::num_rows($res);
3425
        if (1 !== $num) {
3426
            return false;
3427
        }
3428
        $sql = "DELETE FROM $t_api WHERE id = ".$key_id;
3429
        $res = Database::query($sql);
3430
        if (false === $res) {
3431
            return false;
3432
        } //error during query
3433
3434
        return true;
3435
    }
3436
3437
    /**
3438
     * Regenerate an API key from the user's account.
3439
     *
3440
     * @param   int     user ID (defaults to the results of api_get_user_id())
3441
     * @param   string  API key's internal ID
3442
     *
3443
     * @return int num
3444
     */
3445
    public static function update_api_key($user_id, $api_service)
3446
    {
3447
        if ($user_id != strval(intval($user_id))) {
3448
            return false;
3449
        }
3450
        if (false === $user_id) {
3451
            return false;
3452
        }
3453
        $service_name = Database::escape_string($api_service);
3454
        if (false === is_string($service_name)) {
3455
            return false;
3456
        }
3457
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3458
        $sql = "SELECT id FROM $t_api
3459
                WHERE user_id=".$user_id." AND api_service='".$api_service."'";
3460
        $res = Database::query($sql);
3461
        $num = Database::num_rows($res);
3462
        if (1 == $num) {
3463
            $id_key = Database::fetch_array($res, 'ASSOC');
3464
            self::delete_api_key($id_key['id']);
3465
            $num = self::add_api_key($user_id, $api_service);
3466
        } elseif (0 == $num) {
3467
            $num = self::add_api_key($user_id, $api_service);
3468
        }
3469
3470
        return $num;
3471
    }
3472
3473
    /**
3474
     * @param   int     user ID (defaults to the results of api_get_user_id())
3475
     * @param   string    API key's internal ID
3476
     *
3477
     * @return int row ID, or return false if not found
3478
     */
3479
    public static function get_api_key_id($user_id, $api_service)
3480
    {
3481
        if ($user_id != strval(intval($user_id))) {
3482
            return false;
3483
        }
3484
        if (false === $user_id) {
3485
            return false;
3486
        }
3487
        if (empty($api_service)) {
3488
            return false;
3489
        }
3490
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3491
        $api_service = Database::escape_string($api_service);
3492
        $sql = "SELECT id FROM $t_api
3493
                WHERE user_id=".$user_id." AND api_service='".$api_service."'";
3494
        $res = Database::query($sql);
3495
        if (Database::num_rows($res) < 1) {
3496
            return false;
3497
        }
3498
        $row = Database::fetch_array($res, 'ASSOC');
3499
3500
        return $row['id'];
3501
    }
3502
3503
    /**
3504
     * Checks if a user_id is platform admin.
3505
     *
3506
     * @param   int user ID
3507
     *
3508
     * @return bool True if is admin, false otherwise
3509
     *
3510
     * @see main_api.lib.php::api_is_platform_admin() for a context-based check
3511
     */
3512
    public static function is_admin($user_id)
3513
    {
3514
        $user_id = (int) $user_id;
3515
        if (empty($user_id)) {
3516
            return false;
3517
        }
3518
        $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
3519
        $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
3520
        $res = Database::query($sql);
3521
3522
        return 1 === Database::num_rows($res);
3523
    }
3524
3525
    /**
3526
     * Get the total count of users.
3527
     *
3528
     * @param int $status        Status of users to be counted
3529
     * @param int $access_url_id Access URL ID (optional)
3530
     * @param int $active
3531
     *
3532
     * @return mixed Number of users or false on error
3533
     */
3534
    public static function get_number_of_users($status = 0, $access_url_id = 1, $active = null)
3535
    {
3536
        $t_u = Database::get_main_table(TABLE_MAIN_USER);
3537
        $t_a = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3538
3539
        if (api_is_multiple_url_enabled()) {
3540
            $sql = "SELECT count(u.id)
3541
                    FROM $t_u u
3542
                    INNER JOIN $t_a url_user
3543
                    ON (u.id = url_user.user_id)
3544
                    WHERE url_user.access_url_id = $access_url_id
3545
            ";
3546
        } else {
3547
            $sql = "SELECT count(u.id)
3548
                    FROM $t_u u
3549
                    WHERE 1 = 1 ";
3550
        }
3551
3552
        if (is_int($status) && $status > 0) {
3553
            $status = (int) $status;
3554
            $sql .= " AND u.status = $status ";
3555
        }
3556
3557
        if (null !== $active) {
3558
            $active = (int) $active;
3559
            $sql .= " AND u.active = $active ";
3560
        }
3561
3562
        $res = Database::query($sql);
3563
        if (1 === Database::num_rows($res)) {
3564
            return (int) Database::result($res, 0, 0);
3565
        }
3566
3567
        return false;
3568
    }
3569
3570
    /**
3571
     * Gets the tags of a specific field_id
3572
     * USER TAGS.
3573
     *
3574
     * Instructions to create a new user tag by Julio Montoya <[email protected]>
3575
     *
3576
     * 1. Create a new extra field in main/admin/user_fields.php with the "TAG" field type make it available and visible.
3577
     *    Called it "books" for example.
3578
     * 2. Go to profile main/auth/profile.php There you will see a special input (facebook style) that will show suggestions of tags.
3579
     * 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
3580
     * 4. Tags are independent this means that tags can't be shared between tags + book + hobbies.
3581
     * 5. Test and enjoy.
3582
     *
3583
     * @param string $tag
3584
     * @param int    $field_id      field_id
3585
     * @param string $return_format how we are going to result value in array or in a string (json)
3586
     * @param $limit
3587
     *
3588
     * @return mixed
3589
     */
3590
    public static function get_tags($tag, $field_id, $return_format = 'json', $limit = 10)
3591
    {
3592
        // database table definition
3593
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3594
        $field_id = (int) $field_id;
3595
        $limit = (int) $limit;
3596
        $tag = trim(Database::escape_string($tag));
3597
3598
        // all the information of the field
3599
        $sql = "SELECT DISTINCT id, tag from $table_user_tag
3600
                WHERE field_id = $field_id AND tag LIKE '$tag%' ORDER BY tag LIMIT $limit";
3601
        $result = Database::query($sql);
3602
        $return = [];
3603
        if (Database::num_rows($result) > 0) {
3604
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3605
                $return[] = ['id' => $row['tag'], 'text' => $row['tag']];
3606
            }
3607
        }
3608
        if ('json' === $return_format) {
3609
            $return = json_encode($return);
3610
        }
3611
3612
        return $return;
3613
    }
3614
3615
    /**
3616
     * @param int $field_id
3617
     * @param int $limit
3618
     *
3619
     * @return array
3620
     */
3621
    public static function get_top_tags($field_id, $limit = 100)
3622
    {
3623
        // database table definition
3624
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3625
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3626
        $field_id = (int) $field_id;
3627
        $limit = (int) $limit;
3628
        // all the information of the field
3629
        $sql = "SELECT count(*) count, tag FROM $table_user_tag_values  uv
3630
                INNER JOIN $table_user_tag ut
3631
                ON (ut.id = uv.tag_id)
3632
                WHERE field_id = $field_id
3633
                GROUP BY tag_id
3634
                ORDER BY count DESC
3635
                LIMIT $limit";
3636
        $result = Database::query($sql);
3637
        $return = [];
3638
        if (Database::num_rows($result) > 0) {
3639
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3640
                $return[] = $row;
3641
            }
3642
        }
3643
3644
        return $return;
3645
    }
3646
3647
    /**
3648
     * Get user's tags.
3649
     *
3650
     * @param int $user_id
3651
     * @param int $field_id
3652
     *
3653
     * @return array
3654
     */
3655
    public static function get_user_tags($user_id, $field_id)
3656
    {
3657
        // database table definition
3658
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3659
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3660
        $field_id = (int) $field_id;
3661
        $user_id = (int) $user_id;
3662
3663
        // all the information of the field
3664
        $sql = "SELECT ut.id, tag, count
3665
                FROM $table_user_tag ut
3666
                INNER JOIN $table_user_tag_values uv
3667
                ON (uv.tag_id=ut.ID)
3668
                WHERE field_id = $field_id AND user_id = $user_id
3669
                ORDER BY tag";
3670
        $result = Database::query($sql);
3671
        $return = [];
3672
        if (Database::num_rows($result) > 0) {
3673
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3674
                $return[$row['id']] = ['tag' => $row['tag'], 'count' => $row['count']];
3675
            }
3676
        }
3677
3678
        return $return;
3679
    }
3680
3681
    /**
3682
     * Get user's tags.
3683
     *
3684
     * @param int  $user_id
3685
     * @param int  $field_id
3686
     * @param bool $show_links show links or not
3687
     *
3688
     * @return string
3689
     */
3690
    public static function get_user_tags_to_string($user_id, $field_id, $show_links = true)
3691
    {
3692
        // database table definition
3693
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3694
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3695
        $field_id = (int) $field_id;
3696
        $user_id = (int) $user_id;
3697
3698
        // all the information of the field
3699
        $sql = "SELECT ut.id, tag,count FROM $table_user_tag ut
3700
                INNER JOIN $table_user_tag_values uv
3701
                ON (uv.tag_id = ut.id)
3702
                WHERE field_id = $field_id AND user_id = $user_id
3703
                ORDER BY tag";
3704
3705
        $result = Database::query($sql);
3706
        $return = [];
3707
        if (Database::num_rows($result) > 0) {
3708
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3709
                $return[$row['id']] = ['tag' => $row['tag'], 'count' => $row['count']];
3710
            }
3711
        }
3712
        $user_tags = $return;
3713
        $tag_tmp = [];
3714
        foreach ($user_tags as $tag) {
3715
            if ($show_links) {
3716
                $tag_tmp[] = '<a href="'.api_get_path(WEB_PATH).'main/search/index.php?q='.$tag['tag'].'">'.
3717
                    $tag['tag'].
3718
                '</a>';
3719
            } else {
3720
                $tag_tmp[] = $tag['tag'];
3721
            }
3722
        }
3723
3724
        if (is_array($user_tags) && count($user_tags) > 0) {
3725
            return implode(', ', $tag_tmp);
3726
        } else {
3727
            return '';
3728
        }
3729
    }
3730
3731
    /**
3732
     * Get the tag id.
3733
     *
3734
     * @param int $tag
3735
     * @param int $field_id
3736
     *
3737
     * @return int returns 0 if fails otherwise the tag id
3738
     */
3739
    public static function get_tag_id($tag, $field_id)
3740
    {
3741
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3742
        $tag = Database::escape_string($tag);
3743
        $field_id = (int) $field_id;
3744
        //with COLLATE latin1_bin to select query in a case sensitive mode
3745
        $sql = "SELECT id FROM $table_user_tag
3746
                WHERE tag LIKE '$tag' AND field_id = $field_id";
3747
        $result = Database::query($sql);
3748
        if (Database::num_rows($result) > 0) {
3749
            $row = Database::fetch_array($result, 'ASSOC');
3750
3751
            return $row['id'];
3752
        } else {
3753
            return 0;
3754
        }
3755
    }
3756
3757
    /**
3758
     * Get the tag id.
3759
     *
3760
     * @param int $tag_id
3761
     * @param int $field_id
3762
     *
3763
     * @return int 0 if fails otherwise the tag id
3764
     */
3765
    public static function get_tag_id_from_id($tag_id, $field_id)
3766
    {
3767
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3768
        $tag_id = (int) $tag_id;
3769
        $field_id = (int) $field_id;
3770
        $sql = "SELECT id FROM $table_user_tag
3771
                WHERE id = '$tag_id' AND field_id = $field_id";
3772
        $result = Database::query($sql);
3773
        if (Database::num_rows($result) > 0) {
3774
            $row = Database::fetch_array($result, 'ASSOC');
3775
3776
            return $row['id'];
3777
        } else {
3778
            return false;
3779
        }
3780
    }
3781
3782
    /**
3783
     * Adds a user-tag value.
3784
     *
3785
     * @param mixed $tag
3786
     * @param int   $user_id
3787
     * @param int   $field_id field id of the tag
3788
     *
3789
     * @return bool True if the tag was inserted or updated. False otherwise.
3790
     *              The return value doesn't take into account *values* added to the tag.
3791
     *              Only the creation/update of the tag field itself.
3792
     */
3793
    public static function add_tag($tag, $user_id, $field_id)
3794
    {
3795
        // database table definition
3796
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3797
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3798
        $tag = trim(Database::escape_string($tag));
3799
        $user_id = (int) $user_id;
3800
        $field_id = (int) $field_id;
3801
3802
        $tag_id = self::get_tag_id($tag, $field_id);
3803
3804
        /* IMPORTANT
3805
         *  @todo we don't create tags with numbers
3806
         *
3807
         */
3808
        if (is_numeric($tag)) {
3809
            //the form is sending an id this means that the user select it from the list so it MUST exists
3810
            /* $new_tag_id = self::get_tag_id_from_id($tag,$field_id);
3811
              if ($new_tag_id !== false) {
3812
              $sql = "UPDATE $table_user_tag SET count = count + 1 WHERE id  = $new_tag_id";
3813
              $result = Database::query($sql);
3814
              $last_insert_id = $new_tag_id;
3815
              } else {
3816
              $sql = "INSERT INTO $table_user_tag (tag, field_id,count) VALUES ('$tag','$field_id', count + 1)";
3817
              $result = Database::query($sql);
3818
              $last_insert_id = Database::insert_id();
3819
              } */
3820
        }
3821
3822
        //this is a new tag
3823
        if (0 == $tag_id) {
3824
            //the tag doesn't exist
3825
            $sql = "INSERT INTO $table_user_tag (tag, field_id,count) VALUES ('$tag','$field_id', count + 1)";
3826
            Database::query($sql);
3827
            $last_insert_id = Database::insert_id();
3828
        } else {
3829
            //the tag exists we update it
3830
            $sql = "UPDATE $table_user_tag SET count = count + 1 WHERE id  = $tag_id";
3831
            Database::query($sql);
3832
            $last_insert_id = $tag_id;
3833
        }
3834
3835
        if (!empty($last_insert_id) && (0 != $last_insert_id)) {
3836
            //we insert the relationship user-tag
3837
            $sql = "SELECT tag_id FROM $table_user_tag_values
3838
                    WHERE user_id = $user_id AND tag_id = $last_insert_id ";
3839
            $result = Database::query($sql);
3840
            //if the relationship does not exist we create it
3841
            if (0 == Database::num_rows($result)) {
3842
                $sql = "INSERT INTO $table_user_tag_values SET user_id = $user_id, tag_id = $last_insert_id";
3843
                Database::query($sql);
3844
            }
3845
3846
            return true;
3847
        }
3848
3849
        return false;
3850
    }
3851
3852
    /**
3853
     * Deletes an user tag.
3854
     *
3855
     * @param int $user_id
3856
     * @param int $field_id
3857
     */
3858
    public static function delete_user_tags($user_id, $field_id)
3859
    {
3860
        // database table definition
3861
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3862
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3863
        $user_id = (int) $user_id;
3864
3865
        $tags = self::get_user_tags($user_id, $field_id);
3866
        if (is_array($tags) && count($tags) > 0) {
3867
            foreach ($tags as $key => $tag) {
3868
                if ($tag['count'] > '0') {
3869
                    $sql = "UPDATE $table_user_tag SET count = count - 1  WHERE id = $key ";
3870
                    Database::query($sql);
3871
                }
3872
                $sql = "DELETE FROM $table_user_tag_values
3873
                        WHERE user_id = $user_id AND tag_id = $key";
3874
                Database::query($sql);
3875
            }
3876
        }
3877
    }
3878
3879
    /**
3880
     * Process the tag list comes from the UserManager::update_extra_field_value() function.
3881
     *
3882
     * @param array $tags     the tag list that will be added
3883
     * @param int   $user_id
3884
     * @param int   $field_id
3885
     *
3886
     * @return bool
3887
     */
3888
    public static function process_tags($tags, $user_id, $field_id)
3889
    {
3890
        // We loop the tags and add it to the DB
3891
        if (is_array($tags)) {
3892
            foreach ($tags as $tag) {
3893
                self::add_tag($tag, $user_id, $field_id);
3894
            }
3895
        } else {
3896
            self::add_tag($tags, $user_id, $field_id);
3897
        }
3898
3899
        return true;
3900
    }
3901
3902
    /**
3903
     * Returns a list of all administrators.
3904
     *
3905
     * @return array
3906
     */
3907
    public static function get_all_administrators()
3908
    {
3909
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
3910
        $table_admin = Database::get_main_table(TABLE_MAIN_ADMIN);
3911
        $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3912
        $access_url_id = api_get_current_access_url_id();
3913
        if (api_get_multiple_access_url()) {
3914
            $sql = "SELECT admin.user_id, username, firstname, lastname, email, active
3915
                    FROM $tbl_url_rel_user as url
3916
                    INNER JOIN $table_admin as admin
3917
                    ON (admin.user_id=url.user_id)
3918
                    INNER JOIN $table_user u
3919
                    ON (u.id=admin.user_id)
3920
                    WHERE access_url_id ='".$access_url_id."'";
3921
        } else {
3922
            $sql = "SELECT admin.user_id, username, firstname, lastname, email, active
3923
                    FROM $table_admin as admin
3924
                    INNER JOIN $table_user u
3925
                    ON (u.id=admin.user_id)";
3926
        }
3927
        $result = Database::query($sql);
3928
        $return = [];
3929
        if (Database::num_rows($result) > 0) {
3930
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3931
                $return[$row['user_id']] = $row;
3932
            }
3933
        }
3934
3935
        return $return;
3936
    }
3937
3938
    /**
3939
     * Search an user (tags, first name, last name and email ).
3940
     *
3941
     * @param string $tag
3942
     * @param int    $field_id        field id of the tag
3943
     * @param int    $from            where to start in the query
3944
     * @param int    $number_of_items
3945
     * @param bool   $getCount        get count or not
3946
     *
3947
     * @return array
3948
     */
3949
    public static function get_all_user_tags(
3950
        $tag,
3951
        $field_id = 0,
3952
        $from = 0,
3953
        $number_of_items = 10,
3954
        $getCount = false
3955
    ) {
3956
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
3957
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3958
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3959
        $access_url_rel_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3960
3961
        $field_id = intval($field_id);
3962
        $from = intval($from);
3963
        $number_of_items = intval($number_of_items);
3964
3965
        $where_field = "";
3966
        $where_extra_fields = self::get_search_form_where_extra_fields();
3967
        if (0 != $field_id) {
3968
            $where_field = " field_id = $field_id AND ";
3969
        }
3970
3971
        // all the information of the field
3972
        if ($getCount) {
3973
            $select = "SELECT count(DISTINCT u.id) count";
3974
        } else {
3975
            $select = "SELECT DISTINCT u.id, u.username, firstname, lastname, email, tag, picture_uri";
3976
        }
3977
3978
        $sql = " $select
3979
                FROM $user_table u
3980
                INNER JOIN $access_url_rel_user_table url_rel_user
3981
                ON (u.id = url_rel_user.user_id)
3982
                LEFT JOIN $table_user_tag_values uv
3983
                ON (u.id AND uv.user_id AND uv.user_id = url_rel_user.user_id)
3984
                LEFT JOIN $table_user_tag ut ON (uv.tag_id = ut.id)
3985
                WHERE
3986
                    ($where_field tag LIKE '".Database::escape_string($tag."%")."') OR
3987
                    (
3988
                        u.firstname LIKE '".Database::escape_string("%".$tag."%")."' OR
3989
                        u.lastname LIKE '".Database::escape_string("%".$tag."%")."' OR
3990
                        u.username LIKE '".Database::escape_string("%".$tag."%")."' OR
3991
                        concat(u.firstname, ' ', u.lastname) LIKE '".Database::escape_string("%".$tag."%")."' OR
3992
                        concat(u.lastname, ' ', u.firstname) LIKE '".Database::escape_string("%".$tag."%")."'
3993
                     )
3994
                     ".(!empty($where_extra_fields) ? $where_extra_fields : '')."
3995
                     AND url_rel_user.access_url_id=".api_get_current_access_url_id();
3996
3997
        $keyword_active = true;
3998
        // only active users
3999
        if ($keyword_active) {
4000
            $sql .= " AND u.active='1'";
4001
        }
4002
        // avoid anonymous
4003
        $sql .= " AND u.status <> 6 ";
4004
        $sql .= " ORDER BY username";
4005
        $sql .= " LIMIT $from , $number_of_items";
4006
4007
        $result = Database::query($sql);
4008
        $return = [];
4009
4010
        if (Database::num_rows($result) > 0) {
4011
            if ($getCount) {
4012
                $row = Database::fetch_array($result, 'ASSOC');
4013
4014
                return $row['count'];
4015
            }
4016
            while ($row = Database::fetch_array($result, 'ASSOC')) {
4017
                $return[$row['id']] = $row;
4018
            }
4019
        }
4020
4021
        return $return;
4022
    }
4023
4024
    /**
4025
     * Get extra filterable user fields (only type select).
4026
     *
4027
     * @return array Array of extra fields as [int => ['name' => ..., 'variable' => ..., 'data' => ...]] (
4028
     *               or empty array if no extra field)
4029
     */
4030
    public static function getExtraFilterableFields()
4031
    {
4032
        $extraFieldList = self::get_extra_fields();
4033
        $fields = [];
4034
        if (is_array($extraFieldList)) {
4035
            foreach ($extraFieldList as $extraField) {
4036
                // If is enabled to filter and is a "<select>" field type
4037
                if (1 == $extraField[8] && 4 == $extraField[2]) {
4038
                    $fields[] = [
4039
                        'name' => $extraField[3],
4040
                        'variable' => $extraField[1],
4041
                        'data' => $extraField[9],
4042
                    ];
4043
                }
4044
            }
4045
        }
4046
4047
        return $fields;
4048
    }
4049
4050
    /**
4051
     * Get extra where clauses for finding users based on extra filterable user fields (type select).
4052
     *
4053
     * @return string With AND clauses based on user's ID which have the values to search in extra user fields
4054
     *                (or empty if no extra field exists)
4055
     */
4056
    public static function get_search_form_where_extra_fields()
4057
    {
4058
        $useExtraFields = false;
4059
        $extraFields = self::getExtraFilterableFields();
4060
        $extraFieldResult = [];
4061
        if (is_array($extraFields) && count($extraFields) > 0) {
4062
            foreach ($extraFields as $extraField) {
4063
                $varName = 'field_'.$extraField['variable'];
4064
                if (self::is_extra_field_available($extraField['variable'])) {
4065
                    if (isset($_GET[$varName]) && '0' != $_GET[$varName]) {
4066
                        $useExtraFields = true;
4067
                        $extraFieldResult[] = self::get_extra_user_data_by_value(
4068
                            $extraField['variable'],
4069
                            $_GET[$varName]
4070
                        );
4071
                    }
4072
                }
4073
            }
4074
        }
4075
4076
        if ($useExtraFields) {
4077
            $finalResult = [];
4078
            if (count($extraFieldResult) > 1) {
4079
                for ($i = 0; $i < count($extraFieldResult) - 1; $i++) {
4080
                    if (is_array($extraFieldResult[$i]) && is_array($extraFieldResult[$i + 1])) {
4081
                        $finalResult = array_intersect($extraFieldResult[$i], $extraFieldResult[$i + 1]);
4082
                    }
4083
                }
4084
            } else {
4085
                $finalResult = $extraFieldResult[0];
4086
            }
4087
4088
            if (is_array($finalResult) && count($finalResult) > 0) {
4089
                $whereFilter = " AND u.id IN  ('".implode("','", $finalResult)."') ";
4090
            } else {
4091
                //no results
4092
                $whereFilter = " AND u.id  = -1 ";
4093
            }
4094
4095
            return $whereFilter;
4096
        }
4097
4098
        return '';
4099
    }
4100
4101
    /**
4102
     * Show the search form.
4103
     *
4104
     * @param string $query the value of the search box
4105
     *
4106
     * @throws Exception
4107
     *
4108
     * @return string HTML form
4109
     */
4110
    public static function get_search_form($query, $defaultParams = [])
4111
    {
4112
        $searchType = isset($_GET['search_type']) ? $_GET['search_type'] : null;
4113
        $form = new FormValidator(
4114
            'search_user',
4115
            'get',
4116
            api_get_path(WEB_PATH).'main/social/search.php',
4117
            '',
4118
            [],
4119
            FormValidator::LAYOUT_HORIZONTAL
4120
        );
4121
4122
        $query = Security::remove_XSS($query);
4123
4124
        if (!empty($query)) {
4125
            $form->addHeader(get_lang('Results and feedback').' "'.$query.'"');
4126
        }
4127
4128
        $form->addText(
4129
            'q',
4130
            get_lang('Users, Groups'),
4131
            false,
4132
            [
4133
                'id' => 'q',
4134
            ]
4135
        );
4136
        $options = [
4137
            0 => get_lang('Select'),
4138
            1 => get_lang('User'),
4139
            2 => get_lang('Group'),
4140
        ];
4141
        $form->addSelect(
4142
            'search_type',
4143
            get_lang('Type'),
4144
            $options,
4145
            ['onchange' => 'javascript: extra_field_toogle();', 'id' => 'search_type']
4146
        );
4147
4148
        // Extra fields
4149
        $extraFields = self::getExtraFilterableFields();
4150
        $defaults = [];
4151
        if (is_array($extraFields) && count($extraFields) > 0) {
4152
            foreach ($extraFields as $extraField) {
4153
                $varName = 'field_'.$extraField['variable'];
4154
                $options = [
4155
                    0 => get_lang('Select'),
4156
                ];
4157
                foreach ($extraField['data'] as $option) {
4158
                    if (isset($_GET[$varName])) {
4159
                        if ($_GET[$varName] == $option[1]) {
4160
                            $defaults[$option[1]] = true;
4161
                        }
4162
                    }
4163
4164
                    $options[$option[1]] = $option[1];
4165
                }
4166
                $form->addSelect($varName, $extraField['name'], $options);
4167
            }
4168
        }
4169
4170
        $defaults['search_type'] = (int) $searchType;
4171
        $defaults['q'] = $query;
4172
4173
        if (!empty($defaultParams)) {
4174
            $defaults = array_merge($defaults, $defaultParams);
4175
        }
4176
        $form->setDefaults($defaults);
4177
        $form->addButtonSearch(get_lang('Search'));
4178
4179
        $js = '<script>
4180
        extra_field_toogle();
4181
        function extra_field_toogle() {
4182
            if (jQuery("select[name=search_type]").val() != "1") {
4183
                jQuery(".extra_field").hide();
4184
            } else {
4185
                jQuery(".extra_field").show();
4186
            }
4187
        }
4188
        </script>';
4189
4190
        return $js.$form->returnForm();
4191
    }
4192
4193
    /**
4194
     * Shows the user menu.
4195
     */
4196
    public static function show_menu()
4197
    {
4198
        echo '<div class="actions">';
4199
        echo '<a href="/main/auth/profile.php">'.
4200
            Display::return_icon('profile.png').' '.get_lang('Profile').'</a>';
4201
        echo '<a href="/main/messages/inbox.php">'.
4202
            Display::return_icon('inbox.png').' '.get_lang('Inbox').'</a>';
4203
        echo '<a href="/main/messages/outbox.php">'.
4204
            Display::return_icon('outbox.png').' '.get_lang('Outbox').'</a>';
4205
        echo '<span style="float:right; padding-top:7px;">'.
4206
        '<a href="/main/auth/profile.php?show=1">'.
4207
            Display::return_icon('edit.gif').' '.get_lang('Configuration').'</a>';
4208
        echo '</span>';
4209
        echo '</div>';
4210
    }
4211
4212
    /**
4213
     * Allow to register contact to social network.
4214
     *
4215
     * @param int $friend_id     user friend id
4216
     * @param int $my_user_id    user id
4217
     * @param int $relation_type relation between users see constants definition
4218
     *
4219
     * @return bool
4220
     */
4221
    public static function relate_users($friend_id, $my_user_id, $relation_type)
4222
    {
4223
        $tbl_my_friend = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4224
4225
        $friend_id = (int) $friend_id;
4226
        $my_user_id = (int) $my_user_id;
4227
        $relation_type = (int) $relation_type;
4228
4229
        $sql = 'SELECT COUNT(*) as count FROM '.$tbl_my_friend.'
4230
                WHERE
4231
                    friend_user_id='.$friend_id.' AND
4232
                    user_id='.$my_user_id.' AND
4233
                    relation_type NOT IN('.USER_RELATION_TYPE_RRHH.', '.USER_RELATION_TYPE_BOSS.') ';
4234
        $result = Database::query($sql);
4235
        $row = Database::fetch_array($result, 'ASSOC');
4236
        $current_date = api_get_utc_datetime();
4237
4238
        if (0 == $row['count']) {
4239
            $sql = 'INSERT INTO '.$tbl_my_friend.'(friend_user_id,user_id,relation_type,last_edit)
4240
                    VALUES ('.$friend_id.','.$my_user_id.','.$relation_type.',"'.$current_date.'")';
4241
            Database::query($sql);
4242
4243
            return true;
4244
        }
4245
4246
        $sql = 'SELECT COUNT(*) as count, relation_type  FROM '.$tbl_my_friend.'
4247
                WHERE
4248
                    friend_user_id='.$friend_id.' AND
4249
                    user_id='.$my_user_id.' AND
4250
                    relation_type NOT IN('.USER_RELATION_TYPE_RRHH.', '.USER_RELATION_TYPE_BOSS.') ';
4251
        $result = Database::query($sql);
4252
        $row = Database::fetch_array($result, 'ASSOC');
4253
4254
        if (1 == $row['count']) {
4255
            //only for the case of a RRHH or a Student BOSS
4256
            if ($row['relation_type'] != $relation_type &&
4257
                (USER_RELATION_TYPE_RRHH == $relation_type || USER_RELATION_TYPE_BOSS == $relation_type)
4258
            ) {
4259
                $sql = 'INSERT INTO '.$tbl_my_friend.'(friend_user_id,user_id,relation_type,last_edit)
4260
                        VALUES ('.$friend_id.','.$my_user_id.','.$relation_type.',"'.$current_date.'")';
4261
            } else {
4262
                $sql = 'UPDATE '.$tbl_my_friend.' SET relation_type='.$relation_type.'
4263
                        WHERE friend_user_id='.$friend_id.' AND user_id='.$my_user_id;
4264
            }
4265
            Database::query($sql);
4266
4267
            return true;
4268
        }
4269
4270
        return false;
4271
    }
4272
4273
    /**
4274
     * Deletes a contact.
4275
     *
4276
     * @param bool   $friend_id
4277
     * @param bool   $real_removed          true will delete ALL friends relationship
4278
     * @param string $with_status_condition
4279
     *
4280
     * @author isaac flores paz <[email protected]>
4281
     * @author Julio Montoya <[email protected]> Cleaning code
4282
     */
4283
    public static function remove_user_rel_user(
4284
        $friend_id,
4285
        $real_removed = false,
4286
        $with_status_condition = ''
4287
    ) {
4288
        $tbl_my_friend = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4289
        $tbl_my_message = Database::get_main_table(TABLE_MESSAGE);
4290
        $friend_id = (int) $friend_id;
4291
        $user_id = api_get_user_id();
4292
4293
        if ($real_removed) {
4294
            $extra_condition = '';
4295
            if ('' != $with_status_condition) {
4296
                $extra_condition = ' AND relation_type = '.intval($with_status_condition);
4297
            }
4298
            $sql = 'DELETE FROM '.$tbl_my_friend.'
4299
                    WHERE
4300
                        relation_type <> '.USER_RELATION_TYPE_RRHH.' AND
4301
                        friend_user_id='.$friend_id.' '.$extra_condition;
4302
            Database::query($sql);
4303
            $sql = 'DELETE FROM '.$tbl_my_friend.'
4304
                   WHERE
4305
                    relation_type <> '.USER_RELATION_TYPE_RRHH.' AND
4306
                    user_id='.$friend_id.' '.$extra_condition;
4307
            Database::query($sql);
4308
        } else {
4309
            $sql = 'SELECT COUNT(*) as count FROM '.$tbl_my_friend.'
4310
                    WHERE
4311
                        user_id='.$user_id.' AND
4312
                        relation_type NOT IN('.USER_RELATION_TYPE_DELETED.', '.USER_RELATION_TYPE_RRHH.') AND
4313
                        friend_user_id='.$friend_id;
4314
            $result = Database::query($sql);
4315
            $row = Database::fetch_array($result, 'ASSOC');
4316
            if (1 == $row['count']) {
4317
                //Delete user rel user
4318
                $sql_i = 'UPDATE '.$tbl_my_friend.' SET relation_type='.USER_RELATION_TYPE_DELETED.'
4319
                          WHERE user_id='.$user_id.' AND friend_user_id='.$friend_id;
4320
4321
                $sql_j = 'UPDATE '.$tbl_my_message.' SET msg_status='.MESSAGE_STATUS_INVITATION_DENIED.'
4322
                          WHERE
4323
                                user_receiver_id='.$user_id.' AND
4324
                                user_sender_id='.$friend_id.' AND update_date="0000-00-00 00:00:00" ';
4325
                // Delete user
4326
                $sql_ij = 'UPDATE '.$tbl_my_friend.'  SET relation_type='.USER_RELATION_TYPE_DELETED.'
4327
                           WHERE user_id='.$friend_id.' AND friend_user_id='.$user_id;
4328
                $sql_ji = 'UPDATE '.$tbl_my_message.' SET msg_status='.MESSAGE_STATUS_INVITATION_DENIED.'
4329
                           WHERE
4330
                                user_receiver_id='.$friend_id.' AND
4331
                                user_sender_id='.$user_id.' AND
4332
                                update_date="0000-00-00 00:00:00" ';
4333
                Database::query($sql_i);
4334
                Database::query($sql_j);
4335
                Database::query($sql_ij);
4336
                Database::query($sql_ji);
4337
            }
4338
        }
4339
4340
        // Delete accepted invitations
4341
        $sql = "DELETE FROM $tbl_my_message
4342
                WHERE
4343
                    msg_status = ".MESSAGE_STATUS_INVITATION_ACCEPTED." AND
4344
                    (
4345
                        user_receiver_id = $user_id AND
4346
                        user_sender_id = $friend_id
4347
                    ) OR
4348
                    (
4349
                        user_sender_id = $user_id AND
4350
                        user_receiver_id = $friend_id
4351
                    )
4352
        ";
4353
        Database::query($sql);
4354
    }
4355
4356
    /**
4357
     * @param int $userId
4358
     *
4359
     * @return array
4360
     */
4361
    public static function getDrhListFromUser($userId)
4362
    {
4363
        $tblUser = Database::get_main_table(TABLE_MAIN_USER);
4364
        $tblUserRelUser = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4365
        $tblUserRelAccessUrl = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
4366
        $userId = (int) $userId;
4367
4368
        $orderBy = null;
4369
        if (api_is_western_name_order()) {
4370
            $orderBy .= ' ORDER BY firstname, lastname ';
4371
        } else {
4372
            $orderBy .= ' ORDER BY lastname, firstname ';
4373
        }
4374
4375
        $sql = "SELECT u.id, username, u.firstname, u.lastname
4376
                FROM $tblUser u
4377
                INNER JOIN $tblUserRelUser uru ON (uru.friend_user_id = u.id)
4378
                INNER JOIN $tblUserRelAccessUrl a ON (a.user_id = u.id)
4379
                WHERE
4380
                    access_url_id = ".api_get_current_access_url_id()." AND
4381
                    uru.user_id = '$userId' AND
4382
                    relation_type = '".USER_RELATION_TYPE_RRHH."'
4383
                $orderBy
4384
                ";
4385
        $result = Database::query($sql);
4386
4387
        return Database::store_result($result);
4388
    }
4389
4390
    /**
4391
     * get users followed by human resource manager.
4392
     *
4393
     * @param int    $userId
4394
     * @param int    $userStatus         (STUDENT, COURSEMANAGER, etc)
4395
     * @param bool   $getOnlyUserId
4396
     * @param bool   $getSql
4397
     * @param bool   $getCount
4398
     * @param int    $from
4399
     * @param int    $numberItems
4400
     * @param int    $column
4401
     * @param string $direction
4402
     * @param int    $active
4403
     * @param string $lastConnectionDate
4404
     *
4405
     * @return array users
4406
     */
4407
    public static function get_users_followed_by_drh(
4408
        $userId,
4409
        $userStatus = 0,
4410
        $getOnlyUserId = false,
4411
        $getSql = false,
4412
        $getCount = false,
4413
        $from = null,
4414
        $numberItems = null,
4415
        $column = null,
4416
        $direction = null,
4417
        $active = null,
4418
        $lastConnectionDate = null
4419
    ) {
4420
        return self::getUsersFollowedByUser(
4421
            $userId,
4422
            $userStatus,
4423
            $getOnlyUserId,
4424
            $getSql,
4425
            $getCount,
4426
            $from,
4427
            $numberItems,
4428
            $column,
4429
            $direction,
4430
            $active,
4431
            $lastConnectionDate,
4432
            DRH
4433
        );
4434
    }
4435
4436
    /**
4437
     * Get users followed by human resource manager.
4438
     *
4439
     * @param int    $userId
4440
     * @param int    $userStatus         Filter users by status (STUDENT, COURSEMANAGER, etc)
4441
     * @param bool   $getOnlyUserId
4442
     * @param bool   $getSql
4443
     * @param bool   $getCount
4444
     * @param int    $from
4445
     * @param int    $numberItems
4446
     * @param int    $column
4447
     * @param string $direction
4448
     * @param int    $active
4449
     * @param string $lastConnectionDate
4450
     * @param int    $status             the function is called by who? COURSEMANAGER, DRH?
4451
     * @param string $keyword
4452
     *
4453
     * @return mixed Users list (array) or the SQL query if $getSQL was set to true
4454
     */
4455
    public static function getUsersFollowedByUser(
4456
        $userId,
4457
        $userStatus = null,
4458
        $getOnlyUserId = false,
4459
        $getSql = false,
4460
        $getCount = false,
4461
        $from = null,
4462
        $numberItems = null,
4463
        $column = null,
4464
        $direction = null,
4465
        $active = null,
4466
        $lastConnectionDate = null,
4467
        $status = null,
4468
        $keyword = null
4469
    ) {
4470
        // Database Table Definitions
4471
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
4472
        $tbl_user_rel_user = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4473
        $tbl_user_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
4474
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
4475
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4476
        $tbl_session_rel_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4477
        $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
4478
        $tbl_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
4479
4480
        $userId = (int) $userId;
4481
        $limitCondition = '';
4482
4483
        if (isset($from) && isset($numberItems)) {
4484
            $from = (int) $from;
4485
            $numberItems = (int) $numberItems;
4486
            $limitCondition = "LIMIT $from, $numberItems";
4487
        }
4488
4489
        $column = Database::escape_string($column);
4490
        $direction = in_array(strtolower($direction), ['asc', 'desc']) ? $direction : null;
4491
4492
        $userConditions = '';
4493
        if (!empty($userStatus)) {
4494
            $userConditions .= ' AND u.status = '.intval($userStatus);
4495
        }
4496
4497
        $select = " SELECT DISTINCT u.id user_id, u.username, u.lastname, u.firstname, u.email ";
4498
        if ($getOnlyUserId) {
4499
            $select = " SELECT DISTINCT u.id user_id";
4500
        }
4501
4502
        $masterSelect = "SELECT DISTINCT * FROM ";
4503
4504
        if ($getCount) {
4505
            $masterSelect = "SELECT COUNT(DISTINCT(user_id)) as count FROM ";
4506
            $select = " SELECT DISTINCT(u.id) user_id";
4507
        }
4508
4509
        if (!is_null($active)) {
4510
            $active = intval($active);
4511
            $userConditions .= " AND u.active = $active ";
4512
        }
4513
4514
        if (!empty($keyword)) {
4515
            $keyword = Database::escape_string($keyword);
4516
            $userConditions .= " AND (
4517
                u.username LIKE '%$keyword%' OR
4518
                u.firstname LIKE '%$keyword%' OR
4519
                u.lastname LIKE '%$keyword%' OR
4520
                u.official_code LIKE '%$keyword%' OR
4521
                u.email LIKE '%$keyword%'
4522
            )";
4523
        }
4524
4525
        if (!empty($lastConnectionDate)) {
4526
            $lastConnectionDate = Database::escape_string($lastConnectionDate);
4527
            $userConditions .= " AND u.last_login <= '$lastConnectionDate' ";
4528
        }
4529
4530
        $sessionConditionsCoach = null;
4531
        $sessionConditionsTeacher = null;
4532
        $drhConditions = null;
4533
        $teacherSelect = null;
4534
4535
        switch ($status) {
4536
            case DRH:
4537
                $drhConditions .= " AND
4538
                    friend_user_id = '$userId' AND
4539
                    relation_type = '".USER_RELATION_TYPE_RRHH."'
4540
                ";
4541
                break;
4542
            case COURSEMANAGER:
4543
                $drhConditions .= " AND
4544
                    friend_user_id = '$userId' AND
4545
                    relation_type = '".USER_RELATION_TYPE_RRHH."'
4546
                ";
4547
4548
                $sessionConditionsCoach .= " AND
4549
                    (s.id_coach = '$userId')
4550
                ";
4551
4552
                $sessionConditionsTeacher .= " AND
4553
                    (scu.status = 2 AND scu.user_id = '$userId')
4554
                ";
4555
4556
                $teacherSelect =
4557
                "UNION ALL (
4558
                        $select
4559
                        FROM $tbl_user u
4560
                        INNER JOIN $tbl_session_rel_user sru ON (sru.user_id = u.id)
4561
                        WHERE
4562
                            (
4563
                                sru.session_id IN (
4564
                                    SELECT DISTINCT(s.id) FROM $tbl_session s INNER JOIN
4565
                                    $tbl_session_rel_access_url session_rel_access_rel_user
4566
                                    ON session_rel_access_rel_user.session_id = s.id
4567
                                    WHERE access_url_id = ".api_get_current_access_url_id()."
4568
                                    $sessionConditionsCoach
4569
                                ) OR sru.session_id IN (
4570
                                    SELECT DISTINCT(s.id) FROM $tbl_session s
4571
                                    INNER JOIN $tbl_session_rel_access_url url
4572
                                    ON (url.session_id = s.id)
4573
                                    INNER JOIN $tbl_session_rel_course_rel_user scu
4574
                                    ON (scu.session_id = s.id)
4575
                                    WHERE access_url_id = ".api_get_current_access_url_id()."
4576
                                    $sessionConditionsTeacher
4577
                                )
4578
                            )
4579
                            $userConditions
4580
                    )
4581
                    UNION ALL(
4582
                        $select
4583
                        FROM $tbl_user u
4584
                        INNER JOIN $tbl_course_user cu ON (cu.user_id = u.id)
4585
                        WHERE cu.c_id IN (
4586
                            SELECT DISTINCT(c_id) FROM $tbl_course_user
4587
                            WHERE user_id = $userId AND status = ".COURSEMANAGER."
4588
                        )
4589
                        $userConditions
4590
                    )"
4591
                ;
4592
                break;
4593
            case STUDENT_BOSS:
4594
                $drhConditions = " AND friend_user_id = $userId AND relation_type = ".USER_RELATION_TYPE_BOSS;
4595
                break;
4596
            case HRM_REQUEST:
4597
                $drhConditions .= " AND
4598
                    friend_user_id = '$userId' AND
4599
                    relation_type = '".USER_RELATION_TYPE_HRM_REQUEST."'
4600
                ";
4601
                break;
4602
        }
4603
4604
        $join = null;
4605
        $sql = " $masterSelect
4606
                (
4607
                    (
4608
                        $select
4609
                        FROM $tbl_user u
4610
                        INNER JOIN $tbl_user_rel_user uru ON (uru.user_id = u.id)
4611
                        LEFT JOIN $tbl_user_rel_access_url a ON (a.user_id = u.id)
4612
                        $join
4613
                        WHERE
4614
                            access_url_id = ".api_get_current_access_url_id()."
4615
                            $drhConditions
4616
                            $userConditions
4617
                    )
4618
                    $teacherSelect
4619
4620
                ) as t1";
4621
4622
        if ($getSql) {
4623
            return $sql;
4624
        }
4625
        if ($getCount) {
4626
            $result = Database::query($sql);
4627
            $row = Database::fetch_array($result);
4628
4629
            return $row['count'];
4630
        }
4631
4632
        $orderBy = null;
4633
        if (false == $getOnlyUserId) {
4634
            if (api_is_western_name_order()) {
4635
                $orderBy .= " ORDER BY firstname, lastname ";
4636
            } else {
4637
                $orderBy .= " ORDER BY lastname, firstname ";
4638
            }
4639
4640
            if (!empty($column) && !empty($direction)) {
4641
                // Fixing order due the UNIONs
4642
                $column = str_replace('u.', '', $column);
4643
                $orderBy = " ORDER BY $column $direction ";
4644
            }
4645
        }
4646
4647
        $sql .= $orderBy;
4648
        $sql .= $limitCondition;
4649
4650
        $result = Database::query($sql);
4651
        $users = [];
4652
        if (Database::num_rows($result) > 0) {
4653
            while ($row = Database::fetch_array($result)) {
4654
                $users[$row['user_id']] = $row;
4655
            }
4656
        }
4657
4658
        return $users;
4659
    }
4660
4661
    /**
4662
     * Subscribes users to human resource manager (Dashboard feature).
4663
     *
4664
     * @param int   $hr_dept_id
4665
     * @param array $users_id
4666
     * @param bool  $deleteOtherAssignedUsers
4667
     *
4668
     * @return int
4669
     */
4670
    public static function subscribeUsersToHRManager(
4671
        $hr_dept_id,
4672
        $users_id,
4673
        $deleteOtherAssignedUsers = true
4674
    ) {
4675
        return self::subscribeUsersToUser(
4676
            $hr_dept_id,
4677
            $users_id,
4678
            USER_RELATION_TYPE_RRHH,
4679
            false,
4680
            $deleteOtherAssignedUsers
4681
        );
4682
    }
4683
4684
    /**
4685
     * Register request to assign users to HRM.
4686
     *
4687
     * @param int   $hrmId   The HRM ID
4688
     * @param array $usersId The users IDs
4689
     *
4690
     * @return int
4691
     */
4692
    public static function requestUsersToHRManager($hrmId, $usersId)
4693
    {
4694
        return self::subscribeUsersToUser(
4695
            $hrmId,
4696
            $usersId,
4697
            USER_RELATION_TYPE_HRM_REQUEST,
4698
            false,
4699
            false
4700
        );
4701
    }
4702
4703
    /**
4704
     * Remove the requests for assign a user to a HRM.
4705
     *
4706
     * @param array $usersId List of user IDs from whom to remove all relations requests with HRM
4707
     */
4708
    public static function clearHrmRequestsForUser(User $hrmId, $usersId)
4709
    {
4710
        $users = implode(', ', $usersId);
4711
        Database::getManager()
4712
            ->createQuery('
4713
                DELETE FROM ChamiloCoreBundle:UserRelUser uru
4714
                WHERE uru.friendUserId = :hrm_id AND uru.relationType = :relation_type AND uru.userId IN (:users_ids)
4715
            ')
4716
            ->execute(['hrm_id' => $hrmId, 'relation_type' => USER_RELATION_TYPE_HRM_REQUEST, 'users_ids' => $users]);
4717
    }
4718
4719
    /**
4720
     * Add subscribed users to a user by relation type.
4721
     *
4722
     * @param int    $userId                   The user id
4723
     * @param array  $subscribedUsersId        The id of subscribed users
4724
     * @param string $relationType             The relation type
4725
     * @param bool   $deleteUsersBeforeInsert
4726
     * @param bool   $deleteOtherAssignedUsers
4727
     *
4728
     * @return int
4729
     */
4730
    public static function subscribeUsersToUser(
4731
        $userId,
4732
        $subscribedUsersId,
4733
        $relationType,
4734
        $deleteUsersBeforeInsert = false,
4735
        $deleteOtherAssignedUsers = true
4736
    ) {
4737
        $userRelUserTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4738
        $userRelAccessUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
4739
4740
        $userId = (int) $userId;
4741
        $relationType = (int) $relationType;
4742
        $affectedRows = 0;
4743
4744
        if ($deleteOtherAssignedUsers) {
4745
            if (api_get_multiple_access_url()) {
4746
                // Deleting assigned users to hrm_id
4747
                $sql = "SELECT s.user_id
4748
                        FROM $userRelUserTable s
4749
                        INNER JOIN $userRelAccessUrlTable a
4750
                        ON (a.user_id = s.user_id)
4751
                        WHERE
4752
                            friend_user_id = $userId AND
4753
                            relation_type = $relationType AND
4754
                            access_url_id = ".api_get_current_access_url_id();
4755
            } else {
4756
                $sql = "SELECT user_id
4757
                        FROM $userRelUserTable
4758
                        WHERE
4759
                            friend_user_id = $userId AND
4760
                            relation_type = $relationType";
4761
            }
4762
            $result = Database::query($sql);
4763
4764
            if (Database::num_rows($result) > 0) {
4765
                while ($row = Database::fetch_array($result)) {
4766
                    $sql = "DELETE FROM $userRelUserTable
4767
                            WHERE
4768
                                user_id = {$row['user_id']} AND
4769
                                friend_user_id = $userId AND
4770
                                relation_type = $relationType";
4771
                    Database::query($sql);
4772
                }
4773
            }
4774
        }
4775
4776
        if ($deleteUsersBeforeInsert) {
4777
            $sql = "DELETE FROM $userRelUserTable
4778
                    WHERE
4779
                        user_id = $userId AND
4780
                        relation_type = $relationType";
4781
            Database::query($sql);
4782
        }
4783
4784
        // Inserting new user list
4785
        if (is_array($subscribedUsersId)) {
4786
            foreach ($subscribedUsersId as $subscribedUserId) {
4787
                $subscribedUserId = (int) $subscribedUserId;
4788
                $sql = "SELECT id
4789
                        FROM $userRelUserTable
4790
                        WHERE
4791
                            user_id = $subscribedUserId AND
4792
                            friend_user_id = $userId AND
4793
                            relation_type = $relationType";
4794
4795
                $result = Database::query($sql);
4796
                $num = Database::num_rows($result);
4797
                if (0 === $num) {
4798
                    $date = api_get_utc_datetime();
4799
                    $sql = "INSERT INTO $userRelUserTable (user_id, friend_user_id, relation_type, last_edit)
4800
                            VALUES ($subscribedUserId, $userId, $relationType, '$date')";
4801
                    $result = Database::query($sql);
4802
                    $affectedRows += Database::affected_rows($result);
4803
                }
4804
            }
4805
        }
4806
4807
        return $affectedRows;
4808
    }
4809
4810
    /**
4811
     * This function check if an user is followed by human resources manager.
4812
     *
4813
     * @param int $user_id
4814
     * @param int $hr_dept_id Human resources manager
4815
     *
4816
     * @return bool
4817
     */
4818
    public static function is_user_followed_by_drh($user_id, $hr_dept_id)
4819
    {
4820
        $tbl_user_rel_user = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4821
        $user_id = (int) $user_id;
4822
        $hr_dept_id = (int) $hr_dept_id;
4823
        $result = false;
4824
4825
        $sql = "SELECT user_id FROM $tbl_user_rel_user
4826
                WHERE
4827
                    user_id = $user_id AND
4828
                    friend_user_id = $hr_dept_id AND
4829
                    relation_type = ".USER_RELATION_TYPE_RRHH;
4830
        $rs = Database::query($sql);
4831
        if (Database::num_rows($rs) > 0) {
4832
            $result = true;
4833
        }
4834
4835
        return $result;
4836
    }
4837
4838
    /**
4839
     * Return the user id of teacher or session administrator.
4840
     *
4841
     * @param array $courseInfo
4842
     *
4843
     * @return mixed The user id, or false if the session ID was negative
4844
     */
4845
    public static function get_user_id_of_course_admin_or_session_admin($courseInfo)
4846
    {
4847
        $session = api_get_session_id();
4848
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
4849
        $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4850
        $table_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4851
4852
        if (empty($courseInfo)) {
4853
            return false;
4854
        }
4855
4856
        $courseId = $courseInfo['real_id'];
4857
4858
        if (0 == $session || is_null($session)) {
4859
            $sql = 'SELECT u.id uid FROM '.$table_user.' u
4860
                    INNER JOIN '.$table_course_user.' ru
4861
                    ON ru.user_id = u.id
4862
                    WHERE
4863
                        ru.status = 1 AND
4864
                        ru.c_id = "'.$courseId.'" ';
4865
            $rs = Database::query($sql);
4866
            $num_rows = Database::num_rows($rs);
4867
            if (1 == $num_rows) {
4868
                $row = Database::fetch_array($rs);
4869
4870
                return $row['uid'];
4871
            } else {
4872
                $my_num_rows = $num_rows;
4873
                $my_user_id = Database::result($rs, $my_num_rows - 1, 'uid');
4874
4875
                return $my_user_id;
4876
            }
4877
        } elseif ($session > 0) {
4878
            $sql = 'SELECT u.id uid FROM '.$table_user.' u
4879
                    INNER JOIN '.$table_session_course_user.' sru
4880
                    ON sru.user_id=u.id
4881
                    WHERE
4882
                        sru.c_id="'.$courseId.'" AND
4883
                        sru.status=2';
4884
            $rs = Database::query($sql);
4885
            $row = Database::fetch_array($rs);
4886
4887
            return $row['uid'];
4888
        }
4889
4890
        return false;
4891
    }
4892
4893
    /**
4894
     * Determines if a user is a gradebook certified.
4895
     *
4896
     * @param int $cat_id  The category id of gradebook
4897
     * @param int $user_id The user id
4898
     *
4899
     * @return bool
4900
     */
4901
    public static function is_user_certified($cat_id, $user_id)
4902
    {
4903
        $cat_id = (int) $cat_id;
4904
        $user_id = (int) $user_id;
4905
4906
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
4907
        $sql = 'SELECT path_certificate
4908
                FROM '.$table.'
4909
                WHERE
4910
                    cat_id = "'.$cat_id.'" AND
4911
                    user_id = "'.$user_id.'"';
4912
        $rs = Database::query($sql);
4913
        $row = Database::fetch_array($rs);
4914
4915
        if ('' == $row['path_certificate'] || is_null($row['path_certificate'])) {
4916
            return false;
4917
        }
4918
4919
        return true;
4920
    }
4921
4922
    /**
4923
     * Gets the info about a gradebook certificate for a user by course.
4924
     *
4925
     * @param array $course_info The course code
4926
     * @param int   $session_id
4927
     * @param int   $user_id     The user id
4928
     *
4929
     * @return array if there is not information return false
4930
     */
4931
    public static function get_info_gradebook_certificate($course_info, $session_id, $user_id)
4932
    {
4933
        $tbl_grade_certificate = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
4934
        $tbl_grade_category = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
4935
        $session_id = (int) $session_id;
4936
        $user_id = (int) $user_id;
4937
        $courseId = $course_info['real_id'];
4938
4939
        if (empty($session_id)) {
4940
            $session_condition = ' AND (session_id = "" OR session_id = 0 OR session_id IS NULL )';
4941
        } else {
4942
            $session_condition = " AND session_id = $session_id";
4943
        }
4944
4945
        $sql = 'SELECT * FROM '.$tbl_grade_certificate.'
4946
                WHERE cat_id = (
4947
                    SELECT id FROM '.$tbl_grade_category.'
4948
                    WHERE
4949
                        c_id = "'.$courseId.'" '.$session_condition.'
4950
                    LIMIT 1
4951
                ) AND user_id='.$user_id;
4952
4953
        $rs = Database::query($sql);
4954
        if (Database::num_rows($rs) > 0) {
4955
            $row = Database::fetch_array($rs, 'ASSOC');
4956
            $score = $row['score_certificate'];
4957
            $category_id = $row['cat_id'];
4958
            $cat = Category::load($category_id);
4959
            $displayscore = ScoreDisplay::instance();
4960
            if (isset($cat) && $displayscore->is_custom()) {
4961
                $grade = $displayscore->display_score(
4962
                    [$score, $cat[0]->get_weight()],
4963
                    SCORE_DIV_PERCENT_WITH_CUSTOM
4964
                );
4965
            } else {
4966
                $grade = $displayscore->display_score(
4967
                    [$score, $cat[0]->get_weight()]
4968
                );
4969
            }
4970
            $row['grade'] = $grade;
4971
4972
            return $row;
4973
        }
4974
4975
        return false;
4976
    }
4977
4978
    /**
4979
     * This function check if the user is a coach inside session course.
4980
     *
4981
     * @param int $user_id    User id
4982
     * @param int $courseId
4983
     * @param int $session_id
4984
     *
4985
     * @return bool True if the user is a coach
4986
     */
4987
    public static function is_session_course_coach($user_id, $courseId, $session_id)
4988
    {
4989
        $table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4990
        // Protect data
4991
        $user_id = intval($user_id);
4992
        $courseId = intval($courseId);
4993
        $session_id = intval($session_id);
4994
        $result = false;
4995
4996
        $sql = "SELECT session_id FROM $table
4997
                WHERE
4998
                  session_id = $session_id AND
4999
                  c_id = $courseId AND
5000
                  user_id = $user_id AND
5001
                  status = 2 ";
5002
        $res = Database::query($sql);
5003
5004
        if (Database::num_rows($res) > 0) {
5005
            $result = true;
5006
        }
5007
5008
        return $result;
5009
    }
5010
5011
    /**
5012
     * This function returns an icon path that represents the favicon of the website of which the url given.
5013
     * Defaults to the current Chamilo favicon.
5014
     *
5015
     * @param string $url1 URL of website where to look for favicon.ico
5016
     * @param string $url2 Optional second URL of website where to look for favicon.ico
5017
     *
5018
     * @return string Path of icon to load
5019
     */
5020
    public static function get_favicon_from_url($url1, $url2 = null)
5021
    {
5022
        $icon_link = '';
5023
        $url = $url1;
5024
        if (empty($url1)) {
5025
            $url = $url2;
5026
            if (empty($url)) {
5027
                $url = api_get_access_url(api_get_current_access_url_id());
5028
                $url = $url[0];
5029
            }
5030
        }
5031
        if (!empty($url)) {
5032
            $pieces = parse_url($url);
5033
            $icon_link = $pieces['scheme'].'://'.$pieces['host'].'/favicon.ico';
5034
        }
5035
5036
        return $icon_link;
5037
    }
5038
5039
    public static function addUserAsAdmin(User $user)
5040
    {
5041
        if ($user) {
5042
            $userId = $user->getId();
5043
5044
            if (!self::is_admin($userId)) {
5045
                $table = Database::get_main_table(TABLE_MAIN_ADMIN);
5046
                $sql = "INSERT INTO $table SET user_id = $userId";
5047
                Database::query($sql);
5048
            }
5049
5050
            $user->addRole('ROLE_SUPER_ADMIN');
5051
            self::getRepository()->updateUser($user, true);
5052
        }
5053
    }
5054
5055
    public static function removeUserAdmin(User $user)
5056
    {
5057
        $userId = (int) $user->getId();
5058
        if (self::is_admin($userId)) {
5059
            $table = Database::get_main_table(TABLE_MAIN_ADMIN);
5060
            $sql = "DELETE FROM $table WHERE user_id = $userId";
5061
            Database::query($sql);
5062
            $user->removeRole('ROLE_SUPER_ADMIN');
5063
            self::getRepository()->updateUser($user, true);
5064
        }
5065
    }
5066
5067
    /**
5068
     * @param string $from
5069
     * @param string $to
5070
     */
5071
    public static function update_all_user_languages($from, $to)
5072
    {
5073
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
5074
        $from = Database::escape_string($from);
5075
        $to = Database::escape_string($to);
5076
5077
        if (!empty($to) && !empty($from)) {
5078
            $sql = "UPDATE $table_user SET language = '$to'
5079
                    WHERE language = '$from'";
5080
            Database::query($sql);
5081
        }
5082
    }
5083
5084
    /**
5085
     * Subscribe boss to students.
5086
     *
5087
     * @param int   $bossId  The boss id
5088
     * @param array $usersId The users array
5089
     *
5090
     * @return int Affected rows
5091
     */
5092
    public static function subscribeBossToUsers($bossId, $usersId)
5093
    {
5094
        return self::subscribeUsersToUser(
5095
            $bossId,
5096
            $usersId,
5097
            USER_RELATION_TYPE_BOSS
5098
        );
5099
    }
5100
5101
    /**
5102
     * @param int $userId
5103
     *
5104
     * @return bool
5105
     */
5106
    public static function removeAllBossFromStudent($userId)
5107
    {
5108
        $userId = (int) $userId;
5109
5110
        if (empty($userId)) {
5111
            return false;
5112
        }
5113
5114
        $userRelUserTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5115
        $sql = "DELETE FROM $userRelUserTable
5116
                WHERE user_id = $userId AND relation_type = ".USER_RELATION_TYPE_BOSS;
5117
        Database::query($sql);
5118
5119
        return true;
5120
    }
5121
5122
    /**
5123
     * Subscribe boss to students, if $bossList is empty then the boss list will be empty too.
5124
     *
5125
     * @param int   $studentId
5126
     * @param array $bossList
5127
     * @param bool  $sendNotification
5128
     *
5129
     * @return mixed Affected rows or false on failure
5130
     */
5131
    public static function subscribeUserToBossList(
5132
        $studentId,
5133
        $bossList,
5134
        $sendNotification = false
5135
    ) {
5136
        $inserted = 0;
5137
        if (!empty($bossList)) {
5138
            sort($bossList);
5139
            $studentId = (int) $studentId;
5140
            $studentInfo = api_get_user_info($studentId);
5141
5142
            if (empty($studentInfo)) {
5143
                return false;
5144
            }
5145
5146
            $previousBossList = self::getStudentBossList($studentId);
5147
            $previousBossList = !empty($previousBossList) ? array_column($previousBossList, 'boss_id') : [];
5148
            sort($previousBossList);
5149
5150
            // Boss list is the same, nothing changed.
5151
            if ($bossList == $previousBossList) {
5152
                return false;
5153
            }
5154
5155
            $userRelUserTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5156
            self::removeAllBossFromStudent($studentId);
5157
5158
            foreach ($bossList as $bossId) {
5159
                $bossId = (int) $bossId;
5160
                $bossInfo = api_get_user_info($bossId);
5161
5162
                if (empty($bossInfo)) {
5163
                    continue;
5164
                }
5165
5166
                $bossLanguage = $bossInfo['language'];
5167
                $sql = "INSERT IGNORE INTO $userRelUserTable (user_id, friend_user_id, relation_type)
5168
                        VALUES ($studentId, $bossId, ".USER_RELATION_TYPE_BOSS.")";
5169
                $insertId = Database::query($sql);
5170
5171
                if ($insertId) {
5172
                    if ($sendNotification) {
5173
                        $name = $studentInfo['complete_name'];
5174
                        $url = api_get_path(WEB_CODE_PATH).'mySpace/myStudents.php?student='.$studentId;
5175
                        $url = Display::url($url, $url);
5176
                        $subject = sprintf(get_lang('You have been assigned the learner %s'), $name);
5177
                        $message = sprintf(get_lang('You have been assigned the learner %sWithUrlX'), $name, $url);
5178
                        MessageManager::send_message_simple(
5179
                            $bossId,
5180
                            $subject,
5181
                            $message
5182
                        );
5183
                    }
5184
                    $inserted++;
5185
                }
5186
            }
5187
        } else {
5188
            self::removeAllBossFromStudent($studentId);
5189
        }
5190
5191
        return $inserted;
5192
    }
5193
5194
    /**
5195
     * Get users followed by student boss.
5196
     *
5197
     * @param int    $userId
5198
     * @param int    $userStatus         (STUDENT, COURSEMANAGER, etc)
5199
     * @param bool   $getOnlyUserId
5200
     * @param bool   $getSql
5201
     * @param bool   $getCount
5202
     * @param int    $from
5203
     * @param int    $numberItems
5204
     * @param int    $column
5205
     * @param string $direction
5206
     * @param int    $active
5207
     * @param string $lastConnectionDate
5208
     *
5209
     * @return array users
5210
     */
5211
    public static function getUsersFollowedByStudentBoss(
5212
        $userId,
5213
        $userStatus = 0,
5214
        $getOnlyUserId = false,
5215
        $getSql = false,
5216
        $getCount = false,
5217
        $from = null,
5218
        $numberItems = null,
5219
        $column = null,
5220
        $direction = null,
5221
        $active = null,
5222
        $lastConnectionDate = null
5223
    ) {
5224
        return self::getUsersFollowedByUser(
5225
            $userId,
5226
            $userStatus,
5227
            $getOnlyUserId,
5228
            $getSql,
5229
            $getCount,
5230
            $from,
5231
            $numberItems,
5232
            $column,
5233
            $direction,
5234
            $active,
5235
            $lastConnectionDate,
5236
            STUDENT_BOSS
5237
        );
5238
    }
5239
5240
    /**
5241
     * @return array
5242
     */
5243
    public static function getOfficialCodeGrouped()
5244
    {
5245
        $user = Database::get_main_table(TABLE_MAIN_USER);
5246
        $sql = "SELECT DISTINCT official_code
5247
                FROM $user
5248
                GROUP BY official_code";
5249
        $result = Database::query($sql);
5250
        $values = Database::store_result($result, 'ASSOC');
5251
        $result = [];
5252
        foreach ($values as $value) {
5253
            $result[$value['official_code']] = $value['official_code'];
5254
        }
5255
5256
        return $result;
5257
    }
5258
5259
    /**
5260
     * @param string $officialCode
5261
     *
5262
     * @return array
5263
     */
5264
    public static function getUsersByOfficialCode($officialCode)
5265
    {
5266
        $user = Database::get_main_table(TABLE_MAIN_USER);
5267
        $officialCode = Database::escape_string($officialCode);
5268
5269
        $sql = "SELECT DISTINCT id
5270
                FROM $user
5271
                WHERE official_code = '$officialCode'
5272
                ";
5273
        $result = Database::query($sql);
5274
5275
        $users = [];
5276
        while ($row = Database::fetch_array($result)) {
5277
            $users[] = $row['id'];
5278
        }
5279
5280
        return $users;
5281
    }
5282
5283
    /**
5284
     * Calc the expended time (in seconds) by a user in a course.
5285
     *
5286
     * @param int    $userId    The user id
5287
     * @param int    $courseId  The course id
5288
     * @param int    $sessionId Optional. The session id
5289
     * @param string $from      Optional. From date
5290
     * @param string $until     Optional. Until date
5291
     *
5292
     * @return int The time
5293
     */
5294
    public static function getTimeSpentInCourses(
5295
        $userId,
5296
        $courseId,
5297
        $sessionId = 0,
5298
        $from = '',
5299
        $until = ''
5300
    ) {
5301
        $userId = (int) $userId;
5302
        $sessionId = (int) $sessionId;
5303
5304
        $trackCourseAccessTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5305
        $whereConditions = [
5306
            'user_id = ? ' => $userId,
5307
            'AND c_id = ? ' => $courseId,
5308
            'AND session_id = ? ' => $sessionId,
5309
        ];
5310
5311
        if (!empty($from) && !empty($until)) {
5312
            $whereConditions["AND (login_course_date >= '?' "] = $from;
5313
            $whereConditions["AND logout_course_date <= DATE_ADD('?', INTERVAL 1 DAY)) "] = $until;
5314
        }
5315
5316
        $trackResult = Database::select(
5317
            'SUM(UNIX_TIMESTAMP(logout_course_date) - UNIX_TIMESTAMP(login_course_date)) as total_time',
5318
            $trackCourseAccessTable,
5319
            [
5320
                'where' => $whereConditions,
5321
            ],
5322
            'first'
5323
        );
5324
5325
        if (false != $trackResult) {
5326
            return $trackResult['total_time'] ? $trackResult['total_time'] : 0;
5327
        }
5328
5329
        return 0;
5330
    }
5331
5332
    /**
5333
     * Get the boss user ID from a followed user id.
5334
     *
5335
     * @param $userId
5336
     *
5337
     * @return bool
5338
     */
5339
    public static function getFirstStudentBoss($userId)
5340
    {
5341
        $userId = (int) $userId;
5342
        if ($userId > 0) {
5343
            $userRelTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5344
            $row = Database::select(
5345
                'DISTINCT friend_user_id AS boss_id',
5346
                $userRelTable,
5347
                [
5348
                    'where' => [
5349
                        'user_id = ? AND relation_type = ? LIMIT 1' => [
5350
                            $userId,
5351
                            USER_RELATION_TYPE_BOSS,
5352
                        ],
5353
                    ],
5354
                ]
5355
            );
5356
            if (!empty($row)) {
5357
                return $row[0]['boss_id'];
5358
            }
5359
        }
5360
5361
        return false;
5362
    }
5363
5364
    /**
5365
     * Get the boss user ID from a followed user id.
5366
     *
5367
     * @param int $userId student id
5368
     *
5369
     * @return array
5370
     */
5371
    public static function getStudentBossList($userId)
5372
    {
5373
        $userId = (int) $userId;
5374
5375
        if ($userId > 0) {
5376
            $userRelTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5377
            $result = Database::select(
5378
                'DISTINCT friend_user_id AS boss_id',
5379
                $userRelTable,
5380
                [
5381
                    'where' => [
5382
                        'user_id = ? AND relation_type = ? ' => [
5383
                            $userId,
5384
                            USER_RELATION_TYPE_BOSS,
5385
                        ],
5386
                    ],
5387
                ]
5388
            );
5389
5390
            return $result;
5391
        }
5392
5393
        return [];
5394
    }
5395
5396
    /**
5397
     * @param int $bossId
5398
     * @param int $studentId
5399
     *
5400
     * @return bool
5401
     */
5402
    public static function userIsBossOfStudent($bossId, $studentId)
5403
    {
5404
        $result = false;
5405
        $bossList = self::getStudentBossList($studentId);
5406
        if (!empty($bossList)) {
5407
            $bossList = array_column($bossList, 'boss_id');
5408
            if (in_array($bossId, $bossList)) {
5409
                $result = true;
5410
            }
5411
        }
5412
5413
        return $result;
5414
    }
5415
5416
    /**
5417
     * Displays the name of the user and makes the link to the user profile.
5418
     *
5419
     * @param array $userInfo
5420
     *
5421
     * @return string
5422
     */
5423
    public static function getUserProfileLink($userInfo)
5424
    {
5425
        if (isset($userInfo) && isset($userInfo['user_id'])) {
5426
            return Display::url(
5427
                $userInfo['complete_name_with_username'],
5428
                $userInfo['profile_url']
5429
            );
5430
        }
5431
5432
        return get_lang('Anonymous');
5433
    }
5434
5435
    /**
5436
     * Get users whose name matches $firstname and $lastname.
5437
     *
5438
     * @param string $firstname Firstname to search
5439
     * @param string $lastname  Lastname to search
5440
     *
5441
     * @return array The user list
5442
     */
5443
    public static function getUsersByName($firstname, $lastname)
5444
    {
5445
        $firstname = Database::escape_string($firstname);
5446
        $lastname = Database::escape_string($lastname);
5447
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
5448
5449
        $sql = <<<SQL
5450
            SELECT id, username, lastname, firstname
5451
            FROM $userTable
5452
            WHERE
5453
                firstname LIKE '$firstname%' AND
5454
                lastname LIKE '$lastname%'
5455
SQL;
5456
        $result = Database::query($sql);
5457
        $users = [];
5458
        while ($resultData = Database::fetch_object($result)) {
5459
            $users[] = $resultData;
5460
        }
5461
5462
        return $users;
5463
    }
5464
5465
    /**
5466
     * @param int $optionSelected
5467
     *
5468
     * @return string
5469
     */
5470
    public static function getUserSubscriptionTab($optionSelected = 1)
5471
    {
5472
        $allowAdmin = api_get_setting('allow_user_course_subscription_by_course_admin');
5473
        if (('true' === $allowAdmin && api_is_allowed_to_edit()) ||
5474
            api_is_platform_admin()
5475
        ) {
5476
            $userPath = api_get_path(WEB_CODE_PATH).'user/';
5477
5478
            $headers = [
5479
                [
5480
                    'url' => $userPath.'user.php?'.api_get_cidreq().'&type='.STUDENT,
5481
                    'content' => get_lang('Learners'),
5482
                ],
5483
                [
5484
                    'url' => $userPath.'user.php?'.api_get_cidreq().'&type='.COURSEMANAGER,
5485
                    'content' => get_lang('Trainers'),
5486
                ],
5487
                /*[
5488
                    'url' => $userPath.'subscribe_user.php?'.api_get_cidreq(),
5489
                    'content' => get_lang('Learners'),
5490
                ],
5491
                [
5492
                    'url' => $userPath.'subscribe_user.php?type=teacher&'.api_get_cidreq(),
5493
                    'content' => get_lang('Trainers'),
5494
                ],*/
5495
                [
5496
                    'url' => api_get_path(WEB_CODE_PATH).'group/group.php?'.api_get_cidreq(),
5497
                    'content' => get_lang('Groups'),
5498
                ],
5499
                [
5500
                    'url' => $userPath.'class.php?'.api_get_cidreq(),
5501
                    'content' => get_lang('Classes'),
5502
                ],
5503
            ];
5504
5505
            return Display::tabsOnlyLink($headers, $optionSelected);
5506
        }
5507
5508
        return '';
5509
    }
5510
5511
    /**
5512
     * Make sure this function is protected because it does NOT check password!
5513
     *
5514
     * This function defines globals.
5515
     *
5516
     * @param int  $userId
5517
     * @param bool $checkIfUserCanLoginAs
5518
     *
5519
     * @return bool
5520
     *
5521
     * @author Evie Embrechts
5522
     * @author Yannick Warnier <[email protected]>
5523
     */
5524
    public static function loginAsUser($userId, $checkIfUserCanLoginAs = true)
5525
    {
5526
        $userId = (int) $userId;
5527
        $userInfo = api_get_user_info($userId);
5528
5529
        // Check if the user is allowed to 'login_as'
5530
        $canLoginAs = true;
5531
        if ($checkIfUserCanLoginAs) {
5532
            $canLoginAs = api_can_login_as($userId);
5533
        }
5534
5535
        if (!$canLoginAs || empty($userInfo)) {
5536
            return false;
5537
        }
5538
5539
        if ($userId) {
5540
            $logInfo = [
5541
                'tool' => 'logout',
5542
                'tool_id' => 0,
5543
                'tool_id_detail' => 0,
5544
                'action' => '',
5545
                'info' => 'Change user (login as)',
5546
            ];
5547
            Event::registerLog($logInfo);
5548
5549
            // Logout the current user
5550
            self::loginDelete(api_get_user_id());
5551
5552
            return true;
5553
5554
            Session::erase('_user');
5555
            Session::erase('is_platformAdmin');
5556
            Session::erase('is_allowedCreateCourse');
5557
            Session::erase('_uid');
5558
5559
            // Cleaning session variables
5560
            $_user['firstName'] = $userInfo['firstname'];
5561
            $_user['lastName'] = $userInfo['lastname'];
5562
            $_user['mail'] = $userInfo['email'];
5563
            $_user['official_code'] = $userInfo['official_code'];
5564
            $_user['picture_uri'] = $userInfo['picture_uri'];
5565
            $_user['user_id'] = $userId;
5566
            $_user['id'] = $userId;
5567
            $_user['status'] = $userInfo['status'];
5568
5569
            // Filling session variables with new data
5570
            Session::write('_uid', $userId);
5571
            Session::write('_user', $userInfo);
5572
            Session::write('is_platformAdmin', (bool) self::is_admin($userId));
5573
            Session::write('is_allowedCreateCourse', 1 == $userInfo['status']);
5574
            // will be useful later to know if the user is actually an admin or not (example reporting)
5575
            Session::write('login_as', true);
5576
            $logInfo = [
5577
                'tool' => 'login',
5578
                'tool_id' => 0,
5579
                'tool_id_detail' => 0,
5580
                'info' => $userId,
5581
            ];
5582
            Event::registerLog($logInfo);
5583
5584
            return true;
5585
        }
5586
5587
        return false;
5588
    }
5589
5590
    /**
5591
     * Remove all login records from the track_e_online stats table,
5592
     * for the given user ID.
5593
     *
5594
     * @param int $userId User ID
5595
     */
5596
    public static function loginDelete($userId)
5597
    {
5598
        $online_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ONLINE);
5599
        $userId = (int) $userId;
5600
        $query = "DELETE FROM $online_table WHERE login_user_id = $userId";
5601
        Database::query($query);
5602
    }
5603
5604
    /**
5605
     * Login as first admin user registered in the platform.
5606
     *
5607
     * @return array
5608
     */
5609
    public static function logInAsFirstAdmin()
5610
    {
5611
        $adminList = self::get_all_administrators();
5612
5613
        if (!empty($adminList)) {
5614
            $userInfo = current($adminList);
5615
            if (!empty($userInfo)) {
5616
                $result = self::loginAsUser($userInfo['user_id'], false);
5617
                if ($result && api_is_platform_admin()) {
5618
                    return api_get_user_info();
5619
                }
5620
            }
5621
        }
5622
5623
        return [];
5624
    }
5625
5626
    /**
5627
     * Check if user is teacher of a student based in their courses.
5628
     *
5629
     * @param $teacherId
5630
     * @param $studentId
5631
     *
5632
     * @return array
5633
     */
5634
    public static function getCommonCoursesBetweenTeacherAndStudent($teacherId, $studentId)
5635
    {
5636
        $courses = CourseManager::getCoursesFollowedByUser(
5637
            $teacherId,
5638
            COURSEMANAGER
5639
        );
5640
        if (empty($courses)) {
5641
            return false;
5642
        }
5643
5644
        $coursesFromUser = CourseManager::get_courses_list_by_user_id($studentId);
5645
        if (empty($coursesFromUser)) {
5646
            return false;
5647
        }
5648
5649
        $coursesCodeList = array_column($courses, 'code');
5650
        $coursesCodeFromUserList = array_column($coursesFromUser, 'code');
5651
        $commonCourses = array_intersect($coursesCodeList, $coursesCodeFromUserList);
5652
        $commonCourses = array_filter($commonCourses);
5653
5654
        if (!empty($commonCourses)) {
5655
            return $commonCourses;
5656
        }
5657
5658
        return [];
5659
    }
5660
5661
    /**
5662
     * @param int $teacherId
5663
     * @param int $studentId
5664
     *
5665
     * @return bool
5666
     */
5667
    public static function isTeacherOfStudent($teacherId, $studentId)
5668
    {
5669
        $courses = self::getCommonCoursesBetweenTeacherAndStudent(
5670
            $teacherId,
5671
            $studentId
5672
        );
5673
5674
        if (!empty($courses)) {
5675
            return true;
5676
        }
5677
5678
        return false;
5679
    }
5680
5681
    /**
5682
     * Send user confirmation mail.
5683
     *
5684
     * @throws Exception
5685
     */
5686
    public static function sendUserConfirmationMail(User $user)
5687
    {
5688
        $uniqueId = api_get_unique_id();
5689
        $user->setConfirmationToken($uniqueId);
5690
5691
        Database::getManager()->persist($user);
5692
        Database::getManager()->flush();
5693
5694
        $url = api_get_path(WEB_CODE_PATH).'auth/user_mail_confirmation.php?token='.$uniqueId;
5695
5696
        // Check if the user was originally set for an automated subscription to a course or session
5697
        $courseCodeToRedirect = Session::read('course_redirect');
5698
        $sessionToRedirect = Session::read('session_redirect');
5699
        if (!empty($courseCodeToRedirect)) {
5700
            $url .= '&c='.$courseCodeToRedirect;
5701
        }
5702
        if (!empty($sessionToRedirect)) {
5703
            $url .= '&s='.$sessionToRedirect;
5704
        }
5705
        $mailSubject = get_lang('Registration confirmation');
5706
        $mailBody = get_lang('Registration confirmationEmailMessage')
5707
            .PHP_EOL
5708
            .Display::url($url, $url);
5709
5710
        api_mail_html(
5711
            self::formatUserFullName($user),
5712
            $user->getEmail(),
5713
            $mailSubject,
5714
            $mailBody
5715
        );
5716
        Display::addFlash(Display::return_message(get_lang('Check your e-mail and follow the instructions.')));
5717
    }
5718
5719
    /**
5720
     * Anonymize a user. Replace personal info by anonymous info.
5721
     *
5722
     * @param int  $userId   User id
5723
     * @param bool $deleteIP Whether to replace the IP address in logs tables by 127.0.0.1 or to leave as is
5724
     *
5725
     * @throws \Exception
5726
     *
5727
     * @return bool
5728
     * @assert (0) === false
5729
     */
5730
    public static function anonymize($userId, $deleteIP = true)
5731
    {
5732
        global $debug;
5733
5734
        $userId = (int) $userId;
5735
5736
        if (empty($userId)) {
5737
            return false;
5738
        }
5739
5740
        $em = Database::getManager();
5741
        $user = api_get_user_entity($userId);
5742
        $uniqueId = uniqid('anon', true);
5743
        $user
5744
            ->setFirstname($uniqueId)
5745
            ->setLastname($uniqueId)
5746
            ->setBiography('')
5747
            ->setAddress('')
5748
            ->setCurriculumItems(null)
5749
            ->setDateOfBirth(null)
5750
            ->setCompetences('')
5751
            ->setDiplomas('')
5752
            ->setOpenarea('')
5753
            ->setTeach('')
5754
            ->setProductions(null)
5755
            ->setOpenid('')
5756
            ->setEmailCanonical($uniqueId.'@example.com')
5757
            ->setEmail($uniqueId.'@example.com')
5758
            ->setUsername($uniqueId)
5759
            ->setUsernameCanonical($uniqueId)
5760
            ->setPhone('')
5761
            ->setOfficialCode('')
5762
        ;
5763
5764
        self::deleteUserPicture($userId);
5765
        self::cleanUserRequestsOfRemoval($userId);
5766
5767
        // The IP address is a border-case personal data, as it does
5768
        // not directly allow for personal identification (it is not
5769
        // a completely safe value in most countries - the IP could
5770
        // be used by neighbours and crackers)
5771
        if ($deleteIP) {
5772
            $substitute = '127.0.0.1';
5773
            $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
5774
            $sql = "UPDATE $table set user_ip = '$substitute' WHERE access_user_id = $userId";
5775
            $res = Database::query($sql);
5776
            if (false === $res && $debug > 0) {
5777
                error_log("Could not anonymize IP address for user $userId ($sql)");
5778
            }
5779
5780
            $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5781
            $sql = "UPDATE $table set user_ip = '$substitute' WHERE user_id = $userId";
5782
            $res = Database::query($sql);
5783
            if (false === $res && $debug > 0) {
5784
                error_log("Could not anonymize IP address for user $userId ($sql)");
5785
            }
5786
5787
            $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
5788
            $sql = "UPDATE $table set user_ip = '$substitute' WHERE exe_user_id = $userId";
5789
            $res = Database::query($sql);
5790
            if (false === $res && $debug > 0) {
5791
                error_log("Could not anonymize IP address for user $userId ($sql)");
5792
            }
5793
5794
            $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
5795
            $sql = "UPDATE $table set user_ip = '$substitute' WHERE login_user_id = $userId";
5796
            $res = Database::query($sql);
5797
            if (false === $res && $debug > 0) {
5798
                error_log("Could not anonymize IP address for user $userId ($sql)");
5799
            }
5800
5801
            $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ONLINE);
5802
            $sql = "UPDATE $table set user_ip = '$substitute' WHERE login_user_id = $userId";
5803
            $res = Database::query($sql);
5804
            if (false === $res && $debug > 0) {
5805
                error_log("Could not anonymize IP address for user $userId ($sql)");
5806
            }
5807
5808
            $table = Database::get_course_table(TABLE_WIKI);
5809
            $sql = "UPDATE $table set user_ip = '$substitute' WHERE user_id = $userId";
5810
            $res = Database::query($sql);
5811
            if (false === $res && $debug > 0) {
5812
                error_log("Could not anonymize IP address for user $userId ($sql)");
5813
            }
5814
5815
            $table = Database::get_main_table(TABLE_TICKET_MESSAGE);
5816
            $sql = "UPDATE $table set ip_address = '$substitute' WHERE sys_insert_user_id = $userId";
5817
            $res = Database::query($sql);
5818
            if (false === $res && $debug > 0) {
5819
                error_log("Could not anonymize IP address for user $userId ($sql)");
5820
            }
5821
5822
            $table = Database::get_course_table(TABLE_WIKI);
5823
            $sql = "UPDATE $table set user_ip = '$substitute' WHERE user_id = $userId";
5824
            $res = Database::query($sql);
5825
            if (false === $res && $debug > 0) {
5826
                error_log("Could not anonymize IP address for user $userId ($sql)");
5827
            }
5828
        }
5829
        $em->persist($user);
5830
        $em->flush();
5831
        Event::addEvent(LOG_USER_ANONYMIZE, LOG_USER_ID, $userId);
5832
5833
        return true;
5834
    }
5835
5836
    /**
5837
     * @param int $userId
5838
     *
5839
     * @throws Exception
5840
     *
5841
     * @return string
5842
     */
5843
    public static function anonymizeUserWithVerification($userId)
5844
    {
5845
        $allowDelete = api_get_configuration_value('allow_delete_user_for_session_admin');
5846
5847
        $message = '';
5848
        if (api_is_platform_admin() ||
5849
            ($allowDelete && api_is_session_admin())
5850
        ) {
5851
            $userToUpdateInfo = api_get_user_info($userId);
5852
            $currentUserId = api_get_user_id();
5853
5854
            if ($userToUpdateInfo &&
5855
                api_global_admin_can_edit_admin($userId, null, $allowDelete)
5856
            ) {
5857
                if ($userId != $currentUserId &&
5858
                    self::anonymize($userId)
5859
                ) {
5860
                    $message = Display::return_message(
5861
                        sprintf(get_lang('User %s information anonymized.'), $userToUpdateInfo['complete_name_with_username']),
5862
                        'confirmation'
5863
                    );
5864
                } else {
5865
                    $message = Display::return_message(
5866
                        sprintf(get_lang('We could not anonymize user %s information. Please try again or check the logs.'), $userToUpdateInfo['complete_name_with_username']),
5867
                        'error'
5868
                    );
5869
                }
5870
            } else {
5871
                $message = Display::return_message(
5872
                    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']),
5873
                    'error'
5874
                );
5875
            }
5876
        }
5877
5878
        return $message;
5879
    }
5880
5881
    /**
5882
     * @param int $userId
5883
     *
5884
     * @throws Exception
5885
     *
5886
     * @return string
5887
     */
5888
    public static function deleteUserWithVerification($userId)
5889
    {
5890
        $allowDelete = api_get_configuration_value('allow_delete_user_for_session_admin');
5891
        $message = Display::return_message(get_lang('You cannot delete this user'), 'error');
5892
        $userToUpdateInfo = api_get_user_info($userId);
5893
5894
        // User must exist.
5895
        if (empty($userToUpdateInfo)) {
5896
            return $message;
5897
        }
5898
5899
        $currentUserId = api_get_user_id();
5900
5901
        // Cannot delete myself.
5902
        if ($userId == $currentUserId) {
5903
            return $message;
5904
        }
5905
5906
        if (api_is_platform_admin() ||
5907
            ($allowDelete && api_is_session_admin())
5908
        ) {
5909
            if (api_global_admin_can_edit_admin($userId, null, $allowDelete)) {
5910
                if (self::delete_user($userId)) {
5911
                    $message = Display::return_message(
5912
                        get_lang('The user has been deleted').': '.$userToUpdateInfo['complete_name_with_username'],
5913
                        'confirmation'
5914
                    );
5915
                } else {
5916
                    $message = Display::return_message(get_lang('You cannot delete this userBecauseOwnsCourse'), 'error');
5917
                }
5918
            }
5919
        }
5920
5921
        return $message;
5922
    }
5923
5924
    /**
5925
     * @return array
5926
     */
5927
    public static function createDataPrivacyExtraFields()
5928
    {
5929
        self::create_extra_field(
5930
            'request_for_legal_agreement_consent_removal_justification',
5931
            1, //text
5932
            'Request for legal agreement consent removal justification	',
5933
            ''
5934
        );
5935
5936
        self::create_extra_field(
5937
            'request_for_delete_account_justification',
5938
            1, //text
5939
            'Request for delete account justification',
5940
            ''
5941
        );
5942
5943
        $extraFieldId = self::create_extra_field(
5944
            'request_for_legal_agreement_consent_removal',
5945
            1, //text
5946
            'Request for legal agreement consent removal',
5947
            ''
5948
        );
5949
5950
        $extraFieldIdDeleteAccount = self::create_extra_field(
5951
            'request_for_delete_account',
5952
            1, //text
5953
            'Request for delete user account',
5954
            ''
5955
        );
5956
5957
        return [
5958
            'delete_account_extra_field' => $extraFieldIdDeleteAccount,
5959
            'delete_legal' => $extraFieldId,
5960
        ];
5961
    }
5962
5963
    /**
5964
     * @param int $userId
5965
     */
5966
    public static function cleanUserRequestsOfRemoval($userId)
5967
    {
5968
        $userId = (int) $userId;
5969
5970
        $extraFieldValue = new ExtraFieldValue('user');
5971
        $extraFieldsToDelete = [
5972
            'legal_accept',
5973
            'request_for_legal_agreement_consent_removal',
5974
            'request_for_legal_agreement_consent_removal_justification',
5975
            'request_for_delete_account_justification', // just in case delete also this
5976
            'request_for_delete_account',
5977
        ];
5978
5979
        foreach ($extraFieldsToDelete as $variable) {
5980
            $value = $extraFieldValue->get_values_by_handler_and_field_variable(
5981
                $userId,
5982
                $variable
5983
            );
5984
            if ($value && isset($value['id'])) {
5985
                $extraFieldValue->delete($value['id']);
5986
            }
5987
        }
5988
    }
5989
5990
    /**
5991
     * @param int $searchYear
5992
     *
5993
     * @throws Exception
5994
     *
5995
     * @return array
5996
     */
5997
    public static function getSubscribedSessionsByYear(array $userInfo, $searchYear)
5998
    {
5999
        $timezone = new DateTimeZone(api_get_timezone());
6000
6001
        $sessions = [];
6002
        if (DRH == $userInfo['status']) {
6003
            $sessions = SessionManager::get_sessions_followed_by_drh($userInfo['id']);
6004
        } elseif (api_is_platform_admin(true)) {
6005
            $sessions = SessionManager::getSessionsForAdmin($userInfo['id']);
6006
        } else {
6007
            $sessionsByCategory = self::get_sessions_by_category($userInfo['id'], false, true, true);
6008
            $sessionsByCategory = array_column($sessionsByCategory, 'sessions');
6009
6010
            foreach ($sessionsByCategory as $sessionsInCategory) {
6011
                $sessions = array_merge($sessions, $sessionsInCategory);
6012
            }
6013
        }
6014
6015
        $sessions = array_map(
6016
            function ($sessionInfo) {
6017
                if (!isset($sessionInfo['session_id'])) {
6018
                    $sessionInfo['session_id'] = $sessionInfo['id'];
6019
                }
6020
                if (!isset($sessionInfo['session_name'])) {
6021
                    $sessionInfo['session_name'] = $sessionInfo['name'];
6022
                }
6023
6024
                return $sessionInfo;
6025
            },
6026
            $sessions
6027
        );
6028
6029
        $calendarSessions = [];
6030
6031
        foreach ($sessions as $sessionInfo) {
6032
            if (!empty($sessionInfo['duration'])) {
6033
                $courseAccess = CourseManager::getFirstCourseAccessPerSessionAndUser(
6034
                    $sessionInfo['session_id'],
6035
                    $userInfo['id']
6036
                );
6037
6038
                if (empty($courseAccess)) {
6039
                    continue;
6040
                }
6041
6042
                $firstAcessDate = new DateTime(api_get_local_time($courseAccess['login_course_date']), $timezone);
6043
                $lastAccessDate = clone $firstAcessDate;
6044
                $lastAccessDate->modify("+{$sessionInfo['duration']} days");
6045
6046
                $firstAccessYear = (int) $firstAcessDate->format('Y');
6047
                $lastAccessYear = (int) $lastAccessDate->format('Y');
6048
6049
                if ($firstAccessYear <= $searchYear && $lastAccessYear >= $searchYear) {
6050
                    $calendarSessions[$sessionInfo['session_id']] = [
6051
                        'name' => $sessionInfo['session_name'],
6052
                        'access_start_date' => $firstAcessDate->format('Y-m-d h:i:s'),
6053
                        'access_end_date' => $lastAccessDate->format('Y-m-d h:i:s'),
6054
                    ];
6055
                }
6056
6057
                continue;
6058
            }
6059
6060
            $accessStartDate = !empty($sessionInfo['access_start_date'])
6061
                ? new DateTime(api_get_local_time($sessionInfo['access_start_date']), $timezone)
6062
                : null;
6063
            $accessEndDate = !empty($sessionInfo['access_end_date'])
6064
                ? new DateTime(api_get_local_time($sessionInfo['access_end_date']), $timezone)
6065
                : null;
6066
            $accessStartYear = $accessStartDate ? (int) $accessStartDate->format('Y') : 0;
6067
            $accessEndYear = $accessEndDate ? (int) $accessEndDate->format('Y') : 0;
6068
6069
            $isValid = false;
6070
6071
            if ($accessStartYear && $accessEndYear) {
6072
                if ($accessStartYear <= $searchYear && $accessEndYear >= $searchYear) {
6073
                    $isValid = true;
6074
                }
6075
            }
6076
6077
            if ($accessStartYear && !$accessEndYear) {
6078
                if ($accessStartYear == $searchYear) {
6079
                    $isValid = true;
6080
                }
6081
            }
6082
6083
            if (!$accessStartYear && $accessEndYear) {
6084
                if ($accessEndYear == $searchYear) {
6085
                    $isValid = true;
6086
                }
6087
            }
6088
6089
            if ($isValid) {
6090
                $calendarSessions[$sessionInfo['session_id']] = [
6091
                    'name' => $sessionInfo['session_name'],
6092
                    'access_start_date' => $accessStartDate ? $accessStartDate->format('Y-m-d h:i:s') : null,
6093
                    'access_end_date' => $accessEndDate ? $accessEndDate->format('Y-m-d h:i:s') : null,
6094
                ];
6095
            }
6096
        }
6097
6098
        return $calendarSessions;
6099
    }
6100
6101
    /**
6102
     * Get sessions info for planification calendar.
6103
     *
6104
     * @param array $sessionsList Session list from UserManager::getSubscribedSessionsByYear
6105
     * @param int   $searchYear
6106
     *
6107
     * @throws Exception
6108
     *
6109
     * @return array
6110
     */
6111
    public static function getSessionsCalendarByYear(array $sessionsList, $searchYear)
6112
    {
6113
        $timezone = new DateTimeZone(api_get_timezone());
6114
        $calendar = [];
6115
6116
        foreach ($sessionsList as $sessionId => $sessionInfo) {
6117
            $startDate = $sessionInfo['access_start_date']
6118
                ? new DateTime(api_get_local_time($sessionInfo['access_start_date']), $timezone)
6119
                : null;
6120
            $endDate = $sessionInfo['access_end_date']
6121
                ? new DateTime(api_get_local_time($sessionInfo['access_end_date']), $timezone)
6122
                : null;
6123
6124
            $startYear = $startDate ? (int) $startDate->format('Y') : 0;
6125
            $startWeekYear = $startDate ? (int) $startDate->format('o') : 0;
6126
            $startWeek = $startDate ? (int) $startDate->format('W') : 0;
6127
            $endYear = $endDate ? (int) $endDate->format('Y') : 0;
6128
            $endWeekYear = $endDate ? (int) $endDate->format('o') : 0;
6129
            $endWeek = $endDate ? (int) $endDate->format('W') : 0;
6130
6131
            $start = $startWeekYear < $searchYear ? 0 : $startWeek - 1;
6132
            $duration = $endWeekYear > $searchYear ? 52 - $start : $endWeek - $start;
6133
6134
            $calendar[] = [
6135
                'id' => $sessionId,
6136
                'name' => $sessionInfo['name'],
6137
                'human_date' => SessionManager::convertSessionDateToString($startDate, $endDate, false, true),
6138
                'start_in_last_year' => $startYear < $searchYear,
6139
                'end_in_next_year' => $endYear > $searchYear,
6140
                'no_start' => !$startWeek,
6141
                'no_end' => !$endWeek,
6142
                'start' => $start,
6143
                'duration' => $duration > 0 ? $duration : 1,
6144
            ];
6145
        }
6146
6147
        usort(
6148
            $calendar,
6149
            function ($sA, $sB) {
6150
                if ($sA['start'] == $sB['start']) {
6151
                    return 0;
6152
                }
6153
6154
                if ($sA['start'] < $sB['start']) {
6155
                    return -1;
6156
                }
6157
6158
                return 1;
6159
            }
6160
        );
6161
6162
        return $calendar;
6163
    }
6164
6165
    /**
6166
     * Return the user's full name. Optionally with the username.
6167
     *
6168
     * @param bool $includeUsername Optional. By default username is not included.
6169
     */
6170
    public static function formatUserFullName(User $user, $includeUsername = false): string
6171
    {
6172
        $fullName = api_get_person_name($user->getFirstname(), $user->getLastname());
6173
6174
        if ($includeUsername && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
6175
            $username = $user->getUsername();
6176
6177
            return "$fullName ($username)";
6178
        }
6179
6180
        return $fullName;
6181
    }
6182
6183
    /**
6184
     * @param int $userId
6185
     *
6186
     * @return array
6187
     */
6188
    public static function getUserCareers($userId)
6189
    {
6190
        $table = Database::get_main_table(TABLE_MAIN_USER_CAREER);
6191
        $tableCareer = Database::get_main_table(TABLE_CAREER);
6192
        $userId = (int) $userId;
6193
6194
        $sql = "SELECT c.id, c.name
6195
                FROM $table uc
6196
                INNER JOIN $tableCareer c
6197
                ON uc.career_id = c.id
6198
                WHERE user_id = $userId
6199
                ORDER BY uc.created_at
6200
                ";
6201
        $result = Database::query($sql);
6202
6203
        return Database::store_result($result, 'ASSOC');
6204
    }
6205
6206
    /**
6207
     * @param int $userId
6208
     * @param int $careerId
6209
     */
6210
    public static function addUserCareer($userId, $careerId)
6211
    {
6212
        if (!api_get_configuration_value('allow_career_users')) {
6213
            return false;
6214
        }
6215
6216
        if (false === self::userHasCareer($userId, $careerId)) {
6217
            $params = ['user_id' => $userId, 'career_id' => $careerId, 'created_at' => api_get_utc_datetime(), 'updated_at' => api_get_utc_datetime()];
6218
            $table = Database::get_main_table(TABLE_MAIN_USER_CAREER);
6219
            Database::insert($table, $params);
6220
        }
6221
6222
        return true;
6223
    }
6224
6225
    /**
6226
     * @param int   $userCareerId
6227
     * @param array $data
6228
     *
6229
     * @return bool
6230
     */
6231
    public static function updateUserCareer($userCareerId, $data)
6232
    {
6233
        if (!api_get_configuration_value('allow_career_users')) {
6234
            return false;
6235
        }
6236
6237
        $params = ['extra_data' => $data, 'updated_at' => api_get_utc_datetime()];
6238
        $table = Database::get_main_table(TABLE_MAIN_USER_CAREER);
6239
        Database::update(
6240
            $table,
6241
            $params,
6242
            ['id = ?' => (int) $userCareerId]
6243
        );
6244
6245
        return true;
6246
    }
6247
6248
    /**
6249
     * @param int $userId
6250
     * @param int $careerId
6251
     *
6252
     * @return array
6253
     */
6254
    public static function getUserCareer($userId, $careerId)
6255
    {
6256
        $userId = (int) $userId;
6257
        $careerId = (int) $careerId;
6258
        $table = Database::get_main_table(TABLE_MAIN_USER_CAREER);
6259
6260
        $sql = "SELECT * FROM $table WHERE user_id = $userId AND career_id = $careerId";
6261
        $result = Database::query($sql);
6262
6263
        return Database::fetch_array($result, 'ASSOC');
6264
    }
6265
6266
    /**
6267
     * @param int $userId
6268
     * @param int $careerId
6269
     *
6270
     * @return bool
6271
     */
6272
    public static function userHasCareer($userId, $careerId)
6273
    {
6274
        $userId = (int) $userId;
6275
        $careerId = (int) $careerId;
6276
        $table = Database::get_main_table(TABLE_MAIN_USER_CAREER);
6277
6278
        $sql = "SELECT id FROM $table WHERE user_id = $userId AND career_id = $careerId";
6279
        $result = Database::query($sql);
6280
6281
        return Database::num_rows($result) > 0;
6282
    }
6283
6284
    /**
6285
     * @return EncoderFactory
6286
     */
6287
    private static function getEncoderFactory()
6288
    {
6289
        $encryption = self::getPasswordEncryption();
6290
        $encoders = [
6291
            'Chamilo\\CoreBundle\\Entity\\User' => new \Chamilo\CoreBundle\Security\Encoder($encryption),
6292
        ];
6293
6294
        $encoderFactory = new \Symfony\Component\Security\Core\Encoder\EncoderFactory($encoders);
6295
6296
        return $encoderFactory;
6297
    }
6298
6299
    /**
6300
     * @return \Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface
6301
     */
6302
    private static function getEncoder(User $user)
6303
    {
6304
        $encoderFactory = self::getEncoderFactory();
6305
6306
        return $encoderFactory->getEncoder($user);
6307
    }
6308
6309
    /**
6310
     * Disables or enables a user.
6311
     *
6312
     * @param int $user_id
6313
     * @param int $active  Enable or disable
6314
     *
6315
     * @return bool True on success, false on failure
6316
     * @assert (-1,0) === false
6317
     * @assert (1,1) === true
6318
     */
6319
    private static function change_active_state($user_id, $active)
6320
    {
6321
        $user_id = (int) $user_id;
6322
        $active = (int) $active;
6323
6324
        if (empty($user_id)) {
6325
            return false;
6326
        }
6327
6328
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
6329
        $sql = "UPDATE $table_user SET active = '$active' WHERE id = $user_id";
6330
        $r = Database::query($sql);
6331
        $ev = LOG_USER_DISABLE;
6332
        if (1 == $active) {
6333
            $ev = LOG_USER_ENABLE;
6334
        }
6335
        if (false !== $r) {
6336
            Event::addEvent($ev, LOG_USER_ID, $user_id);
6337
        }
6338
6339
        return $r;
6340
    }
6341
6342
    /**
6343
     * Get either a Gravatar URL or complete image tag for a specified email address.
6344
     *
6345
     * @param string $email The email address
6346
     * @param int    $s     Size in pixels, defaults to 80px [ 1 - 2048 ]
6347
     * @param string $d     Default imageset to use [ 404 | mm | identicon | monsterid | wavatar ]
6348
     * @param string $r     Maximum rating (inclusive) [ g | pg | r | x ]
6349
     * @param bool   $img   True to return a complete IMG tag False for just the URL
6350
     * @param array  $atts  Optional, additional key/value attributes to include in the IMG tag
6351
     *
6352
     * @return string containing either just a URL or a complete image tag
6353
     * @source http://gravatar.com/site/implement/images/php/
6354
     */
6355
    private static function getGravatar(
6356
        $email,
6357
        $s = 80,
6358
        $d = 'mm',
6359
        $r = 'g',
6360
        $img = false,
6361
        $atts = []
6362
    ) {
6363
        $url = 'http://www.gravatar.com/avatar/';
6364
        if (!empty($_SERVER['HTTPS'])) {
6365
            $url = 'https://secure.gravatar.com/avatar/';
6366
        }
6367
        $url .= md5(strtolower(trim($email)));
6368
        $url .= "?s=$s&d=$d&r=$r";
6369
        if ($img) {
6370
            $url = '<img src="'.$url.'"';
6371
            foreach ($atts as $key => $val) {
6372
                $url .= ' '.$key.'="'.$val.'"';
6373
            }
6374
            $url .= ' />';
6375
        }
6376
6377
        return $url;
6378
    }
6379
}
6380