Passed
Push — master ( ad5dd8...3078de )
by Julito
08:55
created

UserManager::update_user_picture()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 7
nc 3
nop 3
dl 0
loc 11
rs 10
c 0
b 0
f 0
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Entity\ExtraField as EntityExtraField;
5
use Chamilo\CoreBundle\Entity\ExtraFieldSavedSearch;
6
use Chamilo\CoreBundle\Entity\ResourceNode;
7
use Chamilo\CoreBundle\Entity\SkillRelUser;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, SkillRelUser. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

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

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

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

Loading history...
451
                            $url = $urlInfo['url'];
452
                        }
453
                    }
454
                }
455
456
                $tplContent = new Template(
457
                    null,
458
                    false,
459
                    false,
460
                    false,
461
                    false,
462
                    false
463
                );
464
                // variables for the default template
465
                $tplContent->assign('complete_name', stripslashes(api_get_person_name($firstName, $lastName)));
466
                $tplContent->assign('login_name', $loginName);
467
                $tplContent->assign('original_password', stripslashes($original_password));
468
                $tplContent->assign('mailWebPath', $url);
469
                $tplContent->assign('new_user', $user);
470
471
                $layoutContent = $tplContent->get_template('mail/content_registration_platform.tpl');
472
                $emailBody = $tplContent->fetch($layoutContent);
473
474
                $userInfo = api_get_user_info($userId);
475
                $mailTemplateManager = new MailTemplateManager();
476
477
                $phoneNumber = isset($extra['mobile_phone_number']) ? $extra['mobile_phone_number'] : null;
478
479
                $additionalParameters = [
480
                    'smsType' => SmsPlugin::WELCOME_LOGIN_PASSWORD,
481
                    'userId' => $userId,
482
                    'mobilePhoneNumber' => $phoneNumber,
483
                    'password' => $original_password,
484
                ];
485
486
                $emailBodyTemplate = '';
487
                if (!empty($emailTemplate)) {
488
                    if (isset($emailTemplate['content_registration_platform.tpl']) &&
489
                        !empty($emailTemplate['content_registration_platform.tpl'])
490
                    ) {
491
                        $emailBodyTemplate = $mailTemplateManager->parseTemplate(
492
                            $emailTemplate['content_registration_platform.tpl'],
493
                            $userInfo
494
                        );
495
                    }
496
                }
497
498
                $twoEmail = api_get_configuration_value('send_two_inscription_confirmation_mail');
499
                if (true === $twoEmail) {
500
                    $layoutContent = $tplContent->get_template('mail/new_user_first_email_confirmation.tpl');
501
                    $emailBody = $tplContent->fetch($layoutContent);
502
503
                    if (!empty($emailBodyTemplate) &&
504
                        isset($emailTemplate['new_user_first_email_confirmation.tpl']) &&
505
                        !empty($emailTemplate['new_user_first_email_confirmation.tpl'])
506
                    ) {
507
                        $emailBody = $mailTemplateManager->parseTemplate(
508
                            $emailTemplate['new_user_first_email_confirmation.tpl'],
509
                            $userInfo
510
                        );
511
                    }
512
513
                    api_mail_html(
514
                        $recipient_name,
515
                        $email,
516
                        $emailSubject,
517
                        $emailBody,
518
                        $sender_name,
519
                        $email_admin,
520
                        null,
521
                        null,
522
                        null,
523
                        $additionalParameters,
524
                        $creatorEmail
525
                    );
526
527
                    $layoutContent = $tplContent->get_template('mail/new_user_second_email_confirmation.tpl');
528
                    $emailBody = $tplContent->fetch($layoutContent);
529
530
                    if (!empty($emailBodyTemplate) &&
531
                        isset($emailTemplate['new_user_second_email_confirmation.tpl']) &&
532
                        !empty($emailTemplate['new_user_second_email_confirmation.tpl'])
533
                    ) {
534
                        $emailBody = $mailTemplateManager->parseTemplate(
535
                            $emailTemplate['new_user_second_email_confirmation.tpl'],
536
                            $userInfo
537
                        );
538
                    }
539
540
                    api_mail_html(
541
                        $recipient_name,
542
                        $email,
543
                        $emailSubject,
544
                        $emailBody,
545
                        $sender_name,
546
                        $email_admin,
547
                        null,
548
                        null,
549
                        null,
550
                        $additionalParameters,
551
                        $creatorEmail
552
                    );
553
                } else {
554
                    if (!empty($emailBodyTemplate)) {
555
                        $emailBody = $emailBodyTemplate;
556
                    }
557
                    $sendToInbox = api_get_configuration_value('send_inscription_msg_to_inbox');
558
                    if ($sendToInbox) {
559
                        $adminList = self::get_all_administrators();
560
                        $senderId = 1;
561
                        if (!empty($adminList)) {
562
                            $adminInfo = current($adminList);
563
                            $senderId = $adminInfo['user_id'];
564
                        }
565
566
                        MessageManager::send_message_simple(
567
                            $userId,
568
                            $emailSubject,
569
                            $emailBody,
570
                            $senderId
571
                        );
572
                    } else {
573
                        api_mail_html(
574
                            $recipient_name,
575
                            $email,
576
                            $emailSubject,
577
                            $emailBody,
578
                            $sender_name,
579
                            $email_admin,
580
                            null,
581
                            null,
582
                            null,
583
                            $additionalParameters,
584
                            $creatorEmail
585
                        );
586
                    }
587
                }
588
589
                $notification = api_get_configuration_value('send_notification_when_user_added');
590
                if (!empty($notification) && isset($notification['admins']) && is_array($notification['admins'])) {
591
                    foreach ($notification['admins'] as $adminId) {
592
                        $emailSubjectToAdmin = get_lang('The user has been added').': '.api_get_person_name($firstName, $lastName);
593
                        MessageManager::send_message_simple($adminId, $emailSubjectToAdmin, $emailBody, $userId);
594
                    }
595
                }
596
597
                if ($sendEmailToAllAdmins) {
598
                    $adminList = self::get_all_administrators();
599
600
                    $tplContent = new Template(
601
                        null,
602
                        false,
603
                        false,
604
                        false,
605
                        false,
606
                        false
607
                    );
608
                    // variables for the default template
609
                    $tplContent->assign('complete_name', stripslashes(api_get_person_name($firstName, $lastName)));
610
                    $tplContent->assign('user_added', $user);
611
                    $renderer = FormValidator::getDefaultRenderer();
612
                    // Form template
613
                    $elementTemplate = ' {label}: {element} <br />';
614
                    $renderer->setElementTemplate($elementTemplate);
615
                    /** @var FormValidator $form */
616
                    $form->freeze(null, $elementTemplate);
617
                    $form->removeElement('submit');
618
                    $formData = $form->returnForm();
619
                    $url = api_get_path(WEB_CODE_PATH).'admin/user_information.php?user_id='.$user->getId();
620
                    $tplContent->assign('link', Display::url($url, $url));
621
                    $tplContent->assign('form', $formData);
622
623
                    $layoutContent = $tplContent->get_template('mail/content_registration_platform_to_admin.tpl');
624
                    $emailBody = $tplContent->fetch($layoutContent);
625
626
                    if (!empty($emailBodyTemplate) &&
627
                        isset($emailTemplate['content_registration_platform_to_admin.tpl']) &&
628
                        !empty($emailTemplate['content_registration_platform_to_admin.tpl'])
629
                    ) {
630
                        $emailBody = $mailTemplateManager->parseTemplate(
631
                            $emailTemplate['content_registration_platform_to_admin.tpl'],
632
                            $userInfo
633
                        );
634
                    }
635
636
                    $subject = get_lang('The user has been added');
637
638
                    foreach ($adminList as $adminId => $data) {
639
                        MessageManager::send_message_simple(
640
                            $adminId,
641
                            $subject,
642
                            $emailBody,
643
                            $userId
644
                        );
645
                    }
646
                }
647
                /* ENDS MANAGE EVENT WITH MAIL */
648
            }
649
            Event::addEvent(LOG_USER_CREATE, LOG_USER_ID, $userId, null, $creatorId);
0 ignored issues
show
Bug introduced by
The method addEvent() does not exist on Event. ( Ignorable by Annotation )

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

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

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

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

Loading history...
650
        } else {
651
            Display::addFlash(
652
                Display::return_message(get_lang('There happened an unknown error. Please contact the platform administrator.'))
653
            );
654
655
            return false;
656
        }
657
658
        return $userId;
659
    }
660
661
    /**
662
     * Can user be deleted? This function checks whether there's a course
663
     * in which the given user is the
664
     * only course administrator. If that is the case, the user can't be
665
     * deleted because the course would remain without a course admin.
666
     *
667
     * @param int $user_id The user id
668
     *
669
     * @return bool true if user can be deleted
670
     *
671
     * @assert (null) === false
672
     * @assert (-1) === false
673
     * @assert ('abc') === false
674
     */
675
    public static function canDeleteUser($user_id)
676
    {
677
        $deny = api_get_configuration_value('deny_delete_users');
678
679
        if ($deny) {
680
            return false;
681
        }
682
683
        $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
684
        $user_id = (int) $user_id;
685
686
        if (empty($user_id)) {
687
            return false;
688
        }
689
690
        $sql = "SELECT * FROM $table_course_user
691
                WHERE status = 1 AND user_id = ".$user_id;
692
        $res = Database::query($sql);
693
        while ($course = Database::fetch_object($res)) {
694
            $sql = "SELECT id FROM $table_course_user
695
                    WHERE status=1 AND c_id = ".intval($course->c_id);
696
            $res2 = Database::query($sql);
697
            if (1 == Database::num_rows($res2)) {
698
                return false;
699
            }
700
        }
701
702
        return true;
703
    }
704
705
    /**
706
     * Delete a user from the platform, and all its belongings. This is a
707
     * very dangerous function that should only be accessible by
708
     * super-admins. Other roles should only be able to disable a user,
709
     * which removes access to the platform but doesn't delete anything.
710
     *
711
     * @param int The ID of th user to be deleted
712
     *
713
     * @throws Exception
714
     *
715
     * @return bool true if user is successfully deleted, false otherwise
716
     * @assert (null) === false
717
     * @assert ('abc') === false
718
     */
719
    public static function delete_user($user_id)
720
    {
721
        $user_id = (int) $user_id;
722
723
        if (empty($user_id)) {
724
            return false;
725
        }
726
727
        if (!self::canDeleteUser($user_id)) {
728
            return false;
729
        }
730
731
        $usergroup_rel_user = Database::get_main_table(TABLE_USERGROUP_REL_USER);
732
        $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
733
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
734
        $table_session = Database::get_main_table(TABLE_MAIN_SESSION);
735
        $table_admin = Database::get_main_table(TABLE_MAIN_ADMIN);
736
        $table_session_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
737
        $table_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
738
        $table_group = Database::get_course_table(TABLE_GROUP_USER);
739
        $table_work = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
740
741
        $userInfo = api_get_user_info($user_id);
742
        $repository = Container::getUserRepository();
743
744
        /** @var User $user */
745
        $user = $repository->find($user_id);
746
747
        $repository->deleteUser($user);
748
749
        // Unsubscribe the user from all groups in all his courses
750
        $sql = "SELECT c.id
751
                FROM $table_course c
752
                INNER JOIN $table_course_user cu
753
                ON (c.id = cu.c_id)
754
                WHERE
755
                    cu.user_id = '".$user_id."' AND
756
                    relation_type<>".COURSE_RELATION_TYPE_RRHH."
757
                ";
758
759
        $res = Database::query($sql);
760
        while ($course = Database::fetch_object($res)) {
761
            $sql = "DELETE FROM $table_group
762
                    WHERE c_id = {$course->id} AND user_id = $user_id";
763
            Database::query($sql);
764
        }
765
766
        // Unsubscribe user from usergroup_rel_user
767
        $sql = "DELETE FROM $usergroup_rel_user WHERE user_id = '".$user_id."'";
768
        Database::query($sql);
769
770
        // Unsubscribe user from all courses
771
        $sql = "DELETE FROM $table_course_user WHERE user_id = '".$user_id."'";
772
        Database::query($sql);
773
774
        // Unsubscribe user from all courses in sessions
775
        $sql = "DELETE FROM $table_session_course_user WHERE user_id = '".$user_id."'";
776
        Database::query($sql);
777
778
        // If the user was added as a id_coach then set the current admin as coach see BT#
779
        $currentUserId = api_get_user_id();
780
        $sql = "UPDATE $table_session SET id_coach = $currentUserId
781
                WHERE id_coach = '".$user_id."'";
782
        Database::query($sql);
783
784
        $sql = "UPDATE $table_session SET id_coach = $currentUserId
785
                WHERE session_admin_id = '".$user_id."'";
786
        Database::query($sql);
787
788
        // Unsubscribe user from all sessions
789
        $sql = "DELETE FROM $table_session_user
790
                WHERE user_id = '".$user_id."'";
791
        Database::query($sql);
792
793
        if (api_get_configuration_value('plugin_redirection_enabled')) {
794
            RedirectionPlugin::deleteUserRedirection($user_id);
795
        }
796
797
        // Delete the personal course categories
798
        $course_cat_table = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
799
        $sql = "DELETE FROM $course_cat_table WHERE user_id = '".$user_id."'";
800
        Database::query($sql);
801
802
        // Delete user from the admin table
803
        $sql = "DELETE FROM $table_admin WHERE user_id = '".$user_id."'";
804
        Database::query($sql);
805
806
        // Delete the personal agenda-items from this user
807
        $agenda_table = Database::get_main_table(TABLE_PERSONAL_AGENDA);
808
        $sql = "DELETE FROM $agenda_table WHERE user = '".$user_id."'";
809
        Database::query($sql);
810
811
        $gradebook_results_table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_RESULT);
812
        $sql = 'DELETE FROM '.$gradebook_results_table.' WHERE user_id = '.$user_id;
813
        Database::query($sql);
814
815
        $extraFieldValue = new ExtraFieldValue('user');
816
        $extraFieldValue->deleteValuesByItem($user_id);
817
818
        UrlManager::deleteUserFromAllUrls($user_id);
819
        //UrlManager::deleteUserFromAllUrls($user_id);
820
821
        if ('true' === api_get_setting('allow_social_tool')) {
822
            $userGroup = new UserGroup();
823
            //Delete user from portal groups
824
            $group_list = $userGroup->get_groups_by_user($user_id);
825
            if (!empty($group_list)) {
826
                foreach ($group_list as $group_id => $data) {
827
                    $userGroup->delete_user_rel_group($user_id, $group_id);
828
                }
829
            }
830
831
            // Delete user from friend lists
832
            SocialManager::remove_user_rel_user($user_id, true);
833
        }
834
835
        // Removing survey invitation
836
        SurveyManager::delete_all_survey_invitations_by_user($user_id);
837
838
        // Delete students works
839
        $sql = "DELETE FROM $table_work WHERE user_id = $user_id AND c_id <> 0";
840
        Database::query($sql);
841
842
        /*$sql = "UPDATE c_item_property SET to_user_id = NULL
843
                WHERE to_user_id = '".$user_id."'";
844
        Database::query($sql);
845
846
        $sql = "UPDATE c_item_property SET insert_user_id = NULL
847
                WHERE insert_user_id = '".$user_id."'";
848
        Database::query($sql);
849
850
        $sql = "UPDATE c_item_property SET lastedit_user_id = NULL
851
                WHERE lastedit_user_id = '".$user_id."'";
852
        Database::query($sql);*/
853
854
        // Skills
855
        $em = Database::getManager();
856
857
        $criteria = ['user' => $user_id];
858
        $skills = $em->getRepository(SkillRelUser::class)->findBy($criteria);
859
        if ($skills) {
860
            /** @var SkillRelUser $skill */
861
            foreach ($skills as $skill) {
862
                $comments = $skill->getComments();
863
                if ($comments) {
864
                    /** @var SkillRelUserComment $comment */
865
                    foreach ($comments as $comment) {
866
                        $em->remove($comment);
867
                    }
868
                }
869
                $em->remove($skill);
870
            }
871
        }
872
873
        // ExtraFieldSavedSearch
874
        $criteria = ['user' => $user_id];
875
        $searchList = $em->getRepository(ExtraFieldSavedSearch::class)->findBy($criteria);
876
        if ($searchList) {
877
            foreach ($searchList as $search) {
878
                $em->remove($search);
879
            }
880
        }
881
882
        $connection = Database::getManager()->getConnection();
883
        $tableExists = $connection->getSchemaManager()->tablesExist(['plugin_bbb_room']);
884
        if ($tableExists) {
885
            // Delete user from database
886
            $sql = "DELETE FROM plugin_bbb_room WHERE participant_id = $user_id";
887
            Database::query($sql);
888
        }
889
890
        // Delete user/ticket relationships :(
891
        $tableExists = $connection->getSchemaManager()->tablesExist(['ticket_ticket']);
892
        if ($tableExists) {
893
            TicketManager::deleteUserFromTicketSystem($user_id);
894
        }
895
896
        $tableExists = $connection->getSchemaManager()->tablesExist(['c_lp_category_user']);
897
        if ($tableExists) {
898
            $sql = "DELETE FROM c_lp_category_user WHERE user_id = $user_id";
899
            Database::query($sql);
900
        }
901
902
        $app_plugin = new AppPlugin();
903
        $app_plugin->performActionsWhenDeletingItem('user', $user_id);
904
905
        // Add event to system log
906
        $authorId = api_get_user_id();
907
908
        Event::addEvent(
909
            LOG_USER_DELETE,
910
            LOG_USER_ID,
911
            $user_id,
912
            api_get_utc_datetime(),
913
            $authorId
914
        );
915
916
        Event::addEvent(
917
            LOG_USER_DELETE,
918
            LOG_USER_OBJECT,
919
            $userInfo,
920
            api_get_utc_datetime(),
921
            $authorId
922
        );
923
924
        return true;
925
    }
926
927
    /**
928
     * Deletes users completely. Can be called either as:
929
     * - UserManager::delete_users(1, 2, 3); or
930
     * - UserManager::delete_users(array(1, 2, 3));.
931
     *
932
     * @param array|int $ids
933
     *
934
     * @return bool True if at least one user was successfuly deleted. False otherwise.
935
     *
936
     * @author Laurent Opprecht
937
     *
938
     * @uses \UserManager::delete_user() to actually delete each user
939
     * @assert (null) === false
940
     * @assert (-1) === false
941
     * @assert (array(-1)) === false
942
     */
943
    public static function delete_users($ids = [])
944
    {
945
        $result = false;
946
        $ids = is_array($ids) ? $ids : func_get_args();
947
        if (!is_array($ids) || 0 == count($ids)) {
948
            return false;
949
        }
950
        $ids = array_map('intval', $ids);
951
        foreach ($ids as $id) {
952
            if (empty($id) || $id < 1) {
953
                continue;
954
            }
955
            $deleted = self::delete_user($id);
956
            $result = $deleted || $result;
957
        }
958
959
        return $result;
960
    }
961
962
    /**
963
     * Disable users. Can be called either as:
964
     * - UserManager::deactivate_users(1, 2, 3);
965
     * - UserManager::deactivate_users(array(1, 2, 3));.
966
     *
967
     * @param array|int $ids
968
     *
969
     * @return bool
970
     *
971
     * @author Laurent Opprecht
972
     * @assert (null) === false
973
     * @assert (array(-1)) === false
974
     */
975
    public static function deactivate_users($ids = [])
976
    {
977
        if (empty($ids)) {
978
            return false;
979
        }
980
981
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
982
983
        $ids = is_array($ids) ? $ids : func_get_args();
984
        $ids = array_map('intval', $ids);
985
        $ids = implode(',', $ids);
986
987
        $sql = "UPDATE $table_user SET active = 0 WHERE id IN ($ids)";
988
        $r = Database::query($sql);
989
        if (false !== $r) {
990
            Event::addEvent(LOG_USER_DISABLE, LOG_USER_ID, $ids);
991
992
            return true;
993
        }
994
995
        return false;
996
    }
997
998
    /**
999
     * Enable users. Can be called either as:
1000
     * - UserManager::activate_users(1, 2, 3);
1001
     * - UserManager::activate_users(array(1, 2, 3));.
1002
     *
1003
     * @param array|int IDs of the users to enable
1004
     *
1005
     * @return bool
1006
     *
1007
     * @author Laurent Opprecht
1008
     * @assert (null) === false
1009
     * @assert (array(-1)) === false
1010
     */
1011
    public static function activate_users($ids = [])
1012
    {
1013
        if (empty($ids)) {
1014
            return false;
1015
        }
1016
1017
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
1018
1019
        $ids = is_array($ids) ? $ids : func_get_args();
1020
        $ids = array_map('intval', $ids);
1021
        $ids = implode(',', $ids);
1022
1023
        $sql = "UPDATE $table_user SET active = 1 WHERE id IN ($ids)";
1024
        $r = Database::query($sql);
1025
        if (false !== $r) {
1026
            Event::addEvent(LOG_USER_ENABLE, LOG_USER_ID, $ids);
1027
1028
            return true;
1029
        }
1030
1031
        return false;
1032
    }
1033
1034
    /**
1035
     * Update user information with all the parameters passed to this function.
1036
     *
1037
     * @param int    $user_id         The ID of the user to be updated
1038
     * @param string $firstname       The user's firstname
1039
     * @param string $lastname        The user's lastname
1040
     * @param string $username        The user's username (login)
1041
     * @param string $password        The user's password
1042
     * @param string $auth_source     The authentication source (default: "platform")
1043
     * @param string $email           The user's e-mail address
1044
     * @param int    $status          The user's status
1045
     * @param string $official_code   The user's official code (usually just an internal institutional code)
1046
     * @param string $phone           The user's phone number
1047
     * @param string $picture_uri     The user's picture URL (internal to the Chamilo directory)
1048
     * @param string $expiration_date The date at which this user will be automatically disabled
1049
     * @param int    $active          Whether this account needs to be enabled (1) or disabled (0)
1050
     * @param int    $creator_id      The user ID of the person who registered this user (optional, defaults to null)
1051
     * @param int    $hr_dept_id      The department of HR in which the user is registered (optional, defaults to 0)
1052
     * @param array  $extra           Additional fields to add to this user as extra fields (defaults to null)
1053
     * @param string $language        The language to which the user account will be set
1054
     * @param string $encrypt_method  The cipher method. This parameter is deprecated. It will use the system's default
1055
     * @param bool   $send_email      Whether to send an e-mail to the user after the update is complete
1056
     * @param int    $reset_password  Method used to reset password (0, 1, 2 or 3 - see usage examples for details)
1057
     * @param string $address
1058
     * @param array  $emailTemplate
1059
     *
1060
     * @return bool|int False on error, or the user ID if the user information was updated
1061
     * @assert (false, false, false, false, false, false, false, false, false, false, false, false, false) === false
1062
     */
1063
    public static function update_user(
1064
        $user_id,
1065
        $firstname,
1066
        $lastname,
1067
        $username,
1068
        $password = null,
1069
        $auth_source = null,
1070
        $email,
1071
        $status,
1072
        $official_code,
1073
        $phone,
1074
        $picture_uri,
1075
        $expiration_date,
1076
        $active,
1077
        $creator_id = null,
1078
        $hr_dept_id = 0,
1079
        $extra = null,
1080
        $language = 'english',
1081
        $encrypt_method = '',
1082
        $send_email = false,
1083
        $reset_password = 0,
1084
        $address = null,
1085
        $emailTemplate = []
1086
    ) {
1087
        $original_password = $password;
1088
        $user_id = (int) $user_id;
1089
        $creator_id = (int) $creator_id;
1090
1091
        if (empty($user_id)) {
1092
            return false;
1093
        }
1094
1095
        $userManager = self::getManager();
1096
        $user = api_get_user_entity($user_id);
1097
1098
        if (empty($user)) {
1099
            return false;
1100
        }
1101
1102
        if (0 == $reset_password) {
1103
            $password = null;
1104
            $auth_source = $user->getAuthSource();
1105
        } elseif (1 == $reset_password) {
1106
            $original_password = $password = api_generate_password();
1107
            $auth_source = PLATFORM_AUTH_SOURCE;
1108
        } elseif (2 == $reset_password) {
1109
            $password = $password;
1110
            $auth_source = PLATFORM_AUTH_SOURCE;
1111
        } elseif (3 == $reset_password) {
1112
            $password = $password;
1113
            $auth_source = $auth_source;
1114
        }
1115
1116
        // Checking the user language
1117
        $languages = array_keys(api_get_languages());
1118
        if (!in_array($language, $languages)) {
1119
            $language = api_get_setting('platformLanguage');
1120
        }
1121
1122
        $change_active = 0;
1123
        $isUserActive = $user->getActive();
1124
        if ($isUserActive != $active) {
1125
            $change_active = 1;
1126
        }
1127
1128
        $originalUsername = $user->getUsername();
1129
1130
        // If username is different from original then check if it exists.
1131
        if ($originalUsername !== $username) {
1132
            $available = self::is_username_available($username);
1133
            if (false === $available) {
1134
                return false;
1135
            }
1136
        }
1137
1138
        if (!empty($expiration_date)) {
1139
            $expiration_date = api_get_utc_datetime($expiration_date);
1140
            $expiration_date = new \DateTime(
1141
                $expiration_date,
1142
                new DateTimeZone('UTC')
1143
            );
1144
        }
1145
1146
        $user
1147
            ->setLastname($lastname)
1148
            ->setFirstname($firstname)
1149
            ->setUsername($username)
1150
            ->setStatus($status)
1151
            ->setAuthSource($auth_source)
1152
            ->setLanguage($language)
1153
            ->setLocale($language)
1154
            ->setEmail($email)
1155
            ->setOfficialCode($official_code)
1156
            ->setPhone($phone)
1157
            ->setAddress($address)
1158
            //->setPictureUri($picture_uri)
1159
            ->setExpirationDate($expiration_date)
1160
            ->setActive($active)
1161
            ->setEnabled($active)
1162
            ->setHrDeptId($hr_dept_id)
1163
        ;
1164
1165
        if (!is_null($password)) {
1166
            $user->setPlainPassword($password);
1167
        }
1168
1169
        $statusToGroup = [
1170
            COURSEMANAGER => 'TEACHER',
1171
            STUDENT => 'STUDENT',
1172
            DRH => 'RRHH',
1173
            SESSIONADMIN => 'SESSION_ADMIN',
1174
            STUDENT_BOSS => 'STUDENT_BOSS',
1175
            INVITEE => 'INVITEE',
1176
        ];
1177
1178
        $group = Container::$container->get(GroupRepository::class)->findOneBy(['code' => $statusToGroup[$status]]);
1179
        if ($group) {
1180
            $user->addGroup($group);
1181
        }
1182
1183
        $userManager->updateUser($user, true);
1184
        Event::addEvent(LOG_USER_UPDATE, LOG_USER_ID, $user_id);
1185
1186
        if (1 == $change_active) {
1187
            if (1 == $active) {
1188
                $event_title = LOG_USER_ENABLE;
1189
            } else {
1190
                $event_title = LOG_USER_DISABLE;
1191
            }
1192
            Event::addEvent($event_title, LOG_USER_ID, $user_id);
1193
        }
1194
1195
        if (is_array($extra) && count($extra) > 0) {
1196
            $res = true;
1197
            foreach ($extra as $fname => $fvalue) {
1198
                $res = $res && self::update_extra_field_value(
1199
                    $user_id,
1200
                    $fname,
1201
                    $fvalue
1202
                );
1203
            }
1204
        }
1205
1206
        if (!empty($email) && $send_email) {
1207
            $recipient_name = api_get_person_name($firstname, $lastname, null, PERSON_NAME_EMAIL_ADDRESS);
1208
            $emailsubject = '['.api_get_setting('siteName').'] '.get_lang('Your registration on').' '.api_get_setting('siteName');
1209
            $sender_name = api_get_person_name(
1210
                api_get_setting('administratorName'),
1211
                api_get_setting('administratorSurname'),
1212
                null,
1213
                PERSON_NAME_EMAIL_ADDRESS
1214
            );
1215
            $email_admin = api_get_setting('emailAdministrator');
1216
            $url = api_get_path(WEB_PATH);
1217
            if (api_is_multiple_url_enabled()) {
1218
                $access_url_id = api_get_current_access_url_id();
1219
                if (-1 != $access_url_id) {
1220
                    $url = api_get_access_url($access_url_id);
1221
                    $url = $url['url'];
1222
                }
1223
            }
1224
1225
            $tplContent = new Template(
1226
                null,
1227
                false,
1228
                false,
1229
                false,
1230
                false,
1231
                false
1232
            );
1233
            // variables for the default template
1234
            $tplContent->assign('complete_name', stripslashes(api_get_person_name($firstname, $lastname)));
1235
            $tplContent->assign('login_name', $username);
1236
1237
            $originalPassword = '';
1238
            if ($reset_password > 0) {
1239
                $originalPassword = stripslashes($original_password);
1240
            }
1241
            $tplContent->assign('original_password', $originalPassword);
1242
            $tplContent->assign('portal_url', $url);
1243
1244
            $layoutContent = $tplContent->get_template('mail/user_edit_content.tpl');
1245
            $emailBody = $tplContent->fetch($layoutContent);
1246
1247
            $mailTemplateManager = new MailTemplateManager();
1248
1249
            if (!empty($emailTemplate) &&
1250
                isset($emailTemplate['user_edit_content.tpl']) &&
1251
                !empty($emailTemplate['user_edit_content.tpl'])
1252
            ) {
1253
                $userInfo = api_get_user_info($user_id);
1254
                $emailBody = $mailTemplateManager->parseTemplate($emailTemplate['user_edit_content.tpl'], $userInfo);
1255
            }
1256
1257
            $creatorInfo = api_get_user_info($creator_id);
1258
            $creatorEmail = isset($creatorInfo['email']) ? $creatorInfo['email'] : '';
1259
1260
            api_mail_html(
1261
                $recipient_name,
1262
                $email,
1263
                $emailsubject,
1264
                $emailBody,
1265
                $sender_name,
1266
                $email_admin,
1267
                null,
1268
                null,
1269
                null,
1270
                null,
1271
                $creatorEmail
1272
            );
1273
        }
1274
1275
        $cacheAvailable = api_get_configuration_value('apc');
1276
        if (true === $cacheAvailable) {
1277
            $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$user_id;
1278
            if (apcu_exists($apcVar)) {
1279
                apcu_delete($apcVar);
1280
            }
1281
        }
1282
1283
        return $user->getId();
1284
    }
1285
1286
    /**
1287
     * Disables a user.
1288
     *
1289
     * @param int User id
1290
     *
1291
     * @return bool
1292
     *
1293
     * @uses \UserManager::change_active_state() to actually disable the user
1294
     * @assert (0) === false
1295
     */
1296
    public static function disable($user_id)
1297
    {
1298
        if (empty($user_id)) {
1299
            return false;
1300
        }
1301
        self::change_active_state($user_id, 0);
1302
1303
        return true;
1304
    }
1305
1306
    /**
1307
     * Enable a user.
1308
     *
1309
     * @param int User id
1310
     *
1311
     * @return bool
1312
     *
1313
     * @uses \UserManager::change_active_state() to actually disable the user
1314
     * @assert (0) === false
1315
     */
1316
    public static function enable($user_id)
1317
    {
1318
        if (empty($user_id)) {
1319
            return false;
1320
        }
1321
        self::change_active_state($user_id, 1);
1322
1323
        return true;
1324
    }
1325
1326
    /**
1327
     * Returns the user's id based on the original id and field name in
1328
     * the extra fields. Returns 0 if no user was found. This function is
1329
     * mostly useful in the context of a web services-based sinchronization.
1330
     *
1331
     * @param string Original user id
1332
     * @param string Original field name
1333
     *
1334
     * @return int User id
1335
     * @assert ('0','---') === 0
1336
     */
1337
    public static function get_user_id_from_original_id(
1338
        $original_user_id_value,
1339
        $original_user_id_name
1340
    ) {
1341
        $t_uf = Database::get_main_table(TABLE_EXTRA_FIELD);
1342
        $t_ufv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1343
        $extraFieldType = EntityExtraField::USER_FIELD_TYPE;
1344
1345
        $original_user_id_name = Database::escape_string($original_user_id_name);
1346
        $original_user_id_value = Database::escape_string($original_user_id_value);
1347
1348
        $sql = "SELECT item_id as user_id
1349
                FROM $t_uf uf
1350
                INNER JOIN $t_ufv ufv
1351
                ON ufv.field_id = uf.id
1352
                WHERE
1353
                    variable = '$original_user_id_name' AND
1354
                    value = '$original_user_id_value' AND
1355
                    extra_field_type = $extraFieldType
1356
                ";
1357
        $res = Database::query($sql);
1358
        $row = Database::fetch_object($res);
1359
        if ($row) {
1360
            return $row->user_id;
1361
        }
1362
1363
        return 0;
1364
    }
1365
1366
    /**
1367
     * Check if a username is available.
1368
     *
1369
     * @param string $username the wanted username
1370
     *
1371
     * @return bool true if the wanted username is available
1372
     * @assert ('') === false
1373
     * @assert ('xyzxyzxyz') === true
1374
     */
1375
    public static function is_username_available($username)
1376
    {
1377
        if (empty($username)) {
1378
            return false;
1379
        }
1380
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
1381
        $sql = "SELECT username FROM $table_user
1382
                WHERE username = '".Database::escape_string($username)."'";
1383
        $res = Database::query($sql);
1384
1385
        return 0 == Database::num_rows($res);
1386
    }
1387
1388
    /**
1389
     * Creates a username using person's names, i.e. creates jmontoya from Julio Montoya.
1390
     *
1391
     * @param string $firstname the first name of the user
1392
     * @param string $lastname  the last name of the user
1393
     *
1394
     * @return string suggests a username that contains only ASCII-letters and digits,
1395
     *                without check for uniqueness within the system
1396
     *
1397
     * @author Julio Montoya Armas
1398
     * @author Ivan Tcholakov, 2009 - rework about internationalization.
1399
     * @assert ('','') === false
1400
     * @assert ('a','b') === 'ab'
1401
     */
1402
    public static function create_username($firstname, $lastname)
1403
    {
1404
        if (empty($firstname) && empty($lastname)) {
1405
            return false;
1406
        }
1407
1408
        // The first letter only.
1409
        $firstname = api_substr(
1410
            preg_replace(USERNAME_PURIFIER, '', $firstname),
1411
            0,
1412
            1
1413
        );
1414
        //Looking for a space in the lastname
1415
        $pos = api_strpos($lastname, ' ');
1416
        if (false !== $pos) {
1417
            $lastname = api_substr($lastname, 0, $pos);
1418
        }
1419
1420
        $lastname = preg_replace(USERNAME_PURIFIER, '', $lastname);
1421
        $username = $firstname.$lastname;
1422
        if (empty($username)) {
1423
            $username = 'user';
1424
        }
1425
1426
        $username = URLify::transliterate($username);
1427
1428
        return strtolower(substr($username, 0, USERNAME_MAX_LENGTH - 3));
1429
    }
1430
1431
    /**
1432
     * Creates a unique username, using:
1433
     * 1. the first name and the last name of a user;
1434
     * 2. an already created username but not checked for uniqueness yet.
1435
     *
1436
     * @param string $firstname The first name of a given user. If the second parameter $lastname is NULL, then this
1437
     *                          parameter is treated as username which is to be checked f
1438
     *                          or uniqueness and to be modified when it is necessary.
1439
     * @param string $lastname  the last name of the user
1440
     *
1441
     * @return string Returns a username that contains only ASCII-letters and digits and that is unique in the system.
1442
     *                Note: When the method is called several times with same parameters,
1443
     *                its results look like the following sequence: ivan, ivan2, ivan3, ivan4, ...
1444
     *
1445
     * @author Ivan Tcholakov, 2009
1446
     */
1447
    public static function create_unique_username($firstname, $lastname = null)
1448
    {
1449
        if (is_null($lastname)) {
1450
            // In this case the actual input parameter $firstname should contain ASCII-letters and digits only.
1451
            // For making this method tolerant of mistakes,
1452
            // let us transliterate and purify the suggested input username anyway.
1453
            // So, instead of the sentence $username = $firstname; we place the following:
1454
            $username = strtolower(preg_replace(USERNAME_PURIFIER, '', $firstname));
1455
        } else {
1456
            $username = self::create_username($firstname, $lastname);
1457
        }
1458
        if (!self::is_username_available($username)) {
1459
            $i = 2;
1460
            $temp_username = substr($username, 0, USERNAME_MAX_LENGTH - strlen((string) $i)).$i;
1461
            while (!self::is_username_available($temp_username)) {
1462
                $i++;
1463
                $temp_username = substr($username, 0, USERNAME_MAX_LENGTH - strlen((string) $i)).$i;
1464
            }
1465
            $username = $temp_username;
1466
        }
1467
1468
        $username = URLify::transliterate($username);
1469
1470
        return $username;
1471
    }
1472
1473
    /**
1474
     * Modifies a given username accordingly to the specification for valid characters and length.
1475
     *
1476
     * @param $username string          The input username
1477
     * @param bool $strict (optional)   When this flag is TRUE, the result is guaranteed for full compliance,
1478
     *                     otherwise compliance may be partial. The default value is FALSE.
1479
     *
1480
     * @return string the resulting purified username
1481
     */
1482
    public static function purify_username($username, $strict = false)
1483
    {
1484
        if ($strict) {
1485
            // 1. Conversion of unacceptable letters (latinian letters with accents for example)
1486
            // into ASCII letters in order they not to be totally removed.
1487
            // 2. Applying the strict purifier.
1488
            // 3. Length limitation.
1489
            $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);
1490
            $return = URLify::transliterate($return);
1491
1492
            return $return;
1493
        }
1494
1495
        // 1. Applying the shallow purifier.
1496
        // 2. Length limitation.
1497
        return substr(
1498
            preg_replace(USERNAME_PURIFIER_SHALLOW, '', $username),
1499
            0,
1500
            USERNAME_MAX_LENGTH
1501
        );
1502
    }
1503
1504
    /**
1505
     * Checks whether the user id exists in the database.
1506
     *
1507
     * @param int $userId User id
1508
     *
1509
     * @return bool True if user id was found, false otherwise
1510
     */
1511
    public static function is_user_id_valid($userId)
1512
    {
1513
        $resultData = Database::select(
1514
            'COUNT(1) AS count',
1515
            Database::get_main_table(TABLE_MAIN_USER),
1516
            [
1517
                'where' => ['id = ?' => (int) $userId],
1518
            ],
1519
            'first'
1520
        );
1521
1522
        if (false === $resultData) {
1523
            return false;
1524
        }
1525
1526
        return $resultData['count'] > 0;
1527
    }
1528
1529
    /**
1530
     * Checks whether a given username matches to the specification strictly.
1531
     * The empty username is assumed here as invalid.
1532
     * Mostly this function is to be used in the user interface built-in validation routines
1533
     * for providing feedback while usernames are enterd manually.
1534
     *
1535
     * @param string $username the input username
1536
     *
1537
     * @return bool returns TRUE if the username is valid, FALSE otherwise
1538
     */
1539
    public static function is_username_valid($username)
1540
    {
1541
        return !empty($username) && $username == self::purify_username($username, true);
1542
    }
1543
1544
    /**
1545
     * Checks whether a username is empty. If the username contains whitespace characters,
1546
     * such as spaces, tabulators, newlines, etc.,
1547
     * it is assumed as empty too. This function is safe for validation unpurified data (during importing).
1548
     *
1549
     * @param string $username the given username
1550
     *
1551
     * @return bool returns TRUE if length of the username exceeds the limit, FALSE otherwise
1552
     */
1553
    public static function is_username_empty($username)
1554
    {
1555
        return 0 == strlen(self::purify_username($username, false));
1556
    }
1557
1558
    /**
1559
     * Checks whether a username is too long or not.
1560
     *
1561
     * @param string $username the given username, it should contain only ASCII-letters and digits
1562
     *
1563
     * @return bool returns TRUE if length of the username exceeds the limit, FALSE otherwise
1564
     */
1565
    public static function is_username_too_long($username)
1566
    {
1567
        return strlen($username) > USERNAME_MAX_LENGTH;
1568
    }
1569
1570
    /**
1571
     * Get the users by ID.
1572
     *
1573
     * @param array  $ids    student ids
1574
     * @param string $active
1575
     * @param string $order
1576
     * @param string $limit
1577
     *
1578
     * @return array $result student information
1579
     */
1580
    public static function get_user_list_by_ids($ids = [], $active = null, $order = null, $limit = null)
1581
    {
1582
        if (empty($ids)) {
1583
            return [];
1584
        }
1585
1586
        $ids = is_array($ids) ? $ids : [$ids];
1587
        $ids = array_map('intval', $ids);
1588
        $ids = implode(',', $ids);
1589
1590
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
1591
        $sql = "SELECT * FROM $tbl_user WHERE id IN ($ids)";
1592
        if (!is_null($active)) {
1593
            $sql .= ' AND active='.($active ? '1' : '0');
1594
        }
1595
1596
        if (!is_null($order)) {
1597
            $order = Database::escape_string($order);
1598
            $sql .= ' ORDER BY '.$order;
1599
        }
1600
1601
        if (!is_null($limit)) {
1602
            $limit = Database::escape_string($limit);
1603
            $sql .= ' LIMIT '.$limit;
1604
        }
1605
1606
        $rs = Database::query($sql);
1607
        $result = [];
1608
        while ($row = Database::fetch_array($rs)) {
1609
            $result[] = $row;
1610
        }
1611
1612
        return $result;
1613
    }
1614
1615
    /**
1616
     * Get a list of users of which the given conditions match with an = 'cond'.
1617
     *
1618
     * @param array $conditions a list of condition (example : status=>STUDENT)
1619
     * @param array $order_by   a list of fields on which sort
1620
     *
1621
     * @return array an array with all users of the platform
1622
     *
1623
     * @todo security filter order by
1624
     */
1625
    public static function get_user_list(
1626
        $conditions = [],
1627
        $order_by = [],
1628
        $limit_from = false,
1629
        $limit_to = false,
1630
        $idCampus = null
1631
    ) {
1632
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
1633
        $userUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1634
        $return_array = [];
1635
        $sql = "SELECT user.*, user.id as user_id FROM $user_table user ";
1636
1637
        if (api_is_multiple_url_enabled()) {
1638
            if ($idCampus) {
1639
                $urlId = $idCampus;
1640
            } else {
1641
                $urlId = api_get_current_access_url_id();
1642
            }
1643
            $sql .= " INNER JOIN $userUrlTable url_user
1644
                      ON (user.id = url_user.user_id)
1645
                      WHERE url_user.access_url_id = $urlId";
1646
        } else {
1647
            $sql .= " WHERE 1=1 ";
1648
        }
1649
1650
        if (count($conditions) > 0) {
1651
            foreach ($conditions as $field => $value) {
1652
                $field = Database::escape_string($field);
1653
                $value = Database::escape_string($value);
1654
                $sql .= " AND $field = '$value'";
1655
            }
1656
        }
1657
1658
        if (count($order_by) > 0) {
1659
            $sql .= ' ORDER BY '.Database::escape_string(implode(',', $order_by));
1660
        }
1661
1662
        if (is_numeric($limit_from) && is_numeric($limit_from)) {
1663
            $limit_from = (int) $limit_from;
1664
            $limit_to = (int) $limit_to;
1665
            $sql .= " LIMIT $limit_from, $limit_to";
1666
        }
1667
        $sql_result = Database::query($sql);
1668
        while ($result = Database::fetch_array($sql_result)) {
1669
            $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1670
            $return_array[] = $result;
1671
        }
1672
1673
        return $return_array;
1674
    }
1675
1676
    public static function getUserListExtraConditions(
1677
        $conditions = [],
1678
        $order_by = [],
1679
        $limit_from = false,
1680
        $limit_to = false,
1681
        $idCampus = null,
1682
        $extraConditions = '',
1683
        $getCount = false
1684
    ) {
1685
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
1686
        $userUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1687
        $return_array = [];
1688
        $sql = "SELECT user.*, user.id as user_id FROM $user_table user ";
1689
1690
        if ($getCount) {
1691
            $sql = "SELECT count(user.id) count FROM $user_table user ";
1692
        }
1693
1694
        if (api_is_multiple_url_enabled()) {
1695
            if ($idCampus) {
1696
                $urlId = $idCampus;
1697
            } else {
1698
                $urlId = api_get_current_access_url_id();
1699
            }
1700
            $sql .= " INNER JOIN $userUrlTable url_user
1701
                      ON (user.user_id = url_user.user_id)
1702
                      WHERE url_user.access_url_id = $urlId";
1703
        } else {
1704
            $sql .= " WHERE 1=1 ";
1705
        }
1706
1707
        $sql .= " AND status <> ".ANONYMOUS." ";
1708
1709
        if (count($conditions) > 0) {
1710
            foreach ($conditions as $field => $value) {
1711
                $field = Database::escape_string($field);
1712
                $value = Database::escape_string($value);
1713
                $sql .= " AND $field = '$value'";
1714
            }
1715
        }
1716
1717
        $sql .= str_replace("\'", "'", Database::escape_string($extraConditions));
1718
1719
        if (!empty($order_by) && count($order_by) > 0) {
1720
            $sql .= ' ORDER BY '.Database::escape_string(implode(',', $order_by));
1721
        }
1722
1723
        if (is_numeric($limit_from) && is_numeric($limit_from)) {
1724
            $limit_from = (int) $limit_from;
1725
            $limit_to = (int) $limit_to;
1726
            $sql .= " LIMIT $limit_from, $limit_to";
1727
        }
1728
1729
        $sql_result = Database::query($sql);
1730
1731
        if ($getCount) {
1732
            $result = Database::fetch_array($sql_result);
1733
1734
            return $result['count'];
1735
        }
1736
1737
        while ($result = Database::fetch_array($sql_result)) {
1738
            $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1739
            $return_array[] = $result;
1740
        }
1741
1742
        return $return_array;
1743
    }
1744
1745
    /**
1746
     * Get a list of users of which the given conditions match with a LIKE '%cond%'.
1747
     *
1748
     * @param array  $conditions       a list of condition (exemple : status=>STUDENT)
1749
     * @param array  $order_by         a list of fields on which sort
1750
     * @param bool   $simple_like      Whether we want a simple LIKE 'abc' or a LIKE '%abc%'
1751
     * @param string $condition        Whether we want the filters to be combined by AND or OR
1752
     * @param array  $onlyThisUserList
1753
     *
1754
     * @return array an array with all users of the platform
1755
     *
1756
     * @todo optional course code parameter, optional sorting parameters...
1757
     * @todo security filter order_by
1758
     */
1759
    public static function getUserListLike(
1760
        $conditions = [],
1761
        $order_by = [],
1762
        $simple_like = false,
1763
        $condition = 'AND',
1764
        $onlyThisUserList = []
1765
    ) {
1766
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
1767
        $tblAccessUrlRelUser = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1768
        $return_array = [];
1769
        $sql_query = "SELECT user.id FROM $user_table user ";
1770
1771
        if (api_is_multiple_url_enabled()) {
1772
            $sql_query .= " INNER JOIN $tblAccessUrlRelUser auru ON auru.user_id = user.id ";
1773
        }
1774
1775
        $sql_query .= ' WHERE 1 = 1 ';
1776
        if (count($conditions) > 0) {
1777
            $temp_conditions = [];
1778
            foreach ($conditions as $field => $value) {
1779
                $field = Database::escape_string($field);
1780
                $value = Database::escape_string($value);
1781
                if ($simple_like) {
1782
                    $temp_conditions[] = $field." LIKE '$value%'";
1783
                } else {
1784
                    $temp_conditions[] = $field.' LIKE \'%'.$value.'%\'';
1785
                }
1786
            }
1787
            if (!empty($temp_conditions)) {
1788
                $sql_query .= ' AND '.implode(' '.$condition.' ', $temp_conditions);
1789
            }
1790
1791
            if (api_is_multiple_url_enabled()) {
1792
                $sql_query .= ' AND auru.access_url_id = '.api_get_current_access_url_id();
1793
            }
1794
        } else {
1795
            if (api_is_multiple_url_enabled()) {
1796
                $sql_query .= ' AND auru.access_url_id = '.api_get_current_access_url_id();
1797
            }
1798
        }
1799
1800
        if (!empty($onlyThisUserList)) {
1801
            $onlyThisUserListToString = implode("','", $onlyThisUserList);
1802
            $sql_query .= " AND user.id IN ('$onlyThisUserListToString') ";
1803
        }
1804
1805
        if (count($order_by) > 0) {
1806
            $sql_query .= ' ORDER BY '.Database::escape_string(implode(',', $order_by));
1807
        }
1808
1809
        $sql_result = Database::query($sql_query);
1810
        while ($result = Database::fetch_array($sql_result)) {
1811
            $userInfo = api_get_user_info($result['id']);
1812
            $return_array[] = $userInfo;
1813
        }
1814
1815
        return $return_array;
1816
    }
1817
1818
    /**
1819
     * Gets the current user image.
1820
     *
1821
     * @param string $userId
1822
     * @param int    $size        it can be USER_IMAGE_SIZE_SMALL,
1823
     *                            USER_IMAGE_SIZE_MEDIUM, USER_IMAGE_SIZE_BIG or  USER_IMAGE_SIZE_ORIGINAL
1824
     * @param bool   $addRandomId
1825
     * @param array  $userInfo    to avoid query the DB
1826
     * @todo add gravatar support
1827
     * @todo replace $userId with User entity
1828
     *
1829
     * @return string
1830
     */
1831
    public static function getUserPicture(
1832
        $userId,
1833
        $size = USER_IMAGE_SIZE_MEDIUM,
1834
        $addRandomId = true,
1835
        $userInfo = []
1836
    ) {
1837
        $user = api_get_user_entity($userId);
1838
        $illustrationRepo = Container::getIllustrationRepository();
1839
1840
        return $illustrationRepo->getIllustrationUrl($user);
1841
1842
        /*
1843
        // Make sure userInfo is defined. Otherwise, define it!
1844
        if (empty($userInfo) || !is_array($userInfo) || 0 == count($userInfo)) {
1845
            if (empty($user_id)) {
1846
                return '';
1847
            } else {
1848
                $userInfo = api_get_user_info($user_id);
1849
            }
1850
        }
1851
1852
        $imageWebPath = self::get_user_picture_path_by_id(
1853
            $user_id,
1854
            'web',
1855
            $userInfo
1856
        );
1857
        $pictureWebFile = $imageWebPath['file'];
1858
        $pictureWebDir = $imageWebPath['dir'];
1859
1860
        $pictureAnonymousSize = '128';
1861
        $gravatarSize = 22;
1862
        $realSizeName = 'small_';
1863
1864
        switch ($size) {
1865
            case USER_IMAGE_SIZE_SMALL:
1866
                $pictureAnonymousSize = '32';
1867
                $realSizeName = 'small_';
1868
                $gravatarSize = 32;
1869
                break;
1870
            case USER_IMAGE_SIZE_MEDIUM:
1871
                $pictureAnonymousSize = '64';
1872
                $realSizeName = 'medium_';
1873
                $gravatarSize = 64;
1874
                break;
1875
            case USER_IMAGE_SIZE_ORIGINAL:
1876
                $pictureAnonymousSize = '128';
1877
                $realSizeName = '';
1878
                $gravatarSize = 128;
1879
                break;
1880
            case USER_IMAGE_SIZE_BIG:
1881
                $pictureAnonymousSize = '128';
1882
                $realSizeName = 'big_';
1883
                $gravatarSize = 128;
1884
                break;
1885
        }
1886
1887
        $gravatarEnabled = api_get_setting('gravatar_enabled');
1888
        $anonymousPath = Display::returnIconPath('unknown.png', $pictureAnonymousSize);
1889
        if ('unknown.jpg' == $pictureWebFile || empty($pictureWebFile)) {
1890
            if ('true' === $gravatarEnabled) {
1891
                $file = self::getGravatar(
1892
                    $imageWebPath['email'],
1893
                    $gravatarSize,
1894
                    api_get_setting('gravatar_type')
1895
                );
1896
1897
                if ($addRandomId) {
1898
                    $file .= '&rand='.uniqid();
1899
                }
1900
1901
                return $file;
1902
            }
1903
1904
            return $anonymousPath;
1905
        }
1906
1907
        if ($addRandomId) {
1908
            $picture .= '?rand='.uniqid();
1909
        }
1910
1911
        return $picture;*/
1912
    }
1913
1914
    /**
1915
     * Creates new user photos in various sizes of a user, or deletes user photos.
1916
     * Note: This method relies on configuration setting from main/inc/conf/profile.conf.php.
1917
     *
1918
     * @param int    $user_id the user internal identification number
1919
     * @param string $file    The common file name for the newly created photos.
1920
     *                        It will be checked and modified for compatibility with the file system.
1921
     *                        If full name is provided, path component is ignored.
1922
     *                        If an empty name is provided, then old user photos are deleted only,
1923
     *
1924
     * @see     UserManager::delete_user_picture() as the prefered way for deletion.
1925
     *
1926
     * @param string $source_file    the full system name of the image from which user photos will be created
1927
     * @param string $cropParameters Optional string that contents "x,y,width,height" of a cropped image format
1928
     *
1929
     * @return bool Returns the resulting common file name of created images which usually should be stored in database.
1930
     *              When deletion is requested returns empty string.
1931
     *              In case of internal error or negative validation returns FALSE.
1932
     */
1933
    public static function update_user_picture($userId, UploadedFile $file, $crop = '')
1934
    {
1935
        if (empty($userId) || empty($file)) {
1936
            return false;
1937
        }
1938
1939
        $repo = Container::getUserRepository();
1940
        $user = $repo->find($userId);
1941
        if ($user) {
1942
            $repoIllustration = Container::getIllustrationRepository();
1943
            $repoIllustration->addIllustration($user, $user, $file, $crop);
1944
        }
1945
1946
    }
1947
1948
    /**
1949
     * Deletes user photos.
1950
     *
1951
     * @param int $userId the user internal identification number
1952
     *
1953
     * @return mixed returns empty string on success, FALSE on error
1954
     */
1955
    public static function deleteUserPicture($userId)
1956
    {
1957
        $repo = Container::getUserRepository();
1958
        $user = $repo->find($userId);
1959
        if ($user) {
1960
            $illustrationRepo = Container::getIllustrationRepository();
1961
            $illustrationRepo->deleteIllustration($user);
1962
        }
1963
    }
1964
1965
    /**
1966
     * Returns an XHTML formatted list of productions for a user, or FALSE if he
1967
     * doesn't have any.
1968
     *
1969
     * If there has been a request to remove a production, the function will return
1970
     * without building the list unless forced to do so by the optional second
1971
     * parameter. This increases performance by avoiding to read through the
1972
     * productions on the filesystem before the removal request has been carried
1973
     * out because they'll have to be re-read afterwards anyway.
1974
     *
1975
     * @param int  $user_id    User id
1976
     * @param bool $force      Optional parameter to force building after a removal request
1977
     * @param bool $showDelete
1978
     *
1979
     * @return string A string containing the XHTML code to display the production list, or FALSE
1980
     */
1981
    public static function build_production_list($user_id, $force = false, $showDelete = false)
1982
    {
1983
        if (!$force && !empty($_POST['remove_production'])) {
1984
            return true; // postpone reading from the filesystem
1985
        }
1986
1987
        $productions = self::get_user_productions($user_id);
1988
1989
        if (empty($productions)) {
1990
            return false;
1991
        }
1992
1993
        $production_dir = self::getUserPathById($user_id, 'web');
0 ignored issues
show
Bug introduced by
The method getUserPathById() does not exist on UserManager. ( Ignorable by Annotation )

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

1993
        /** @scrutinizer ignore-call */ 
1994
        $production_dir = self::getUserPathById($user_id, 'web');

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

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

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

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

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

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

3223
                array_multisort($myCourseList, /** @scrutinizer ignore-type */ SORT_ASC, $list);
Loading history...
3224
            }
3225
        }
3226
3227
        return $myCourseList;
3228
    }
3229
3230
    /**
3231
     * Get user id from a username.
3232
     *
3233
     * @param string $username
3234
     *
3235
     * @return int User ID (or false if not found)
3236
     */
3237
    public static function get_user_id_from_username($username)
3238
    {
3239
        if (empty($username)) {
3240
            return false;
3241
        }
3242
        $username = trim($username);
3243
        $username = Database::escape_string($username);
3244
        $t_user = Database::get_main_table(TABLE_MAIN_USER);
3245
        $sql = "SELECT id FROM $t_user WHERE username = '$username'";
3246
        $res = Database::query($sql);
3247
3248
        if (false === $res) {
3249
            return false;
3250
        }
3251
        if (1 !== Database::num_rows($res)) {
3252
            return false;
3253
        }
3254
        $row = Database::fetch_array($res);
3255
3256
        return $row['id'];
3257
    }
3258
3259
    /**
3260
     * Get the users files upload from his share_folder.
3261
     *
3262
     * @param string $user_id      User ID
3263
     * @param string $course       course directory
3264
     * @param string $resourceType resource type: images, all
3265
     *
3266
     * @return string
3267
     */
3268
    public static function get_user_upload_files_by_course(
3269
        $user_id,
3270
        $course,
3271
        $resourceType = 'all'
3272
    ) {
3273
        $return = '';
3274
        $user_id = (int) $user_id;
3275
3276
        if (!empty($user_id) && !empty($course)) {
3277
            $path = api_get_path(SYS_COURSE_PATH).$course.'/document/shared_folder/sf_user_'.$user_id.'/';
0 ignored issues
show
Bug introduced by
The constant SYS_COURSE_PATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3278
            $web_path = api_get_path(WEB_COURSE_PATH).$course.'/document/shared_folder/sf_user_'.$user_id.'/';
3279
            $file_list = [];
3280
3281
            if (is_dir($path)) {
3282
                $handle = opendir($path);
3283
                while ($file = readdir($handle)) {
3284
                    if ('.' == $file || '..' == $file || '.htaccess' == $file || is_dir($path.$file)) {
3285
                        continue; // skip current/parent directory and .htaccess
3286
                    }
3287
                    $file_list[] = $file;
3288
                }
3289
                if (count($file_list) > 0) {
3290
                    $return = "<h4>$course</h4>";
3291
                    $return .= '<ul class="thumbnails">';
3292
                }
3293
                $extensionList = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'tif'];
3294
                foreach ($file_list as $file) {
3295
                    if ('all' == $resourceType) {
3296
                        $return .= '<li>
3297
                            <a href="'.$web_path.urlencode($file).'" target="_blank">'.htmlentities($file).'</a></li>';
3298
                    } elseif ('images' == $resourceType) {
3299
                        //get extension
3300
                        $ext = explode('.', $file);
3301
                        if (isset($ext[1]) && in_array($ext[1], $extensionList)) {
3302
                            $return .= '<li class="span2">
3303
                                            <a class="thumbnail" href="'.$web_path.urlencode($file).'" target="_blank">
3304
                                                <img src="'.$web_path.urlencode($file).'" >
3305
                                            </a>
3306
                                        </li>';
3307
                        }
3308
                    }
3309
                }
3310
                if (count($file_list) > 0) {
3311
                    $return .= '</ul>';
3312
                }
3313
            }
3314
        }
3315
3316
        return $return;
3317
    }
3318
3319
    /**
3320
     * Gets the API key (or keys) and return them into an array.
3321
     *
3322
     * @param int     Optional user id (defaults to the result of api_get_user_id())
3323
     * @param string $api_service
3324
     *
3325
     * @return mixed Non-indexed array containing the list of API keys for this user, or FALSE on error
3326
     */
3327
    public static function get_api_keys($user_id = null, $api_service = 'dokeos')
3328
    {
3329
        if ($user_id != strval(intval($user_id))) {
3330
            return false;
3331
        }
3332
        if (empty($user_id)) {
3333
            $user_id = api_get_user_id();
3334
        }
3335
        if (false === $user_id) {
3336
            return false;
3337
        }
3338
        $service_name = Database::escape_string($api_service);
3339
        if (false === is_string($service_name)) {
3340
            return false;
3341
        }
3342
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3343
        $sql = "SELECT * FROM $t_api WHERE user_id = $user_id AND api_service='$api_service';";
3344
        $res = Database::query($sql);
3345
        if (false === $res) {
3346
            return false;
3347
        } //error during query
3348
        $num = Database::num_rows($res);
3349
        if (0 == $num) {
3350
            return false;
3351
        }
3352
        $list = [];
3353
        while ($row = Database::fetch_array($res)) {
3354
            $list[$row['id']] = $row['api_key'];
3355
        }
3356
3357
        return $list;
3358
    }
3359
3360
    /**
3361
     * Adds a new API key to the users' account.
3362
     *
3363
     * @param   int     Optional user ID (defaults to the results of api_get_user_id())
3364
     * @param string $api_service
3365
     *
3366
     * @return bool True on success, false on failure
3367
     */
3368
    public static function add_api_key($user_id = null, $api_service = 'dokeos')
3369
    {
3370
        if ($user_id != strval(intval($user_id))) {
3371
            return false;
3372
        }
3373
        if (empty($user_id)) {
3374
            $user_id = api_get_user_id();
3375
        }
3376
        if (false === $user_id) {
3377
            return false;
3378
        }
3379
        $service_name = Database::escape_string($api_service);
3380
        if (false === is_string($service_name)) {
3381
            return false;
3382
        }
3383
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3384
        $md5 = md5((time() + ($user_id * 5)) - rand(10000, 10000)); //generate some kind of random key
3385
        $sql = "INSERT INTO $t_api (user_id, api_key,api_service) VALUES ($user_id,'$md5','$service_name')";
3386
        $res = Database::query($sql);
3387
        if (false === $res) {
3388
            return false;
3389
        } //error during query
3390
        $num = Database::insert_id();
3391
3392
        return 0 == $num ? false : $num;
0 ignored issues
show
Bug Best Practice introduced by
The expression return 0 == $num ? false : $num also could return the type string which is incompatible with the documented return type boolean.
Loading history...
3393
    }
3394
3395
    /**
3396
     * Deletes an API key from the user's account.
3397
     *
3398
     * @param   int     API key's internal ID
3399
     *
3400
     * @return bool True on success, false on failure
3401
     */
3402
    public static function delete_api_key($key_id)
3403
    {
3404
        if ($key_id != strval(intval($key_id))) {
3405
            return false;
3406
        }
3407
        if (false === $key_id) {
3408
            return false;
3409
        }
3410
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3411
        $sql = "SELECT * FROM $t_api WHERE id = ".$key_id;
3412
        $res = Database::query($sql);
3413
        if (false === $res) {
3414
            return false;
3415
        } //error during query
3416
        $num = Database::num_rows($res);
3417
        if (1 !== $num) {
3418
            return false;
3419
        }
3420
        $sql = "DELETE FROM $t_api WHERE id = ".$key_id;
3421
        $res = Database::query($sql);
3422
        if (false === $res) {
3423
            return false;
3424
        } //error during query
3425
3426
        return true;
3427
    }
3428
3429
    /**
3430
     * Regenerate an API key from the user's account.
3431
     *
3432
     * @param   int     user ID (defaults to the results of api_get_user_id())
3433
     * @param   string  API key's internal ID
3434
     *
3435
     * @return int num
3436
     */
3437
    public static function update_api_key($user_id, $api_service)
3438
    {
3439
        if ($user_id != strval(intval($user_id))) {
3440
            return false;
3441
        }
3442
        if (false === $user_id) {
3443
            return false;
3444
        }
3445
        $service_name = Database::escape_string($api_service);
3446
        if (false === is_string($service_name)) {
3447
            return false;
3448
        }
3449
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3450
        $sql = "SELECT id FROM $t_api
3451
                WHERE user_id=".$user_id." AND api_service='".$api_service."'";
3452
        $res = Database::query($sql);
3453
        $num = Database::num_rows($res);
3454
        if (1 == $num) {
3455
            $id_key = Database::fetch_array($res, 'ASSOC');
3456
            self::delete_api_key($id_key['id']);
3457
            $num = self::add_api_key($user_id, $api_service);
3458
        } elseif (0 == $num) {
3459
            $num = self::add_api_key($user_id, $api_service);
3460
        }
3461
3462
        return $num;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $num also could return the type boolean which is incompatible with the documented return type integer.
Loading history...
3463
    }
3464
3465
    /**
3466
     * @param   int     user ID (defaults to the results of api_get_user_id())
3467
     * @param   string    API key's internal ID
3468
     *
3469
     * @return int row ID, or return false if not found
3470
     */
3471
    public static function get_api_key_id($user_id, $api_service)
3472
    {
3473
        if ($user_id != strval(intval($user_id))) {
3474
            return false;
3475
        }
3476
        if (false === $user_id) {
3477
            return false;
3478
        }
3479
        if (empty($api_service)) {
3480
            return false;
3481
        }
3482
        $t_api = Database::get_main_table(TABLE_MAIN_USER_API_KEY);
3483
        $api_service = Database::escape_string($api_service);
3484
        $sql = "SELECT id FROM $t_api
3485
                WHERE user_id=".$user_id." AND api_service='".$api_service."'";
3486
        $res = Database::query($sql);
3487
        if (Database::num_rows($res) < 1) {
3488
            return false;
3489
        }
3490
        $row = Database::fetch_array($res, 'ASSOC');
3491
3492
        return $row['id'];
3493
    }
3494
3495
    /**
3496
     * Checks if a user_id is platform admin.
3497
     *
3498
     * @param   int user ID
3499
     *
3500
     * @return bool True if is admin, false otherwise
3501
     *
3502
     * @see main_api.lib.php::api_is_platform_admin() for a context-based check
3503
     */
3504
    public static function is_admin($user_id)
3505
    {
3506
        $user_id = (int) $user_id;
3507
        if (empty($user_id)) {
3508
            return false;
3509
        }
3510
        $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
3511
        $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
3512
        $res = Database::query($sql);
3513
3514
        return 1 === Database::num_rows($res);
3515
    }
3516
3517
    /**
3518
     * Get the total count of users.
3519
     *
3520
     * @param int $status        Status of users to be counted
3521
     * @param int $access_url_id Access URL ID (optional)
3522
     * @param int $active
3523
     *
3524
     * @return mixed Number of users or false on error
3525
     */
3526
    public static function get_number_of_users($status = 0, $access_url_id = 1, $active = null)
3527
    {
3528
        $t_u = Database::get_main_table(TABLE_MAIN_USER);
3529
        $t_a = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3530
3531
        if (api_is_multiple_url_enabled()) {
3532
            $sql = "SELECT count(u.id)
3533
                    FROM $t_u u
3534
                    INNER JOIN $t_a url_user
3535
                    ON (u.id = url_user.user_id)
3536
                    WHERE url_user.access_url_id = $access_url_id
3537
            ";
3538
        } else {
3539
            $sql = "SELECT count(u.id)
3540
                    FROM $t_u u
3541
                    WHERE 1 = 1 ";
3542
        }
3543
3544
        if (is_int($status) && $status > 0) {
3545
            $status = (int) $status;
3546
            $sql .= " AND u.status = $status ";
3547
        }
3548
3549
        if (null !== $active) {
3550
            $active = (int) $active;
3551
            $sql .= " AND u.active = $active ";
3552
        }
3553
3554
        $res = Database::query($sql);
3555
        if (1 === Database::num_rows($res)) {
3556
            return (int) Database::result($res, 0, 0);
3557
        }
3558
3559
        return false;
3560
    }
3561
3562
    /**
3563
     * Gets the tags of a specific field_id
3564
     * USER TAGS.
3565
     *
3566
     * Instructions to create a new user tag by Julio Montoya <[email protected]>
3567
     *
3568
     * 1. Create a new extra field in main/admin/user_fields.php with the "TAG" field type make it available and visible.
3569
     *    Called it "books" for example.
3570
     * 2. Go to profile main/auth/profile.php There you will see a special input (facebook style) that will show suggestions of tags.
3571
     * 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
3572
     * 4. Tags are independent this means that tags can't be shared between tags + book + hobbies.
3573
     * 5. Test and enjoy.
3574
     *
3575
     * @param string $tag
3576
     * @param int    $field_id      field_id
3577
     * @param string $return_format how we are going to result value in array or in a string (json)
3578
     * @param $limit
3579
     *
3580
     * @return mixed
3581
     */
3582
    public static function get_tags($tag, $field_id, $return_format = 'json', $limit = 10)
3583
    {
3584
        // database table definition
3585
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3586
        $field_id = (int) $field_id;
3587
        $limit = (int) $limit;
3588
        $tag = trim(Database::escape_string($tag));
3589
3590
        // all the information of the field
3591
        $sql = "SELECT DISTINCT id, tag from $table_user_tag
3592
                WHERE field_id = $field_id AND tag LIKE '$tag%' ORDER BY tag LIMIT $limit";
3593
        $result = Database::query($sql);
3594
        $return = [];
3595
        if (Database::num_rows($result) > 0) {
3596
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3597
                $return[] = ['id' => $row['tag'], 'text' => $row['tag']];
3598
            }
3599
        }
3600
        if ('json' === $return_format) {
3601
            $return = json_encode($return);
3602
        }
3603
3604
        return $return;
3605
    }
3606
3607
    /**
3608
     * @param int $field_id
3609
     * @param int $limit
3610
     *
3611
     * @return array
3612
     */
3613
    public static function get_top_tags($field_id, $limit = 100)
3614
    {
3615
        // database table definition
3616
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3617
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3618
        $field_id = (int) $field_id;
3619
        $limit = (int) $limit;
3620
        // all the information of the field
3621
        $sql = "SELECT count(*) count, tag FROM $table_user_tag_values  uv
3622
                INNER JOIN $table_user_tag ut
3623
                ON (ut.id = uv.tag_id)
3624
                WHERE field_id = $field_id
3625
                GROUP BY tag_id
3626
                ORDER BY count DESC
3627
                LIMIT $limit";
3628
        $result = Database::query($sql);
3629
        $return = [];
3630
        if (Database::num_rows($result) > 0) {
3631
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3632
                $return[] = $row;
3633
            }
3634
        }
3635
3636
        return $return;
3637
    }
3638
3639
    /**
3640
     * Get user's tags.
3641
     *
3642
     * @param int $user_id
3643
     * @param int $field_id
3644
     *
3645
     * @return array
3646
     */
3647
    public static function get_user_tags($user_id, $field_id)
3648
    {
3649
        // database table definition
3650
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3651
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3652
        $field_id = (int) $field_id;
3653
        $user_id = (int) $user_id;
3654
3655
        // all the information of the field
3656
        $sql = "SELECT ut.id, tag, count
3657
                FROM $table_user_tag ut
3658
                INNER JOIN $table_user_tag_values uv
3659
                ON (uv.tag_id=ut.ID)
3660
                WHERE field_id = $field_id AND user_id = $user_id
3661
                ORDER BY tag";
3662
        $result = Database::query($sql);
3663
        $return = [];
3664
        if (Database::num_rows($result) > 0) {
3665
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3666
                $return[$row['id']] = ['tag' => $row['tag'], 'count' => $row['count']];
3667
            }
3668
        }
3669
3670
        return $return;
3671
    }
3672
3673
    /**
3674
     * Get user's tags.
3675
     *
3676
     * @param int  $user_id
3677
     * @param int  $field_id
3678
     * @param bool $show_links show links or not
3679
     *
3680
     * @return string
3681
     */
3682
    public static function get_user_tags_to_string($user_id, $field_id, $show_links = true)
3683
    {
3684
        // database table definition
3685
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3686
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3687
        $field_id = (int) $field_id;
3688
        $user_id = (int) $user_id;
3689
3690
        // all the information of the field
3691
        $sql = "SELECT ut.id, tag,count FROM $table_user_tag ut
3692
                INNER JOIN $table_user_tag_values uv
3693
                ON (uv.tag_id = ut.id)
3694
                WHERE field_id = $field_id AND user_id = $user_id
3695
                ORDER BY tag";
3696
3697
        $result = Database::query($sql);
3698
        $return = [];
3699
        if (Database::num_rows($result) > 0) {
3700
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3701
                $return[$row['id']] = ['tag' => $row['tag'], 'count' => $row['count']];
3702
            }
3703
        }
3704
        $user_tags = $return;
3705
        $tag_tmp = [];
3706
        foreach ($user_tags as $tag) {
3707
            if ($show_links) {
3708
                $tag_tmp[] = '<a href="'.api_get_path(WEB_PATH).'main/search/index.php?q='.$tag['tag'].'">'.
3709
                    $tag['tag'].
3710
                '</a>';
3711
            } else {
3712
                $tag_tmp[] = $tag['tag'];
3713
            }
3714
        }
3715
3716
        if (is_array($user_tags) && count($user_tags) > 0) {
3717
            return implode(', ', $tag_tmp);
3718
        } else {
3719
            return '';
3720
        }
3721
    }
3722
3723
    /**
3724
     * Get the tag id.
3725
     *
3726
     * @param int $tag
3727
     * @param int $field_id
3728
     *
3729
     * @return int returns 0 if fails otherwise the tag id
3730
     */
3731
    public static function get_tag_id($tag, $field_id)
3732
    {
3733
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3734
        $tag = Database::escape_string($tag);
3735
        $field_id = (int) $field_id;
3736
        //with COLLATE latin1_bin to select query in a case sensitive mode
3737
        $sql = "SELECT id FROM $table_user_tag
3738
                WHERE tag LIKE '$tag' AND field_id = $field_id";
3739
        $result = Database::query($sql);
3740
        if (Database::num_rows($result) > 0) {
3741
            $row = Database::fetch_array($result, 'ASSOC');
3742
3743
            return $row['id'];
3744
        } else {
3745
            return 0;
3746
        }
3747
    }
3748
3749
    /**
3750
     * Get the tag id.
3751
     *
3752
     * @param int $tag_id
3753
     * @param int $field_id
3754
     *
3755
     * @return int 0 if fails otherwise the tag id
3756
     */
3757
    public static function get_tag_id_from_id($tag_id, $field_id)
3758
    {
3759
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3760
        $tag_id = (int) $tag_id;
3761
        $field_id = (int) $field_id;
3762
        $sql = "SELECT id FROM $table_user_tag
3763
                WHERE id = '$tag_id' AND field_id = $field_id";
3764
        $result = Database::query($sql);
3765
        if (Database::num_rows($result) > 0) {
3766
            $row = Database::fetch_array($result, 'ASSOC');
3767
3768
            return $row['id'];
3769
        } else {
3770
            return false;
3771
        }
3772
    }
3773
3774
    /**
3775
     * Adds a user-tag value.
3776
     *
3777
     * @param mixed $tag
3778
     * @param int   $user_id
3779
     * @param int   $field_id field id of the tag
3780
     *
3781
     * @return bool True if the tag was inserted or updated. False otherwise.
3782
     *              The return value doesn't take into account *values* added to the tag.
3783
     *              Only the creation/update of the tag field itself.
3784
     */
3785
    public static function add_tag($tag, $user_id, $field_id)
3786
    {
3787
        // database table definition
3788
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3789
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3790
        $tag = trim(Database::escape_string($tag));
3791
        $user_id = (int) $user_id;
3792
        $field_id = (int) $field_id;
3793
3794
        $tag_id = self::get_tag_id($tag, $field_id);
3795
3796
        /* IMPORTANT
3797
         *  @todo we don't create tags with numbers
3798
         *
3799
         */
3800
        if (is_numeric($tag)) {
3801
            //the form is sending an id this means that the user select it from the list so it MUST exists
3802
            /* $new_tag_id = self::get_tag_id_from_id($tag,$field_id);
3803
              if ($new_tag_id !== false) {
3804
              $sql = "UPDATE $table_user_tag SET count = count + 1 WHERE id  = $new_tag_id";
3805
              $result = Database::query($sql);
3806
              $last_insert_id = $new_tag_id;
3807
              } else {
3808
              $sql = "INSERT INTO $table_user_tag (tag, field_id,count) VALUES ('$tag','$field_id', count + 1)";
3809
              $result = Database::query($sql);
3810
              $last_insert_id = Database::insert_id();
3811
              } */
3812
        }
3813
3814
        //this is a new tag
3815
        if (0 == $tag_id) {
3816
            //the tag doesn't exist
3817
            $sql = "INSERT INTO $table_user_tag (tag, field_id,count) VALUES ('$tag','$field_id', count + 1)";
3818
            Database::query($sql);
3819
            $last_insert_id = Database::insert_id();
3820
        } else {
3821
            //the tag exists we update it
3822
            $sql = "UPDATE $table_user_tag SET count = count + 1 WHERE id  = $tag_id";
3823
            Database::query($sql);
3824
            $last_insert_id = $tag_id;
3825
        }
3826
3827
        if (!empty($last_insert_id) && (0 != $last_insert_id)) {
3828
            //we insert the relationship user-tag
3829
            $sql = "SELECT tag_id FROM $table_user_tag_values
3830
                    WHERE user_id = $user_id AND tag_id = $last_insert_id ";
3831
            $result = Database::query($sql);
3832
            //if the relationship does not exist we create it
3833
            if (0 == Database::num_rows($result)) {
3834
                $sql = "INSERT INTO $table_user_tag_values SET user_id = $user_id, tag_id = $last_insert_id";
3835
                Database::query($sql);
3836
            }
3837
3838
            return true;
3839
        }
3840
3841
        return false;
3842
    }
3843
3844
    /**
3845
     * Deletes an user tag.
3846
     *
3847
     * @param int $user_id
3848
     * @param int $field_id
3849
     */
3850
    public static function delete_user_tags($user_id, $field_id)
3851
    {
3852
        // database table definition
3853
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3854
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3855
        $user_id = (int) $user_id;
3856
3857
        $tags = self::get_user_tags($user_id, $field_id);
3858
        if (is_array($tags) && count($tags) > 0) {
3859
            foreach ($tags as $key => $tag) {
3860
                if ($tag['count'] > '0') {
3861
                    $sql = "UPDATE $table_user_tag SET count = count - 1  WHERE id = $key ";
3862
                    Database::query($sql);
3863
                }
3864
                $sql = "DELETE FROM $table_user_tag_values
3865
                        WHERE user_id = $user_id AND tag_id = $key";
3866
                Database::query($sql);
3867
            }
3868
        }
3869
    }
3870
3871
    /**
3872
     * Process the tag list comes from the UserManager::update_extra_field_value() function.
3873
     *
3874
     * @param array $tags     the tag list that will be added
3875
     * @param int   $user_id
3876
     * @param int   $field_id
3877
     *
3878
     * @return bool
3879
     */
3880
    public static function process_tags($tags, $user_id, $field_id)
3881
    {
3882
        // We loop the tags and add it to the DB
3883
        if (is_array($tags)) {
3884
            foreach ($tags as $tag) {
3885
                self::add_tag($tag, $user_id, $field_id);
3886
            }
3887
        } else {
3888
            self::add_tag($tags, $user_id, $field_id);
3889
        }
3890
3891
        return true;
3892
    }
3893
3894
    /**
3895
     * Returns a list of all administrators.
3896
     *
3897
     * @return array
3898
     */
3899
    public static function get_all_administrators()
3900
    {
3901
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
3902
        $table_admin = Database::get_main_table(TABLE_MAIN_ADMIN);
3903
        $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3904
        $access_url_id = api_get_current_access_url_id();
3905
        if (api_get_multiple_access_url()) {
3906
            $sql = "SELECT admin.user_id, username, firstname, lastname, email, active
3907
                    FROM $tbl_url_rel_user as url
3908
                    INNER JOIN $table_admin as admin
3909
                    ON (admin.user_id=url.user_id)
3910
                    INNER JOIN $table_user u
3911
                    ON (u.id=admin.user_id)
3912
                    WHERE access_url_id ='".$access_url_id."'";
3913
        } else {
3914
            $sql = "SELECT admin.user_id, username, firstname, lastname, email, active
3915
                    FROM $table_admin as admin
3916
                    INNER JOIN $table_user u
3917
                    ON (u.id=admin.user_id)";
3918
        }
3919
        $result = Database::query($sql);
3920
        $return = [];
3921
        if (Database::num_rows($result) > 0) {
3922
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3923
                $return[$row['user_id']] = $row;
3924
            }
3925
        }
3926
3927
        return $return;
3928
    }
3929
3930
    /**
3931
     * Search an user (tags, first name, last name and email ).
3932
     *
3933
     * @param string $tag
3934
     * @param int    $field_id        field id of the tag
3935
     * @param int    $from            where to start in the query
3936
     * @param int    $number_of_items
3937
     * @param bool   $getCount        get count or not
3938
     *
3939
     * @return array
3940
     */
3941
    public static function get_all_user_tags(
3942
        $tag,
3943
        $field_id = 0,
3944
        $from = 0,
3945
        $number_of_items = 10,
3946
        $getCount = false
3947
    ) {
3948
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
3949
        $table_user_tag = Database::get_main_table(TABLE_MAIN_TAG);
3950
        $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG);
3951
        $access_url_rel_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3952
3953
        $field_id = intval($field_id);
3954
        $from = intval($from);
3955
        $number_of_items = intval($number_of_items);
3956
3957
        $where_field = "";
3958
        $where_extra_fields = self::get_search_form_where_extra_fields();
3959
        if (0 != $field_id) {
3960
            $where_field = " field_id = $field_id AND ";
3961
        }
3962
3963
        // all the information of the field
3964
        if ($getCount) {
3965
            $select = "SELECT count(DISTINCT u.id) count";
3966
        } else {
3967
            $select = "SELECT DISTINCT u.id, u.username, firstname, lastname, email, tag, picture_uri";
3968
        }
3969
3970
        $sql = " $select
3971
                FROM $user_table u
3972
                INNER JOIN $access_url_rel_user_table url_rel_user
3973
                ON (u.id = url_rel_user.user_id)
3974
                LEFT JOIN $table_user_tag_values uv
3975
                ON (u.id AND uv.user_id AND uv.user_id = url_rel_user.user_id)
3976
                LEFT JOIN $table_user_tag ut ON (uv.tag_id = ut.id)
3977
                WHERE
3978
                    ($where_field tag LIKE '".Database::escape_string($tag."%")."') OR
3979
                    (
3980
                        u.firstname LIKE '".Database::escape_string("%".$tag."%")."' OR
3981
                        u.lastname LIKE '".Database::escape_string("%".$tag."%")."' OR
3982
                        u.username LIKE '".Database::escape_string("%".$tag."%")."' OR
3983
                        concat(u.firstname, ' ', u.lastname) LIKE '".Database::escape_string("%".$tag."%")."' OR
3984
                        concat(u.lastname, ' ', u.firstname) LIKE '".Database::escape_string("%".$tag."%")."'
3985
                     )
3986
                     ".(!empty($where_extra_fields) ? $where_extra_fields : '')."
3987
                     AND url_rel_user.access_url_id=".api_get_current_access_url_id();
3988
3989
        $keyword_active = true;
3990
        // only active users
3991
        if ($keyword_active) {
3992
            $sql .= " AND u.active='1'";
3993
        }
3994
        // avoid anonymous
3995
        $sql .= " AND u.status <> 6 ";
3996
        $sql .= " ORDER BY username";
3997
        $sql .= " LIMIT $from , $number_of_items";
3998
3999
        $result = Database::query($sql);
4000
        $return = [];
4001
4002
        if (Database::num_rows($result) > 0) {
4003
            if ($getCount) {
4004
                $row = Database::fetch_array($result, 'ASSOC');
4005
4006
                return $row['count'];
4007
            }
4008
            while ($row = Database::fetch_array($result, 'ASSOC')) {
4009
                $return[$row['id']] = $row;
4010
            }
4011
        }
4012
4013
        return $return;
4014
    }
4015
4016
    /**
4017
     * Get extra filterable user fields (only type select).
4018
     *
4019
     * @return array Array of extra fields as [int => ['name' => ..., 'variable' => ..., 'data' => ...]] (
4020
     *               or empty array if no extra field)
4021
     */
4022
    public static function getExtraFilterableFields()
4023
    {
4024
        $extraFieldList = self::get_extra_fields();
4025
        $fields = [];
4026
        if (is_array($extraFieldList)) {
4027
            foreach ($extraFieldList as $extraField) {
4028
                // If is enabled to filter and is a "<select>" field type
4029
                if (1 == $extraField[8] && 4 == $extraField[2]) {
4030
                    $fields[] = [
4031
                        'name' => $extraField[3],
4032
                        'variable' => $extraField[1],
4033
                        'data' => $extraField[9],
4034
                    ];
4035
                }
4036
            }
4037
        }
4038
4039
        return $fields;
4040
    }
4041
4042
    /**
4043
     * Get extra where clauses for finding users based on extra filterable user fields (type select).
4044
     *
4045
     * @return string With AND clauses based on user's ID which have the values to search in extra user fields
4046
     *                (or empty if no extra field exists)
4047
     */
4048
    public static function get_search_form_where_extra_fields()
4049
    {
4050
        $useExtraFields = false;
4051
        $extraFields = self::getExtraFilterableFields();
4052
        $extraFieldResult = [];
4053
        if (is_array($extraFields) && count($extraFields) > 0) {
4054
            foreach ($extraFields as $extraField) {
4055
                $varName = 'field_'.$extraField['variable'];
4056
                if (self::is_extra_field_available($extraField['variable'])) {
4057
                    if (isset($_GET[$varName]) && '0' != $_GET[$varName]) {
4058
                        $useExtraFields = true;
4059
                        $extraFieldResult[] = self::get_extra_user_data_by_value(
4060
                            $extraField['variable'],
4061
                            $_GET[$varName]
4062
                        );
4063
                    }
4064
                }
4065
            }
4066
        }
4067
4068
        if ($useExtraFields) {
4069
            $finalResult = [];
4070
            if (count($extraFieldResult) > 1) {
4071
                for ($i = 0; $i < count($extraFieldResult) - 1; $i++) {
4072
                    if (is_array($extraFieldResult[$i]) && is_array($extraFieldResult[$i + 1])) {
4073
                        $finalResult = array_intersect($extraFieldResult[$i], $extraFieldResult[$i + 1]);
4074
                    }
4075
                }
4076
            } else {
4077
                $finalResult = $extraFieldResult[0];
4078
            }
4079
4080
            if (is_array($finalResult) && count($finalResult) > 0) {
4081
                $whereFilter = " AND u.id IN  ('".implode("','", $finalResult)."') ";
4082
            } else {
4083
                //no results
4084
                $whereFilter = " AND u.id  = -1 ";
4085
            }
4086
4087
            return $whereFilter;
4088
        }
4089
4090
        return '';
4091
    }
4092
4093
    /**
4094
     * Show the search form.
4095
     *
4096
     * @param string $query the value of the search box
4097
     *
4098
     * @throws Exception
4099
     *
4100
     * @return string HTML form
4101
     */
4102
    public static function get_search_form($query, $defaultParams = [])
4103
    {
4104
        $searchType = isset($_GET['search_type']) ? $_GET['search_type'] : null;
4105
        $form = new FormValidator(
4106
            'search_user',
4107
            'get',
4108
            api_get_path(WEB_PATH).'main/social/search.php',
4109
            '',
4110
            [],
4111
            FormValidator::LAYOUT_HORIZONTAL
4112
        );
4113
4114
        $query = Security::remove_XSS($query);
4115
4116
        if (!empty($query)) {
4117
            $form->addHeader(get_lang('Results and feedback').' "'.$query.'"');
4118
        }
4119
4120
        $form->addText(
4121
            'q',
4122
            get_lang('Users, Groups'),
4123
            false,
4124
            [
4125
                'id' => 'q',
4126
            ]
4127
        );
4128
        $options = [
4129
            0 => get_lang('Select'),
4130
            1 => get_lang('User'),
4131
            2 => get_lang('Group'),
4132
        ];
4133
        $form->addSelect(
4134
            'search_type',
4135
            get_lang('Type'),
4136
            $options,
4137
            ['onchange' => 'javascript: extra_field_toogle();', 'id' => 'search_type']
4138
        );
4139
4140
        // Extra fields
4141
        $extraFields = self::getExtraFilterableFields();
4142
        $defaults = [];
4143
        if (is_array($extraFields) && count($extraFields) > 0) {
4144
            foreach ($extraFields as $extraField) {
4145
                $varName = 'field_'.$extraField['variable'];
4146
                $options = [
4147
                    0 => get_lang('Select'),
4148
                ];
4149
                foreach ($extraField['data'] as $option) {
4150
                    if (isset($_GET[$varName])) {
4151
                        if ($_GET[$varName] == $option[1]) {
4152
                            $defaults[$option[1]] = true;
4153
                        }
4154
                    }
4155
4156
                    $options[$option[1]] = $option[1];
4157
                }
4158
                $form->addSelect($varName, $extraField['name'], $options);
4159
            }
4160
        }
4161
4162
        $defaults['search_type'] = (int) $searchType;
4163
        $defaults['q'] = $query;
4164
4165
        if (!empty($defaultParams)) {
4166
            $defaults = array_merge($defaults, $defaultParams);
4167
        }
4168
        $form->setDefaults($defaults);
4169
        $form->addButtonSearch(get_lang('Search'));
4170
4171
        $js = '<script>
4172
        extra_field_toogle();
4173
        function extra_field_toogle() {
4174
            if (jQuery("select[name=search_type]").val() != "1") {
4175
                jQuery(".extra_field").hide();
4176
            } else {
4177
                jQuery(".extra_field").show();
4178
            }
4179
        }
4180
        </script>';
4181
4182
        return $js.$form->returnForm();
4183
    }
4184
4185
    /**
4186
     * Shows the user menu.
4187
     */
4188
    public static function show_menu()
4189
    {
4190
        echo '<div class="actions">';
4191
        echo '<a href="/main/auth/profile.php">'.
4192
            Display::return_icon('profile.png').' '.get_lang('Profile').'</a>';
4193
        echo '<a href="/main/messages/inbox.php">'.
4194
            Display::return_icon('inbox.png').' '.get_lang('Inbox').'</a>';
4195
        echo '<a href="/main/messages/outbox.php">'.
4196
            Display::return_icon('outbox.png').' '.get_lang('Outbox').'</a>';
4197
        echo '<span style="float:right; padding-top:7px;">'.
4198
        '<a href="/main/auth/profile.php?show=1">'.
4199
            Display::return_icon('edit.gif').' '.get_lang('Configuration').'</a>';
4200
        echo '</span>';
4201
        echo '</div>';
4202
    }
4203
4204
    /**
4205
     * Allow to register contact to social network.
4206
     *
4207
     * @param int $friend_id     user friend id
4208
     * @param int $my_user_id    user id
4209
     * @param int $relation_type relation between users see constants definition
4210
     *
4211
     * @return bool
4212
     */
4213
    public static function relate_users($friend_id, $my_user_id, $relation_type)
4214
    {
4215
        $tbl_my_friend = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4216
4217
        $friend_id = (int) $friend_id;
4218
        $my_user_id = (int) $my_user_id;
4219
        $relation_type = (int) $relation_type;
4220
4221
        $sql = 'SELECT COUNT(*) as count FROM '.$tbl_my_friend.'
4222
                WHERE
4223
                    friend_user_id='.$friend_id.' AND
4224
                    user_id='.$my_user_id.' AND
4225
                    relation_type NOT IN('.USER_RELATION_TYPE_RRHH.', '.USER_RELATION_TYPE_BOSS.') ';
4226
        $result = Database::query($sql);
4227
        $row = Database::fetch_array($result, 'ASSOC');
4228
        $current_date = api_get_utc_datetime();
4229
4230
        if (0 == $row['count']) {
4231
            $sql = 'INSERT INTO '.$tbl_my_friend.'(friend_user_id,user_id,relation_type,last_edit)
4232
                    VALUES ('.$friend_id.','.$my_user_id.','.$relation_type.',"'.$current_date.'")';
4233
            Database::query($sql);
4234
4235
            return true;
4236
        }
4237
4238
        $sql = 'SELECT COUNT(*) as count, relation_type  FROM '.$tbl_my_friend.'
4239
                WHERE
4240
                    friend_user_id='.$friend_id.' AND
4241
                    user_id='.$my_user_id.' AND
4242
                    relation_type NOT IN('.USER_RELATION_TYPE_RRHH.', '.USER_RELATION_TYPE_BOSS.') ';
4243
        $result = Database::query($sql);
4244
        $row = Database::fetch_array($result, 'ASSOC');
4245
4246
        if (1 == $row['count']) {
4247
            //only for the case of a RRHH or a Student BOSS
4248
            if ($row['relation_type'] != $relation_type &&
4249
                (USER_RELATION_TYPE_RRHH == $relation_type || USER_RELATION_TYPE_BOSS == $relation_type)
4250
            ) {
4251
                $sql = 'INSERT INTO '.$tbl_my_friend.'(friend_user_id,user_id,relation_type,last_edit)
4252
                        VALUES ('.$friend_id.','.$my_user_id.','.$relation_type.',"'.$current_date.'")';
4253
            } else {
4254
                $sql = 'UPDATE '.$tbl_my_friend.' SET relation_type='.$relation_type.'
4255
                        WHERE friend_user_id='.$friend_id.' AND user_id='.$my_user_id;
4256
            }
4257
            Database::query($sql);
4258
4259
            return true;
4260
        }
4261
4262
        return false;
4263
    }
4264
4265
    /**
4266
     * Deletes a contact.
4267
     *
4268
     * @param bool   $friend_id
4269
     * @param bool   $real_removed          true will delete ALL friends relationship
4270
     * @param string $with_status_condition
4271
     *
4272
     * @author isaac flores paz <[email protected]>
4273
     * @author Julio Montoya <[email protected]> Cleaning code
4274
     */
4275
    public static function remove_user_rel_user(
4276
        $friend_id,
4277
        $real_removed = false,
4278
        $with_status_condition = ''
4279
    ) {
4280
        $tbl_my_friend = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4281
        $tbl_my_message = Database::get_main_table(TABLE_MESSAGE);
4282
        $friend_id = (int) $friend_id;
4283
        $user_id = api_get_user_id();
4284
4285
        if ($real_removed) {
4286
            $extra_condition = '';
4287
            if ('' != $with_status_condition) {
4288
                $extra_condition = ' AND relation_type = '.intval($with_status_condition);
4289
            }
4290
            $sql = 'DELETE FROM '.$tbl_my_friend.'
4291
                    WHERE
4292
                        relation_type <> '.USER_RELATION_TYPE_RRHH.' AND
4293
                        friend_user_id='.$friend_id.' '.$extra_condition;
4294
            Database::query($sql);
4295
            $sql = 'DELETE FROM '.$tbl_my_friend.'
4296
                   WHERE
4297
                    relation_type <> '.USER_RELATION_TYPE_RRHH.' AND
4298
                    user_id='.$friend_id.' '.$extra_condition;
4299
            Database::query($sql);
4300
        } else {
4301
            $sql = 'SELECT COUNT(*) as count FROM '.$tbl_my_friend.'
4302
                    WHERE
4303
                        user_id='.$user_id.' AND
4304
                        relation_type NOT IN('.USER_RELATION_TYPE_DELETED.', '.USER_RELATION_TYPE_RRHH.') AND
4305
                        friend_user_id='.$friend_id;
4306
            $result = Database::query($sql);
4307
            $row = Database::fetch_array($result, 'ASSOC');
4308
            if (1 == $row['count']) {
4309
                //Delete user rel user
4310
                $sql_i = 'UPDATE '.$tbl_my_friend.' SET relation_type='.USER_RELATION_TYPE_DELETED.'
4311
                          WHERE user_id='.$user_id.' AND friend_user_id='.$friend_id;
4312
4313
                $sql_j = 'UPDATE '.$tbl_my_message.' SET msg_status='.MESSAGE_STATUS_INVITATION_DENIED.'
4314
                          WHERE
4315
                                user_receiver_id='.$user_id.' AND
4316
                                user_sender_id='.$friend_id.' AND update_date="0000-00-00 00:00:00" ';
4317
                // Delete user
4318
                $sql_ij = 'UPDATE '.$tbl_my_friend.'  SET relation_type='.USER_RELATION_TYPE_DELETED.'
4319
                           WHERE user_id='.$friend_id.' AND friend_user_id='.$user_id;
4320
                $sql_ji = 'UPDATE '.$tbl_my_message.' SET msg_status='.MESSAGE_STATUS_INVITATION_DENIED.'
4321
                           WHERE
4322
                                user_receiver_id='.$friend_id.' AND
4323
                                user_sender_id='.$user_id.' AND
4324
                                update_date="0000-00-00 00:00:00" ';
4325
                Database::query($sql_i);
4326
                Database::query($sql_j);
4327
                Database::query($sql_ij);
4328
                Database::query($sql_ji);
4329
            }
4330
        }
4331
4332
        // Delete accepted invitations
4333
        $sql = "DELETE FROM $tbl_my_message
4334
                WHERE
4335
                    msg_status = ".MESSAGE_STATUS_INVITATION_ACCEPTED." AND
4336
                    (
4337
                        user_receiver_id = $user_id AND
4338
                        user_sender_id = $friend_id
4339
                    ) OR
4340
                    (
4341
                        user_sender_id = $user_id AND
4342
                        user_receiver_id = $friend_id
4343
                    )
4344
        ";
4345
        Database::query($sql);
4346
    }
4347
4348
    /**
4349
     * @param int $userId
4350
     *
4351
     * @return array
4352
     */
4353
    public static function getDrhListFromUser($userId)
4354
    {
4355
        $tblUser = Database::get_main_table(TABLE_MAIN_USER);
4356
        $tblUserRelUser = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4357
        $tblUserRelAccessUrl = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
4358
        $userId = (int) $userId;
4359
4360
        $orderBy = null;
4361
        if (api_is_western_name_order()) {
4362
            $orderBy .= ' ORDER BY firstname, lastname ';
4363
        } else {
4364
            $orderBy .= ' ORDER BY lastname, firstname ';
4365
        }
4366
4367
        $sql = "SELECT u.id, username, u.firstname, u.lastname
4368
                FROM $tblUser u
4369
                INNER JOIN $tblUserRelUser uru ON (uru.friend_user_id = u.id)
4370
                INNER JOIN $tblUserRelAccessUrl a ON (a.user_id = u.id)
4371
                WHERE
4372
                    access_url_id = ".api_get_current_access_url_id()." AND
4373
                    uru.user_id = '$userId' AND
4374
                    relation_type = '".USER_RELATION_TYPE_RRHH."'
4375
                $orderBy
4376
                ";
4377
        $result = Database::query($sql);
4378
4379
        return Database::store_result($result);
4380
    }
4381
4382
    /**
4383
     * get users followed by human resource manager.
4384
     *
4385
     * @param int    $userId
4386
     * @param int    $userStatus         (STUDENT, COURSEMANAGER, etc)
4387
     * @param bool   $getOnlyUserId
4388
     * @param bool   $getSql
4389
     * @param bool   $getCount
4390
     * @param int    $from
4391
     * @param int    $numberItems
4392
     * @param int    $column
4393
     * @param string $direction
4394
     * @param int    $active
4395
     * @param string $lastConnectionDate
4396
     *
4397
     * @return array users
4398
     */
4399
    public static function get_users_followed_by_drh(
4400
        $userId,
4401
        $userStatus = 0,
4402
        $getOnlyUserId = false,
4403
        $getSql = false,
4404
        $getCount = false,
4405
        $from = null,
4406
        $numberItems = null,
4407
        $column = null,
4408
        $direction = null,
4409
        $active = null,
4410
        $lastConnectionDate = null
4411
    ) {
4412
        return self::getUsersFollowedByUser(
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::getUsersFol...astConnectionDate, DRH) also could return the type string which is incompatible with the documented return type array.
Loading history...
4413
            $userId,
4414
            $userStatus,
4415
            $getOnlyUserId,
4416
            $getSql,
4417
            $getCount,
4418
            $from,
4419
            $numberItems,
4420
            $column,
4421
            $direction,
4422
            $active,
4423
            $lastConnectionDate,
4424
            DRH
4425
        );
4426
    }
4427
4428
    /**
4429
     * Get users followed by human resource manager.
4430
     *
4431
     * @param int    $userId
4432
     * @param int    $userStatus         Filter users by status (STUDENT, COURSEMANAGER, etc)
4433
     * @param bool   $getOnlyUserId
4434
     * @param bool   $getSql
4435
     * @param bool   $getCount
4436
     * @param int    $from
4437
     * @param int    $numberItems
4438
     * @param int    $column
4439
     * @param string $direction
4440
     * @param int    $active
4441
     * @param string $lastConnectionDate
4442
     * @param int    $status             the function is called by who? COURSEMANAGER, DRH?
4443
     * @param string $keyword
4444
     *
4445
     * @return mixed Users list (array) or the SQL query if $getSQL was set to true
4446
     */
4447
    public static function getUsersFollowedByUser(
4448
        $userId,
4449
        $userStatus = null,
4450
        $getOnlyUserId = false,
4451
        $getSql = false,
4452
        $getCount = false,
4453
        $from = null,
4454
        $numberItems = null,
4455
        $column = null,
4456
        $direction = null,
4457
        $active = null,
4458
        $lastConnectionDate = null,
4459
        $status = null,
4460
        $keyword = null
4461
    ) {
4462
        // Database Table Definitions
4463
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
4464
        $tbl_user_rel_user = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4465
        $tbl_user_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
4466
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
4467
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4468
        $tbl_session_rel_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4469
        $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
4470
        $tbl_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
4471
4472
        $userId = (int) $userId;
4473
        $limitCondition = '';
4474
4475
        if (isset($from) && isset($numberItems)) {
4476
            $from = (int) $from;
4477
            $numberItems = (int) $numberItems;
4478
            $limitCondition = "LIMIT $from, $numberItems";
4479
        }
4480
4481
        $column = Database::escape_string($column);
4482
        $direction = in_array(strtolower($direction), ['asc', 'desc']) ? $direction : null;
4483
4484
        $userConditions = '';
4485
        if (!empty($userStatus)) {
4486
            $userConditions .= ' AND u.status = '.intval($userStatus);
4487
        }
4488
4489
        $select = " SELECT DISTINCT u.id user_id, u.username, u.lastname, u.firstname, u.email ";
4490
        if ($getOnlyUserId) {
4491
            $select = " SELECT DISTINCT u.id user_id";
4492
        }
4493
4494
        $masterSelect = "SELECT DISTINCT * FROM ";
4495
4496
        if ($getCount) {
4497
            $masterSelect = "SELECT COUNT(DISTINCT(user_id)) as count FROM ";
4498
            $select = " SELECT DISTINCT(u.id) user_id";
4499
        }
4500
4501
        if (!is_null($active)) {
4502
            $active = intval($active);
4503
            $userConditions .= " AND u.active = $active ";
4504
        }
4505
4506
        if (!empty($keyword)) {
4507
            $keyword = Database::escape_string($keyword);
4508
            $userConditions .= " AND (
4509
                u.username LIKE '%$keyword%' OR
4510
                u.firstname LIKE '%$keyword%' OR
4511
                u.lastname LIKE '%$keyword%' OR
4512
                u.official_code LIKE '%$keyword%' OR
4513
                u.email LIKE '%$keyword%'
4514
            )";
4515
        }
4516
4517
        if (!empty($lastConnectionDate)) {
4518
            $lastConnectionDate = Database::escape_string($lastConnectionDate);
4519
            $userConditions .= " AND u.last_login <= '$lastConnectionDate' ";
4520
        }
4521
4522
        $sessionConditionsCoach = null;
4523
        $sessionConditionsTeacher = null;
4524
        $drhConditions = null;
4525
        $teacherSelect = null;
4526
4527
        switch ($status) {
4528
            case DRH:
4529
                $drhConditions .= " AND
4530
                    friend_user_id = '$userId' AND
4531
                    relation_type = '".USER_RELATION_TYPE_RRHH."'
4532
                ";
4533
                break;
4534
            case COURSEMANAGER:
4535
                $drhConditions .= " AND
4536
                    friend_user_id = '$userId' AND
4537
                    relation_type = '".USER_RELATION_TYPE_RRHH."'
4538
                ";
4539
4540
                $sessionConditionsCoach .= " AND
4541
                    (s.id_coach = '$userId')
4542
                ";
4543
4544
                $sessionConditionsTeacher .= " AND
4545
                    (scu.status = 2 AND scu.user_id = '$userId')
4546
                ";
4547
4548
                $teacherSelect =
4549
                "UNION ALL (
4550
                        $select
4551
                        FROM $tbl_user u
4552
                        INNER JOIN $tbl_session_rel_user sru ON (sru.user_id = u.id)
4553
                        WHERE
4554
                            (
4555
                                sru.session_id IN (
4556
                                    SELECT DISTINCT(s.id) FROM $tbl_session s INNER JOIN
4557
                                    $tbl_session_rel_access_url session_rel_access_rel_user
4558
                                    ON session_rel_access_rel_user.session_id = s.id
4559
                                    WHERE access_url_id = ".api_get_current_access_url_id()."
4560
                                    $sessionConditionsCoach
4561
                                ) OR sru.session_id IN (
4562
                                    SELECT DISTINCT(s.id) FROM $tbl_session s
4563
                                    INNER JOIN $tbl_session_rel_access_url url
4564
                                    ON (url.session_id = s.id)
4565
                                    INNER JOIN $tbl_session_rel_course_rel_user scu
4566
                                    ON (scu.session_id = s.id)
4567
                                    WHERE access_url_id = ".api_get_current_access_url_id()."
4568
                                    $sessionConditionsTeacher
4569
                                )
4570
                            )
4571
                            $userConditions
4572
                    )
4573
                    UNION ALL(
4574
                        $select
4575
                        FROM $tbl_user u
4576
                        INNER JOIN $tbl_course_user cu ON (cu.user_id = u.id)
4577
                        WHERE cu.c_id IN (
4578
                            SELECT DISTINCT(c_id) FROM $tbl_course_user
4579
                            WHERE user_id = $userId AND status = ".COURSEMANAGER."
4580
                        )
4581
                        $userConditions
4582
                    )"
4583
                ;
4584
                break;
4585
            case STUDENT_BOSS:
4586
                $drhConditions = " AND friend_user_id = $userId AND relation_type = ".USER_RELATION_TYPE_BOSS;
4587
                break;
4588
            case HRM_REQUEST:
4589
                $drhConditions .= " AND
4590
                    friend_user_id = '$userId' AND
4591
                    relation_type = '".USER_RELATION_TYPE_HRM_REQUEST."'
4592
                ";
4593
                break;
4594
        }
4595
4596
        $join = null;
4597
        $sql = " $masterSelect
4598
                (
4599
                    (
4600
                        $select
4601
                        FROM $tbl_user u
4602
                        INNER JOIN $tbl_user_rel_user uru ON (uru.user_id = u.id)
4603
                        LEFT JOIN $tbl_user_rel_access_url a ON (a.user_id = u.id)
4604
                        $join
4605
                        WHERE
4606
                            access_url_id = ".api_get_current_access_url_id()."
4607
                            $drhConditions
4608
                            $userConditions
4609
                    )
4610
                    $teacherSelect
4611
4612
                ) as t1";
4613
4614
        if ($getSql) {
4615
            return $sql;
4616
        }
4617
        if ($getCount) {
4618
            $result = Database::query($sql);
4619
            $row = Database::fetch_array($result);
4620
4621
            return $row['count'];
4622
        }
4623
4624
        $orderBy = null;
4625
        if (false == $getOnlyUserId) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

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

Loading history...
4626
            if (api_is_western_name_order()) {
4627
                $orderBy .= " ORDER BY firstname, lastname ";
4628
            } else {
4629
                $orderBy .= " ORDER BY lastname, firstname ";
4630
            }
4631
4632
            if (!empty($column) && !empty($direction)) {
4633
                // Fixing order due the UNIONs
4634
                $column = str_replace('u.', '', $column);
4635
                $orderBy = " ORDER BY $column $direction ";
4636
            }
4637
        }
4638
4639
        $sql .= $orderBy;
4640
        $sql .= $limitCondition;
4641
4642
        $result = Database::query($sql);
4643
        $users = [];
4644
        if (Database::num_rows($result) > 0) {
4645
            while ($row = Database::fetch_array($result)) {
4646
                $users[$row['user_id']] = $row;
4647
            }
4648
        }
4649
4650
        return $users;
4651
    }
4652
4653
    /**
4654
     * Subscribes users to human resource manager (Dashboard feature).
4655
     *
4656
     * @param int   $hr_dept_id
4657
     * @param array $users_id
4658
     * @param bool  $deleteOtherAssignedUsers
4659
     *
4660
     * @return int
4661
     */
4662
    public static function subscribeUsersToHRManager(
4663
        $hr_dept_id,
4664
        $users_id,
4665
        $deleteOtherAssignedUsers = true
4666
    ) {
4667
        return self::subscribeUsersToUser(
4668
            $hr_dept_id,
4669
            $users_id,
4670
            USER_RELATION_TYPE_RRHH,
4671
            false,
4672
            $deleteOtherAssignedUsers
4673
        );
4674
    }
4675
4676
    /**
4677
     * Register request to assign users to HRM.
4678
     *
4679
     * @param int   $hrmId   The HRM ID
4680
     * @param array $usersId The users IDs
4681
     *
4682
     * @return int
4683
     */
4684
    public static function requestUsersToHRManager($hrmId, $usersId)
4685
    {
4686
        return self::subscribeUsersToUser(
4687
            $hrmId,
4688
            $usersId,
4689
            USER_RELATION_TYPE_HRM_REQUEST,
4690
            false,
4691
            false
4692
        );
4693
    }
4694
4695
    /**
4696
     * Remove the requests for assign a user to a HRM.
4697
     *
4698
     * @param array $usersId List of user IDs from whom to remove all relations requests with HRM
4699
     */
4700
    public static function clearHrmRequestsForUser(User $hrmId, $usersId)
4701
    {
4702
        $users = implode(', ', $usersId);
4703
        Database::getManager()
4704
            ->createQuery('
4705
                DELETE FROM ChamiloCoreBundle:UserRelUser uru
4706
                WHERE uru.friendUserId = :hrm_id AND uru.relationType = :relation_type AND uru.userId IN (:users_ids)
4707
            ')
4708
            ->execute(['hrm_id' => $hrmId, 'relation_type' => USER_RELATION_TYPE_HRM_REQUEST, 'users_ids' => $users]);
4709
    }
4710
4711
    /**
4712
     * Add subscribed users to a user by relation type.
4713
     *
4714
     * @param int    $userId                   The user id
4715
     * @param array  $subscribedUsersId        The id of subscribed users
4716
     * @param string $relationType             The relation type
4717
     * @param bool   $deleteUsersBeforeInsert
4718
     * @param bool   $deleteOtherAssignedUsers
4719
     *
4720
     * @return int
4721
     */
4722
    public static function subscribeUsersToUser(
4723
        $userId,
4724
        $subscribedUsersId,
4725
        $relationType,
4726
        $deleteUsersBeforeInsert = false,
4727
        $deleteOtherAssignedUsers = true
4728
    ) {
4729
        $userRelUserTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4730
        $userRelAccessUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
4731
4732
        $userId = (int) $userId;
4733
        $relationType = (int) $relationType;
4734
        $affectedRows = 0;
4735
4736
        if ($deleteOtherAssignedUsers) {
4737
            if (api_get_multiple_access_url()) {
4738
                // Deleting assigned users to hrm_id
4739
                $sql = "SELECT s.user_id
4740
                        FROM $userRelUserTable s
4741
                        INNER JOIN $userRelAccessUrlTable a
4742
                        ON (a.user_id = s.user_id)
4743
                        WHERE
4744
                            friend_user_id = $userId AND
4745
                            relation_type = $relationType AND
4746
                            access_url_id = ".api_get_current_access_url_id();
4747
            } else {
4748
                $sql = "SELECT user_id
4749
                        FROM $userRelUserTable
4750
                        WHERE
4751
                            friend_user_id = $userId AND
4752
                            relation_type = $relationType";
4753
            }
4754
            $result = Database::query($sql);
4755
4756
            if (Database::num_rows($result) > 0) {
4757
                while ($row = Database::fetch_array($result)) {
4758
                    $sql = "DELETE FROM $userRelUserTable
4759
                            WHERE
4760
                                user_id = {$row['user_id']} AND
4761
                                friend_user_id = $userId AND
4762
                                relation_type = $relationType";
4763
                    Database::query($sql);
4764
                }
4765
            }
4766
        }
4767
4768
        if ($deleteUsersBeforeInsert) {
4769
            $sql = "DELETE FROM $userRelUserTable
4770
                    WHERE
4771
                        user_id = $userId AND
4772
                        relation_type = $relationType";
4773
            Database::query($sql);
4774
        }
4775
4776
        // Inserting new user list
4777
        if (is_array($subscribedUsersId)) {
4778
            foreach ($subscribedUsersId as $subscribedUserId) {
4779
                $subscribedUserId = (int) $subscribedUserId;
4780
                $sql = "SELECT id
4781
                        FROM $userRelUserTable
4782
                        WHERE
4783
                            user_id = $subscribedUserId AND
4784
                            friend_user_id = $userId AND
4785
                            relation_type = $relationType";
4786
4787
                $result = Database::query($sql);
4788
                $num = Database::num_rows($result);
4789
                if (0 === $num) {
4790
                    $date = api_get_utc_datetime();
4791
                    $sql = "INSERT INTO $userRelUserTable (user_id, friend_user_id, relation_type, last_edit)
4792
                            VALUES ($subscribedUserId, $userId, $relationType, '$date')";
4793
                    $result = Database::query($sql);
4794
                    $affectedRows += Database::affected_rows($result);
4795
                }
4796
            }
4797
        }
4798
4799
        return $affectedRows;
4800
    }
4801
4802
    /**
4803
     * This function check if an user is followed by human resources manager.
4804
     *
4805
     * @param int $user_id
4806
     * @param int $hr_dept_id Human resources manager
4807
     *
4808
     * @return bool
4809
     */
4810
    public static function is_user_followed_by_drh($user_id, $hr_dept_id)
4811
    {
4812
        $tbl_user_rel_user = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
4813
        $user_id = (int) $user_id;
4814
        $hr_dept_id = (int) $hr_dept_id;
4815
        $result = false;
4816
4817
        $sql = "SELECT user_id FROM $tbl_user_rel_user
4818
                WHERE
4819
                    user_id = $user_id AND
4820
                    friend_user_id = $hr_dept_id AND
4821
                    relation_type = ".USER_RELATION_TYPE_RRHH;
4822
        $rs = Database::query($sql);
4823
        if (Database::num_rows($rs) > 0) {
4824
            $result = true;
4825
        }
4826
4827
        return $result;
4828
    }
4829
4830
    /**
4831
     * Return the user id of teacher or session administrator.
4832
     *
4833
     * @param array $courseInfo
4834
     *
4835
     * @return mixed The user id, or false if the session ID was negative
4836
     */
4837
    public static function get_user_id_of_course_admin_or_session_admin($courseInfo)
4838
    {
4839
        $session = api_get_session_id();
4840
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
4841
        $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4842
        $table_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4843
4844
        if (empty($courseInfo)) {
4845
            return false;
4846
        }
4847
4848
        $courseId = $courseInfo['real_id'];
4849
4850
        if (0 == $session || is_null($session)) {
4851
            $sql = 'SELECT u.id uid FROM '.$table_user.' u
4852
                    INNER JOIN '.$table_course_user.' ru
4853
                    ON ru.user_id = u.id
4854
                    WHERE
4855
                        ru.status = 1 AND
4856
                        ru.c_id = "'.$courseId.'" ';
4857
            $rs = Database::query($sql);
4858
            $num_rows = Database::num_rows($rs);
4859
            if (1 == $num_rows) {
4860
                $row = Database::fetch_array($rs);
4861
4862
                return $row['uid'];
4863
            } else {
4864
                $my_num_rows = $num_rows;
4865
                $my_user_id = Database::result($rs, $my_num_rows - 1, 'uid');
4866
4867
                return $my_user_id;
4868
            }
4869
        } elseif ($session > 0) {
4870
            $sql = 'SELECT u.id uid FROM '.$table_user.' u
4871
                    INNER JOIN '.$table_session_course_user.' sru
4872
                    ON sru.user_id=u.id
4873
                    WHERE
4874
                        sru.c_id="'.$courseId.'" AND
4875
                        sru.status=2';
4876
            $rs = Database::query($sql);
4877
            $row = Database::fetch_array($rs);
4878
4879
            return $row['uid'];
4880
        }
4881
4882
        return false;
4883
    }
4884
4885
    /**
4886
     * Determines if a user is a gradebook certified.
4887
     *
4888
     * @param int $cat_id  The category id of gradebook
4889
     * @param int $user_id The user id
4890
     *
4891
     * @return bool
4892
     */
4893
    public static function is_user_certified($cat_id, $user_id)
4894
    {
4895
        $cat_id = (int) $cat_id;
4896
        $user_id = (int) $user_id;
4897
4898
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
4899
        $sql = 'SELECT path_certificate
4900
                FROM '.$table.'
4901
                WHERE
4902
                    cat_id = "'.$cat_id.'" AND
4903
                    user_id = "'.$user_id.'"';
4904
        $rs = Database::query($sql);
4905
        $row = Database::fetch_array($rs);
4906
4907
        if ('' == $row['path_certificate'] || is_null($row['path_certificate'])) {
4908
            return false;
4909
        }
4910
4911
        return true;
4912
    }
4913
4914
    /**
4915
     * Gets the info about a gradebook certificate for a user by course.
4916
     *
4917
     * @param array $course_info The course code
4918
     * @param int   $session_id
4919
     * @param int   $user_id     The user id
4920
     *
4921
     * @return array if there is not information return false
4922
     */
4923
    public static function get_info_gradebook_certificate($course_info, $session_id, $user_id)
4924
    {
4925
        $tbl_grade_certificate = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
4926
        $tbl_grade_category = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
4927
        $session_id = (int) $session_id;
4928
        $user_id = (int) $user_id;
4929
        $courseId = $course_info['real_id'];
4930
4931
        if (empty($session_id)) {
4932
            $session_condition = ' AND (session_id = "" OR session_id = 0 OR session_id IS NULL )';
4933
        } else {
4934
            $session_condition = " AND session_id = $session_id";
4935
        }
4936
4937
        $sql = 'SELECT * FROM '.$tbl_grade_certificate.'
4938
                WHERE cat_id = (
4939
                    SELECT id FROM '.$tbl_grade_category.'
4940
                    WHERE
4941
                        c_id = "'.$courseId.'" '.$session_condition.'
4942
                    LIMIT 1
4943
                ) AND user_id='.$user_id;
4944
4945
        $rs = Database::query($sql);
4946
        if (Database::num_rows($rs) > 0) {
4947
            $row = Database::fetch_array($rs, 'ASSOC');
4948
            $score = $row['score_certificate'];
4949
            $category_id = $row['cat_id'];
4950
            $cat = Category::load($category_id);
4951
            $displayscore = ScoreDisplay::instance();
4952
            if (isset($cat) && $displayscore->is_custom()) {
4953
                $grade = $displayscore->display_score(
4954
                    [$score, $cat[0]->get_weight()],
4955
                    SCORE_DIV_PERCENT_WITH_CUSTOM
4956
                );
4957
            } else {
4958
                $grade = $displayscore->display_score(
4959
                    [$score, $cat[0]->get_weight()]
4960
                );
4961
            }
4962
            $row['grade'] = $grade;
4963
4964
            return $row;
4965
        }
4966
4967
        return false;
4968
    }
4969
4970
    /**
4971
     * This function check if the user is a coach inside session course.
4972
     *
4973
     * @param int $user_id    User id
4974
     * @param int $courseId
4975
     * @param int $session_id
4976
     *
4977
     * @return bool True if the user is a coach
4978
     */
4979
    public static function is_session_course_coach($user_id, $courseId, $session_id)
4980
    {
4981
        $table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4982
        // Protect data
4983
        $user_id = intval($user_id);
4984
        $courseId = intval($courseId);
4985
        $session_id = intval($session_id);
4986
        $result = false;
4987
4988
        $sql = "SELECT session_id FROM $table
4989
                WHERE
4990
                  session_id = $session_id AND
4991
                  c_id = $courseId AND
4992
                  user_id = $user_id AND
4993
                  status = 2 ";
4994
        $res = Database::query($sql);
4995
4996
        if (Database::num_rows($res) > 0) {
4997
            $result = true;
4998
        }
4999
5000
        return $result;
5001
    }
5002
5003
    /**
5004
     * This function returns an icon path that represents the favicon of the website of which the url given.
5005
     * Defaults to the current Chamilo favicon.
5006
     *
5007
     * @param string $url1 URL of website where to look for favicon.ico
5008
     * @param string $url2 Optional second URL of website where to look for favicon.ico
5009
     *
5010
     * @return string Path of icon to load
5011
     */
5012
    public static function get_favicon_from_url($url1, $url2 = null)
5013
    {
5014
        $icon_link = '';
5015
        $url = $url1;
5016
        if (empty($url1)) {
5017
            $url = $url2;
5018
            if (empty($url)) {
5019
                $url = api_get_access_url(api_get_current_access_url_id());
5020
                $url = $url[0];
5021
            }
5022
        }
5023
        if (!empty($url)) {
5024
            $pieces = parse_url($url);
5025
            $icon_link = $pieces['scheme'].'://'.$pieces['host'].'/favicon.ico';
5026
        }
5027
5028
        return $icon_link;
5029
    }
5030
5031
    public static function addUserAsAdmin(User $user)
5032
    {
5033
        if ($user) {
0 ignored issues
show
introduced by
$user is of type Chamilo\CoreBundle\Entity\User, thus it always evaluated to true.
Loading history...
5034
            $userId = $user->getId();
5035
5036
            if (!self::is_admin($userId)) {
5037
                $table = Database::get_main_table(TABLE_MAIN_ADMIN);
5038
                $sql = "INSERT INTO $table SET user_id = $userId";
5039
                Database::query($sql);
5040
            }
5041
5042
            $user->addRole('ROLE_SUPER_ADMIN');
5043
            self::getManager()->updateUser($user, true);
5044
        }
5045
    }
5046
5047
    public static function removeUserAdmin(User $user)
5048
    {
5049
        $userId = (int) $user->getId();
5050
        if (self::is_admin($userId)) {
5051
            $table = Database::get_main_table(TABLE_MAIN_ADMIN);
5052
            $sql = "DELETE FROM $table WHERE user_id = $userId";
5053
            Database::query($sql);
5054
            $user->removeRole('ROLE_SUPER_ADMIN');
5055
            self::getManager()->updateUser($user, true);
5056
        }
5057
    }
5058
5059
    /**
5060
     * @param string $from
5061
     * @param string $to
5062
     */
5063
    public static function update_all_user_languages($from, $to)
5064
    {
5065
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
5066
        $from = Database::escape_string($from);
5067
        $to = Database::escape_string($to);
5068
5069
        if (!empty($to) && !empty($from)) {
5070
            $sql = "UPDATE $table_user SET language = '$to'
5071
                    WHERE language = '$from'";
5072
            Database::query($sql);
5073
        }
5074
    }
5075
5076
    /**
5077
     * Subscribe boss to students.
5078
     *
5079
     * @param int   $bossId  The boss id
5080
     * @param array $usersId The users array
5081
     *
5082
     * @return int Affected rows
5083
     */
5084
    public static function subscribeBossToUsers($bossId, $usersId)
5085
    {
5086
        return self::subscribeUsersToUser(
5087
            $bossId,
5088
            $usersId,
5089
            USER_RELATION_TYPE_BOSS
5090
        );
5091
    }
5092
5093
    /**
5094
     * @param int $userId
5095
     *
5096
     * @return bool
5097
     */
5098
    public static function removeAllBossFromStudent($userId)
5099
    {
5100
        $userId = (int) $userId;
5101
5102
        if (empty($userId)) {
5103
            return false;
5104
        }
5105
5106
        $userRelUserTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5107
        $sql = "DELETE FROM $userRelUserTable
5108
                WHERE user_id = $userId AND relation_type = ".USER_RELATION_TYPE_BOSS;
5109
        Database::query($sql);
5110
5111
        return true;
5112
    }
5113
5114
    /**
5115
     * Subscribe boss to students, if $bossList is empty then the boss list will be empty too.
5116
     *
5117
     * @param int   $studentId
5118
     * @param array $bossList
5119
     * @param bool  $sendNotification
5120
     *
5121
     * @return mixed Affected rows or false on failure
5122
     */
5123
    public static function subscribeUserToBossList(
5124
        $studentId,
5125
        $bossList,
5126
        $sendNotification = false
5127
    ) {
5128
        $inserted = 0;
5129
        if (!empty($bossList)) {
5130
            sort($bossList);
5131
            $studentId = (int) $studentId;
5132
            $studentInfo = api_get_user_info($studentId);
5133
5134
            if (empty($studentInfo)) {
5135
                return false;
5136
            }
5137
5138
            $previousBossList = self::getStudentBossList($studentId);
5139
            $previousBossList = !empty($previousBossList) ? array_column($previousBossList, 'boss_id') : [];
5140
            sort($previousBossList);
5141
5142
            // Boss list is the same, nothing changed.
5143
            if ($bossList == $previousBossList) {
5144
                return false;
5145
            }
5146
5147
            $userRelUserTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5148
            self::removeAllBossFromStudent($studentId);
5149
5150
            foreach ($bossList as $bossId) {
5151
                $bossId = (int) $bossId;
5152
                $bossInfo = api_get_user_info($bossId);
5153
5154
                if (empty($bossInfo)) {
5155
                    continue;
5156
                }
5157
5158
                $bossLanguage = $bossInfo['language'];
5159
                $sql = "INSERT IGNORE INTO $userRelUserTable (user_id, friend_user_id, relation_type)
5160
                        VALUES ($studentId, $bossId, ".USER_RELATION_TYPE_BOSS.")";
5161
                $insertId = Database::query($sql);
5162
5163
                if ($insertId) {
5164
                    if ($sendNotification) {
5165
                        $name = $studentInfo['complete_name'];
5166
                        $url = api_get_path(WEB_CODE_PATH).'mySpace/myStudents.php?student='.$studentId;
5167
                        $url = Display::url($url, $url);
5168
                        $subject = sprintf(get_lang('You have been assigned the learner %s'), $name);
5169
                        $message = sprintf(get_lang('You have been assigned the learner %sWithUrlX'), $name, $url);
5170
                        MessageManager::send_message_simple(
5171
                            $bossId,
5172
                            $subject,
5173
                            $message
5174
                        );
5175
                    }
5176
                    $inserted++;
5177
                }
5178
            }
5179
        } else {
5180
            self::removeAllBossFromStudent($studentId);
5181
        }
5182
5183
        return $inserted;
5184
    }
5185
5186
    /**
5187
     * Get users followed by student boss.
5188
     *
5189
     * @param int    $userId
5190
     * @param int    $userStatus         (STUDENT, COURSEMANAGER, etc)
5191
     * @param bool   $getOnlyUserId
5192
     * @param bool   $getSql
5193
     * @param bool   $getCount
5194
     * @param int    $from
5195
     * @param int    $numberItems
5196
     * @param int    $column
5197
     * @param string $direction
5198
     * @param int    $active
5199
     * @param string $lastConnectionDate
5200
     *
5201
     * @return array users
5202
     */
5203
    public static function getUsersFollowedByStudentBoss(
5204
        $userId,
5205
        $userStatus = 0,
5206
        $getOnlyUserId = false,
5207
        $getSql = false,
5208
        $getCount = false,
5209
        $from = null,
5210
        $numberItems = null,
5211
        $column = null,
5212
        $direction = null,
5213
        $active = null,
5214
        $lastConnectionDate = null
5215
    ) {
5216
        return self::getUsersFollowedByUser(
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::getUsersFol...tionDate, STUDENT_BOSS) also could return the type string which is incompatible with the documented return type array.
Loading history...
5217
            $userId,
5218
            $userStatus,
5219
            $getOnlyUserId,
5220
            $getSql,
5221
            $getCount,
5222
            $from,
5223
            $numberItems,
5224
            $column,
5225
            $direction,
5226
            $active,
5227
            $lastConnectionDate,
5228
            STUDENT_BOSS
5229
        );
5230
    }
5231
5232
    /**
5233
     * @return array
5234
     */
5235
    public static function getOfficialCodeGrouped()
5236
    {
5237
        $user = Database::get_main_table(TABLE_MAIN_USER);
5238
        $sql = "SELECT DISTINCT official_code
5239
                FROM $user
5240
                GROUP BY official_code";
5241
        $result = Database::query($sql);
5242
        $values = Database::store_result($result, 'ASSOC');
5243
        $result = [];
5244
        foreach ($values as $value) {
5245
            $result[$value['official_code']] = $value['official_code'];
5246
        }
5247
5248
        return $result;
5249
    }
5250
5251
    /**
5252
     * @param string $officialCode
5253
     *
5254
     * @return array
5255
     */
5256
    public static function getUsersByOfficialCode($officialCode)
5257
    {
5258
        $user = Database::get_main_table(TABLE_MAIN_USER);
5259
        $officialCode = Database::escape_string($officialCode);
5260
5261
        $sql = "SELECT DISTINCT id
5262
                FROM $user
5263
                WHERE official_code = '$officialCode'
5264
                ";
5265
        $result = Database::query($sql);
5266
5267
        $users = [];
5268
        while ($row = Database::fetch_array($result)) {
5269
            $users[] = $row['id'];
5270
        }
5271
5272
        return $users;
5273
    }
5274
5275
    /**
5276
     * Calc the expended time (in seconds) by a user in a course.
5277
     *
5278
     * @param int    $userId    The user id
5279
     * @param int    $courseId  The course id
5280
     * @param int    $sessionId Optional. The session id
5281
     * @param string $from      Optional. From date
5282
     * @param string $until     Optional. Until date
5283
     *
5284
     * @return int The time
5285
     */
5286
    public static function getTimeSpentInCourses(
5287
        $userId,
5288
        $courseId,
5289
        $sessionId = 0,
5290
        $from = '',
5291
        $until = ''
5292
    ) {
5293
        $userId = (int) $userId;
5294
        $sessionId = (int) $sessionId;
5295
5296
        $trackCourseAccessTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5297
        $whereConditions = [
5298
            'user_id = ? ' => $userId,
5299
            'AND c_id = ? ' => $courseId,
5300
            'AND session_id = ? ' => $sessionId,
5301
        ];
5302
5303
        if (!empty($from) && !empty($until)) {
5304
            $whereConditions["AND (login_course_date >= '?' "] = $from;
5305
            $whereConditions["AND logout_course_date <= DATE_ADD('?', INTERVAL 1 DAY)) "] = $until;
5306
        }
5307
5308
        $trackResult = Database::select(
5309
            'SUM(UNIX_TIMESTAMP(logout_course_date) - UNIX_TIMESTAMP(login_course_date)) as total_time',
5310
            $trackCourseAccessTable,
5311
            [
5312
                'where' => $whereConditions,
5313
            ],
5314
            'first'
5315
        );
5316
5317
        if (false != $trackResult) {
5318
            return $trackResult['total_time'] ? $trackResult['total_time'] : 0;
5319
        }
5320
5321
        return 0;
5322
    }
5323
5324
    /**
5325
     * Get the boss user ID from a followed user id.
5326
     *
5327
     * @param $userId
5328
     *
5329
     * @return bool
5330
     */
5331
    public static function getFirstStudentBoss($userId)
5332
    {
5333
        $userId = (int) $userId;
5334
        if ($userId > 0) {
5335
            $userRelTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5336
            $row = Database::select(
5337
                'DISTINCT friend_user_id AS boss_id',
5338
                $userRelTable,
5339
                [
5340
                    'where' => [
5341
                        'user_id = ? AND relation_type = ? LIMIT 1' => [
5342
                            $userId,
5343
                            USER_RELATION_TYPE_BOSS,
5344
                        ],
5345
                    ],
5346
                ]
5347
            );
5348
            if (!empty($row)) {
5349
                return $row[0]['boss_id'];
5350
            }
5351
        }
5352
5353
        return false;
5354
    }
5355
5356
    /**
5357
     * Get the boss user ID from a followed user id.
5358
     *
5359
     * @param int $userId student id
5360
     *
5361
     * @return array
5362
     */
5363
    public static function getStudentBossList($userId)
5364
    {
5365
        $userId = (int) $userId;
5366
5367
        if ($userId > 0) {
5368
            $userRelTable = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
5369
            $result = Database::select(
5370
                'DISTINCT friend_user_id AS boss_id',
5371
                $userRelTable,
5372
                [
5373
                    'where' => [
5374
                        'user_id = ? AND relation_type = ? ' => [
5375
                            $userId,
5376
                            USER_RELATION_TYPE_BOSS,
5377
                        ],
5378
                    ],
5379
                ]
5380
            );
5381
5382
            return $result;
5383
        }
5384
5385
        return [];
5386
    }
5387
5388
    /**
5389
     * @param int $bossId
5390
     * @param int $studentId
5391
     *
5392
     * @return bool
5393
     */
5394
    public static function userIsBossOfStudent($bossId, $studentId)
5395
    {
5396
        $result = false;
5397
        $bossList = self::getStudentBossList($studentId);
5398
        if (!empty($bossList)) {
5399
            $bossList = array_column($bossList, 'boss_id');
5400
            if (in_array($bossId, $bossList)) {
5401
                $result = true;
5402
            }
5403
        }
5404
5405
        return $result;
5406
    }
5407
5408
    /**
5409
     * Displays the name of the user and makes the link to the user profile.
5410
     *
5411
     * @param array $userInfo
5412
     *
5413
     * @return string
5414
     */
5415
    public static function getUserProfileLink($userInfo)
5416
    {
5417
        if (isset($userInfo) && isset($userInfo['user_id'])) {
5418
            return Display::url(
5419
                $userInfo['complete_name_with_username'],
5420
                $userInfo['profile_url']
5421
            );
5422
        }
5423
5424
        return get_lang('Anonymous');
5425
    }
5426
5427
    /**
5428
     * Get users whose name matches $firstname and $lastname.
5429
     *
5430
     * @param string $firstname Firstname to search
5431
     * @param string $lastname  Lastname to search
5432
     *
5433
     * @return array The user list
5434
     */
5435
    public static function getUsersByName($firstname, $lastname)
5436
    {
5437
        $firstname = Database::escape_string($firstname);
5438
        $lastname = Database::escape_string($lastname);
5439
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
5440
5441
        $sql = <<<SQL
5442
            SELECT id, username, lastname, firstname
5443
            FROM $userTable
5444
            WHERE
5445
                firstname LIKE '$firstname%' AND
5446
                lastname LIKE '$lastname%'
5447
SQL;
5448
        $result = Database::query($sql);
5449
        $users = [];
5450
        while ($resultData = Database::fetch_object($result)) {
5451
            $users[] = $resultData;
5452
        }
5453
5454
        return $users;
5455
    }
5456
5457
    /**
5458
     * @param int $optionSelected
5459
     *
5460
     * @return string
5461
     */
5462
    public static function getUserSubscriptionTab($optionSelected = 1)
5463
    {
5464
        $allowAdmin = api_get_setting('allow_user_course_subscription_by_course_admin');
5465
        if (('true' === $allowAdmin && api_is_allowed_to_edit()) ||
5466
            api_is_platform_admin()
5467
        ) {
5468
            $userPath = api_get_path(WEB_CODE_PATH).'user/';
5469
5470
            $headers = [
5471
                [
5472
                    'url' => $userPath.'user.php?'.api_get_cidreq().'&type='.STUDENT,
5473
                    'content' => get_lang('Learners'),
5474
                ],
5475
                [
5476
                    'url' => $userPath.'user.php?'.api_get_cidreq().'&type='.COURSEMANAGER,
5477
                    'content' => get_lang('Trainers'),
5478
                ],
5479
                /*[
5480
                    'url' => $userPath.'subscribe_user.php?'.api_get_cidreq(),
5481
                    'content' => get_lang('Learners'),
5482
                ],
5483
                [
5484
                    'url' => $userPath.'subscribe_user.php?type=teacher&'.api_get_cidreq(),
5485
                    'content' => get_lang('Trainers'),
5486
                ],*/
5487
                [
5488
                    'url' => api_get_path(WEB_CODE_PATH).'group/group.php?'.api_get_cidreq(),
5489
                    'content' => get_lang('Groups'),
5490
                ],
5491
                [
5492
                    'url' => $userPath.'class.php?'.api_get_cidreq(),
5493
                    'content' => get_lang('Classes'),
5494
                ],
5495
            ];
5496
5497
            return Display::tabsOnlyLink($headers, $optionSelected);
5498
        }
5499
5500
        return '';
5501
    }
5502
5503
    /**
5504
     * Make sure this function is protected because it does NOT check password!
5505
     *
5506
     * This function defines globals.
5507
     *
5508
     * @param int  $userId
5509
     * @param bool $checkIfUserCanLoginAs
5510
     *
5511
     * @return bool
5512
     *
5513
     * @author Evie Embrechts
5514
     * @author Yannick Warnier <[email protected]>
5515
     */
5516
    public static function loginAsUser($userId, $checkIfUserCanLoginAs = true)
5517
    {
5518
        $userId = (int) $userId;
5519
        $userInfo = api_get_user_info($userId);
5520
5521
        // Check if the user is allowed to 'login_as'
5522
        $canLoginAs = true;
5523
        if ($checkIfUserCanLoginAs) {
5524
            $canLoginAs = api_can_login_as($userId);
5525
        }
5526
5527
        if (!$canLoginAs || empty($userInfo)) {
5528
            return false;
5529
        }
5530
5531
        if ($userId) {
5532
            $logInfo = [
5533
                'tool' => 'logout',
5534
                'tool_id' => 0,
5535
                'tool_id_detail' => 0,
5536
                'action' => '',
5537
                'info' => 'Change user (login as)',
5538
            ];
5539
            Event::registerLog($logInfo);
0 ignored issues
show
Bug introduced by
The method registerLog() does not exist on Event. ( Ignorable by Annotation )

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

5539
            Event::/** @scrutinizer ignore-call */ 
5540
                   registerLog($logInfo);

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

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

Loading history...
5540
5541
            // Logout the current user
5542
            self::loginDelete(api_get_user_id());
5543
5544
            return true;
5545
5546
            Session::erase('_user');
0 ignored issues
show
Unused Code introduced by
ChamiloSession::erase('_user') is not reachable.

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

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

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

    return false;
}

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

Loading history...
5547
            Session::erase('is_platformAdmin');
5548
            Session::erase('is_allowedCreateCourse');
5549
            Session::erase('_uid');
5550
5551
            // Cleaning session variables
5552
            $_user['firstName'] = $userInfo['firstname'];
5553
            $_user['lastName'] = $userInfo['lastname'];
5554
            $_user['mail'] = $userInfo['email'];
5555
            $_user['official_code'] = $userInfo['official_code'];
5556
            $_user['picture_uri'] = $userInfo['picture_uri'];
5557
            $_user['user_id'] = $userId;
5558
            $_user['id'] = $userId;
5559
            $_user['status'] = $userInfo['status'];
5560
5561
            // Filling session variables with new data
5562
            Session::write('_uid', $userId);
5563
            Session::write('_user', $userInfo);
5564
            Session::write('is_platformAdmin', (bool) self::is_admin($userId));
5565
            Session::write('is_allowedCreateCourse', 1 == $userInfo['status']);
5566
            // will be useful later to know if the user is actually an admin or not (example reporting)
5567
            Session::write('login_as', true);
5568
            $logInfo = [
5569
                'tool' => 'login',
5570
                'tool_id' => 0,
5571
                'tool_id_detail' => 0,
5572
                'info' => $userId,
5573
            ];
5574
            Event::registerLog($logInfo);
5575
5576
            return true;
5577
        }
5578
5579
        return false;
5580
    }
5581
5582
    /**
5583
     * Remove all login records from the track_e_online stats table,
5584
     * for the given user ID.
5585
     *
5586
     * @param int $userId User ID
5587
     */
5588
    public static function loginDelete($userId)
5589
    {
5590
        $online_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ONLINE);
5591
        $userId = (int) $userId;
5592
        $query = "DELETE FROM $online_table WHERE login_user_id = $userId";
5593
        Database::query($query);
5594
    }
5595
5596
    /**
5597
     * Login as first admin user registered in the platform.
5598
     *
5599
     * @return array
5600
     */
5601
    public static function logInAsFirstAdmin()
5602
    {
5603
        $adminList = self::get_all_administrators();
5604
5605
        if (!empty($adminList)) {
5606
            $userInfo = current($adminList);
5607
            if (!empty($userInfo)) {
5608
                $result = self::loginAsUser($userInfo['user_id'], false);
5609
                if ($result && api_is_platform_admin()) {
5610
                    return api_get_user_info();
0 ignored issues
show
Bug Best Practice introduced by
The expression return api_get_user_info() could also return false which is incompatible with the documented return type array. Did you maybe forget to handle an error condition?

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

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

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

Loading history...
6348
        $email,
6349
        $s = 80,
6350
        $d = 'mm',
6351
        $r = 'g',
6352
        $img = false,
6353
        $atts = []
6354
    ) {
6355
        $url = 'http://www.gravatar.com/avatar/';
6356
        if (!empty($_SERVER['HTTPS'])) {
6357
            $url = 'https://secure.gravatar.com/avatar/';
6358
        }
6359
        $url .= md5(strtolower(trim($email)));
6360
        $url .= "?s=$s&d=$d&r=$r";
6361
        if ($img) {
6362
            $url = '<img src="'.$url.'"';
6363
            foreach ($atts as $key => $val) {
6364
                $url .= ' '.$key.'="'.$val.'"';
6365
            }
6366
            $url .= ' />';
6367
        }
6368
6369
        return $url;
6370
    }
6371
}
6372