Passed
Push — master ( 414a0d...d40d17 )
by Julito
08:35
created

UserRepository::getUserPendingInvitations()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 12
nc 1
nop 1
dl 0
loc 17
rs 9.8666
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/* For licensing terms, see /license.txt */
6
7
namespace Chamilo\CoreBundle\Repository\Node;
8
9
use Chamilo\CoreBundle\Entity\AccessUrl;
10
use Chamilo\CoreBundle\Entity\Course;
11
use Chamilo\CoreBundle\Entity\Message;
12
use Chamilo\CoreBundle\Entity\ResourceNode;
13
use Chamilo\CoreBundle\Entity\Session;
14
use Chamilo\CoreBundle\Entity\TrackELogin;
15
use Chamilo\CoreBundle\Entity\TrackEOnline;
16
use Chamilo\CoreBundle\Entity\User;
17
use Chamilo\CoreBundle\Entity\UserRelUser;
18
use Chamilo\CoreBundle\Repository\ResourceRepository;
19
use Datetime;
20
use Doctrine\Common\Collections\Collection;
21
use Doctrine\Common\Collections\Criteria;
22
use Doctrine\DBAL\Types\Types;
23
use Doctrine\ORM\Query\Expr\Join;
24
use Doctrine\ORM\QueryBuilder;
25
use Doctrine\Persistence\ManagerRegistry;
26
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
27
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
28
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
29
use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;
30
31
class UserRepository extends ResourceRepository implements PasswordUpgraderInterface
32
{
33
    protected ?UserPasswordHasherInterface $hasher = null;
34
35
    public function __construct(ManagerRegistry $registry)
36
    {
37
        parent::__construct($registry, User::class);
38
    }
39
40
    public function loadUserByIdentifier(string $identifier): ?User
41
    {
42
        return $this->findOneBy([
43
            'username' => $identifier,
44
        ]);
45
    }
46
47
    public function setHasher(UserPasswordHasherInterface $hasher): void
48
    {
49
        $this->hasher = $hasher;
50
    }
51
52
    public function createUser(): User
53
    {
54
        return new User();
55
    }
56
57
    public function updateUser(User $user, bool $andFlush = true): void
58
    {
59
        $this->updateCanonicalFields($user);
60
        $this->updatePassword($user);
61
        $this->getEntityManager()->persist($user);
62
        if ($andFlush) {
63
            $this->getEntityManager()->flush();
64
        }
65
    }
66
67
    public function canonicalize(string $string): string
68
    {
69
        $encoding = mb_detect_encoding($string, mb_detect_order(), true);
70
71
        return $encoding
72
            ? mb_convert_case($string, MB_CASE_LOWER, $encoding)
73
            : mb_convert_case($string, MB_CASE_LOWER);
74
    }
75
76
    public function updateCanonicalFields(User $user): void
77
    {
78
        $user->setUsernameCanonical($this->canonicalize($user->getUsername()));
79
        $user->setEmailCanonical($this->canonicalize($user->getEmail()));
80
    }
81
82
    public function updatePassword(User $user): void
83
    {
84
        $password = (string) $user->getPlainPassword();
85
        if ('' !== $password) {
86
            $password = $this->hasher->hashPassword($user, $password);
0 ignored issues
show
Bug introduced by
The method hashPassword() does not exist on null. ( Ignorable by Annotation )

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

86
            /** @scrutinizer ignore-call */ 
87
            $password = $this->hasher->hashPassword($user, $password);

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...
87
            $user->setPassword($password);
88
            $user->eraseCredentials();
89
        }
90
    }
91
92
    public function upgradePassword(PasswordAuthenticatedUserInterface $user, string $newHashedPassword): void
93
    {
94
        /** @var User $user */
95
        $user->setPassword($newHashedPassword);
96
        $this->getEntityManager()->persist($user);
97
        $this->getEntityManager()->flush();
98
    }
99
100
    public function getRootUser(): User
101
    {
102
        $qb = $this->createQueryBuilder('u');
103
        $qb
104
            ->innerJoin(
105
                'u.resourceNode',
106
                'r'
107
            )
108
        ;
109
        $qb
110
            ->where('r.creator = u')
111
            ->andWhere('r.parent IS NULL')
112
            ->getFirstResult()
113
        ;
114
115
        $rootUser = $qb->getQuery()->getSingleResult();
116
117
        if (null === $rootUser) {
118
            throw new UserNotFoundException('Root user not found');
119
        }
120
121
        return $rootUser;
122
    }
123
124
    public function deleteUser(User $user): void
125
    {
126
        $em = $this->getEntityManager();
127
        $type = $user->getResourceNode()->getResourceType();
128
        $rootUser = $this->getRootUser();
129
130
        // User children will be set to the root user.
131
        $criteria = Criteria::create()->where(Criteria::expr()->eq('resourceType', $type));
132
        $userNodeCreatedList = $user->getResourceNodes()->matching($criteria);
133
        /** @var ResourceNode $userCreated */
134
        foreach ($userNodeCreatedList as $userCreated) {
135
            $userCreated->setCreator($rootUser);
136
        }
137
138
        $em->remove($user->getResourceNode());
139
140
        foreach ($user->getGroups() as $group) {
141
            $user->removeGroup($group);
142
        }
143
144
        $em->remove($user);
145
        $em->flush();
146
    }
147
148
    public function addUserToResourceNode(int $userId, int $creatorId): ResourceNode
149
    {
150
        /** @var User $user */
151
        $user = $this->find($userId);
152
        $creator = $this->find($creatorId);
153
154
        $resourceNode = (new ResourceNode())
155
            ->setTitle($user->getUsername())
156
            ->setCreator($creator)
157
            ->setResourceType($this->getResourceType())
158
            //->setParent($resourceNode)
159
        ;
160
161
        $user->setResourceNode($resourceNode);
162
163
        $this->getEntityManager()->persist($resourceNode);
164
        $this->getEntityManager()->persist($user);
165
166
        return $resourceNode;
167
    }
168
169
    public function addRoleListQueryBuilder(array $roleList, QueryBuilder $qb = null): QueryBuilder
170
    {
171
        $qb = $this->getOrCreateQueryBuilder($qb, 'u');
172
        if (!empty($roleList)) {
173
            $qb
174
                ->andWhere('u.roles IN (:roles)')
175
                ->setParameter('roles', $roleList, Types::ARRAY)
176
            ;
177
        }
178
179
        return $qb;
180
    }
181
182
    public function findByUsername(string $username): ?User
183
    {
184
        $user = $this->findOneBy([
185
            'username' => $username,
186
        ]);
187
188
        if (null === $user) {
189
            throw new UserNotFoundException(sprintf("User with id '%s' not found.", $username));
190
        }
191
192
        return $user;
193
    }
194
195
    /**
196
     * Get a filtered list of user by role and (optionally) access url.
197
     *
198
     * @param string $keyword     The query to filter
199
     * @param int    $accessUrlId The access URL ID
200
     *
201
     * @return User[]
202
     */
203
    public function findByRole(string $role, string $keyword, int $accessUrlId = 0)
204
    {
205
        $qb = $this->createQueryBuilder('u');
206
207
        $this->addActiveAndNotAnonUserQueryBuilder($qb);
208
        $this->addAccessUrlQueryBuilder($accessUrlId, $qb);
209
        $this->addRoleQueryBuilder($role, $qb);
210
        $this->addSearchByKeywordQueryBuilder($keyword, $qb);
211
212
        return $qb->getQuery()->getResult();
213
    }
214
215
    /**
216
     * Get course user relationship based in the course_rel_user table.
217
     *
218
     * @return Course[]
219
     */
220
    public function getCourses(User $user, AccessUrl $url, int $status, string $keyword = '')
221
    {
222
        $qb = $this->createQueryBuilder('u');
223
224
        $qb
225
            //->select('DISTINCT course')
226
            ->innerJoin('u.courses', 'courseRelUser')
227
            ->innerJoin('courseRelUser.course', 'course')
228
            ->innerJoin('course.urls', 'accessUrlRelCourse')
229
            ->innerJoin('accessUrlRelCourse.url', 'url')
230
            ->where('url = :url')
231
            ->andWhere('courseRelUser.user = :user')
232
            ->andWhere('courseRelUser.status = :status')
233
            ->setParameters(
234
                [
235
                    'user' => $user,
236
                    'url' => $url,
237
                    'status' => $status,
238
                ]
239
            )
240
        //    ->addSelect('courseRelUser')
241
        ;
242
243
        if (!empty($keyword)) {
244
            $qb
245
                ->andWhere('course.title like = :keyword OR course.code like = :keyword')
246
                ->setParameter('keyword', $keyword)
247
            ;
248
        }
249
250
        $qb->orderBy('course.title', Criteria::DESC);
251
252
        $query = $qb->getQuery();
253
254
        return $query->getResult();
255
    }
256
257
    /*
258
    public function getTeachers()
259
    {
260
        $queryBuilder = $this->repository->createQueryBuilder('u');
261
262
        // Selecting course info.
263
        $queryBuilder
264
            ->select('u')
265
            ->where('u.groups.id = :groupId')
266
            ->setParameter('groupId', 1);
267
268
        $query = $queryBuilder->getQuery();
269
270
        return $query->execute();
271
    }*/
272
273
    /*public function getUsers($group)
274
    {
275
        $queryBuilder = $this->repository->createQueryBuilder('u');
276
277
        // Selecting course info.
278
        $queryBuilder
279
            ->select('u')
280
            ->where('u.groups = :groupId')
281
            ->setParameter('groupId', $group);
282
283
        $query = $queryBuilder->getQuery();
284
285
        return $query->execute();
286
    }*/
287
288
    /**
289
     * Get the coaches for a course within a session.
290
     *
291
     * @return Collection|array
292
     */
293
    public function getCoachesForSessionCourse(Session $session, Course $course)
294
    {
295
        $qb = $this->createQueryBuilder('u');
296
297
        $qb->select('u')
298
            ->innerJoin(
299
                'ChamiloCoreBundle:SessionRelCourseRelUser',
300
                'scu',
301
                Join::WITH,
302
                'scu.user = u'
303
            )
304
            ->where(
305
                $qb->expr()->andX(
306
                    $qb->expr()->eq('scu.session', $session->getId()),
307
                    $qb->expr()->eq('scu.course', $course->getId()),
308
                    $qb->expr()->eq('scu.status', Session::COURSE_COACH)
309
                )
310
            )
311
        ;
312
313
        return $qb->getQuery()->getResult();
314
    }
315
316
    /**
317
     * Get course user relationship based in the course_rel_user table.
318
     *
319
     * @return array
320
     */
321
    /*public function getCourses(User $user)
322
    {
323
        $qb = $this->createQueryBuilder('user');
324
325
        // Selecting course info.
326
        $qb->select('c');
327
328
        // Loading User.
329
        //$qb->from('Chamilo\CoreBundle\Entity\User', 'u');
330
331
        // Selecting course
332
        $qb->innerJoin('Chamilo\CoreBundle\Entity\Course', 'c');
333
334
        //@todo check app settings
335
        //$qb->add('orderBy', 'u.lastname ASC');
336
337
        $wherePart = $qb->expr()->andx();
338
339
        // Get only users subscribed to this course
340
        $wherePart->add($qb->expr()->eq('user.userId', $user->getUserId()));
341
342
        $qb->where($wherePart);
343
        $query = $qb->getQuery();
344
345
        return $query->execute();
346
    }
347
348
    public function getTeachers()
349
    {
350
        $qb = $this->createQueryBuilder('u');
351
352
        // Selecting course info.
353
        $qb
354
            ->select('u')
355
            ->where('u.groups.id = :groupId')
356
            ->setParameter('groupId', 1);
357
358
        $query = $qb->getQuery();
359
360
        return $query->execute();
361
    }*/
362
363
    /*public function getUsers($group)
364
    {
365
        $qb = $this->createQueryBuilder('u');
366
367
        // Selecting course info.
368
        $qb
369
            ->select('u')
370
            ->where('u.groups = :groupId')
371
            ->setParameter('groupId', $group);
372
373
        $query = $qb->getQuery();
374
375
        return $query->execute();
376
    }*/
377
378
    /**
379
     * Get the sessions admins for a user.
380
     *
381
     * @return array
382
     */
383
    public function getSessionAdmins(User $user)
384
    {
385
        $qb = $this->createQueryBuilder('u');
386
        $qb
387
            ->distinct()
388
            ->innerJoin(
389
                'ChamiloCoreBundle:SessionRelUser',
390
                'su',
391
                Join::WITH,
392
                'u = su.user'
393
            )
394
            ->innerJoin(
395
                'ChamiloCoreBundle:SessionRelCourseRelUser',
396
                'scu',
397
                Join::WITH,
398
                'su.session = scu.session'
399
            )
400
            ->where(
401
                $qb->expr()->eq('scu.user', $user->getId())
402
            )
403
            ->andWhere(
404
                $qb->expr()->eq('su.relationType', Session::DRH)
405
            )
406
        ;
407
408
        return $qb->getQuery()->getResult();
409
    }
410
411
    /**
412
     * Get number of users in URL.
413
     *
414
     * @return int
415
     */
416
    public function getCountUsersByUrl(AccessUrl $url)
417
    {
418
        return $this->createQueryBuilder('u')
419
            ->select('COUNT(u)')
420
            ->innerJoin('u.portals', 'p')
421
            ->where('p.url = :url')
422
            ->setParameters([
423
                'url' => $url,
424
            ])
425
            ->getQuery()
426
            ->getSingleScalarResult()
427
        ;
428
    }
429
430
    /**
431
     * Get number of users in URL.
432
     *
433
     * @return int
434
     */
435
    public function getCountTeachersByUrl(AccessUrl $url)
436
    {
437
        $qb = $this->createQueryBuilder('u');
438
439
        $qb
440
            ->select('COUNT(u)')
441
            ->innerJoin('u.portals', 'p')
442
            ->where('p.url = :url')
443
            ->setParameters([
444
                'url' => $url,
445
            ])
446
        ;
447
448
        $this->addRoleListQueryBuilder(['ROLE_TEACHER'], $qb);
449
450
        return (int) $qb->getQuery()->getSingleScalarResult();
451
    }
452
453
    /**
454
     * Find potential users to send a message.
455
     *
456
     * @todo remove  api_is_platform_admin
457
     *
458
     * @param int    $currentUserId The current user ID
459
     * @param string $searchFilter  Optional. The search text to filter the user list
460
     * @param int    $limit         Optional. Sets the maximum number of results to retrieve
461
     *
462
     * @return User[]
463
     */
464
    public function findUsersToSendMessage(int $currentUserId, string $searchFilter = null, int $limit = 10)
465
    {
466
        $allowSendMessageToAllUsers = api_get_setting('allow_send_message_to_all_platform_users');
467
        $accessUrlId = api_get_multiple_access_url() ? api_get_current_access_url_id() : 1;
468
469
        $messageTool = 'true' === api_get_setting('allow_message_tool');
470
        if (!$messageTool) {
471
            return [];
472
        }
473
474
        $qb = $this->createQueryBuilder('u');
475
        $this->addActiveAndNotAnonUserQueryBuilder($qb);
476
        $this->addAccessUrlQueryBuilder($accessUrlId, $qb);
477
478
        $dql = null;
479
        if ('true' === api_get_setting('allow_social_tool')) {
480
            // All users
481
            if ('true' === $allowSendMessageToAllUsers || api_is_platform_admin()) {
482
                $this->addNotCurrentUserQueryBuilder($currentUserId, $qb);
483
            /*$dql = "SELECT DISTINCT U
484
                    FROM ChamiloCoreBundle:User U
485
                    LEFT JOIN ChamiloCoreBundle:AccessUrlRelUser R
486
                    WITH U = R.user
487
                    WHERE
488
                        U.active = 1 AND
489
                        U.status != 6  AND
490
                        U.id != {$currentUserId} AND
491
                        R.url = {$accessUrlId}";*/
492
            } else {
493
                $this->addOnlyMyFriendsQueryBuilder($currentUserId, $qb);
494
                /*$dql = 'SELECT DISTINCT U
495
                        FROM ChamiloCoreBundle:AccessUrlRelUser R, ChamiloCoreBundle:UserRelUser UF
496
                        INNER JOIN ChamiloCoreBundle:User AS U
497
                        WITH UF.friendUserId = U
498
                        WHERE
499
                            U.active = 1 AND
500
                            U.status != 6 AND
501
                            UF.relationType NOT IN('.USER_RELATION_TYPE_DELETED.', '.USER_RELATION_TYPE_RRHH.") AND
502
                            UF.user = {$currentUserId} AND
503
                            UF.friendUserId != {$currentUserId} AND
504
                            U = R.user AND
505
                            R.url = {$accessUrlId}";*/
506
            }
507
        } else {
508
            if ('true' === $allowSendMessageToAllUsers) {
509
                $this->addNotCurrentUserQueryBuilder($currentUserId, $qb);
510
            } else {
511
                return [];
512
            }
513
514
            /*else {
515
                $time_limit = (int) api_get_setting('time_limit_whosonline');
516
                $online_time = time() - ($time_limit * 60);
517
                $limit_date = api_get_utc_datetime($online_time);
518
                $dql = "SELECT DISTINCT U
519
                        FROM ChamiloCoreBundle:User U
520
                        INNER JOIN ChamiloCoreBundle:TrackEOnline T
521
                        WITH U.id = T.loginUserId
522
                        WHERE
523
                          U.active = 1 AND
524
                          T.loginDate >= '".$limit_date."'";
525
            }*/
526
        }
527
528
        if (!empty($searchFilter)) {
529
            $this->addSearchByKeywordQueryBuilder($searchFilter, $qb);
530
        }
531
532
        return $qb->getQuery()->getResult();
533
    }
534
535
    /**
536
     * Get the list of HRM who have assigned this user.
537
     *
538
     * @return User[]
539
     */
540
    public function getAssignedHrmUserList(int $userId, int $urlId)
541
    {
542
        $qb = $this->createQueryBuilder('u');
543
        $this->addAccessUrlQueryBuilder($urlId, $qb);
544
        $this->addActiveAndNotAnonUserQueryBuilder($qb);
545
        $this->addUserRelUserQueryBuilder($userId, UserRelUser::USER_RELATION_TYPE_RRHH, $qb);
546
547
        return $qb->getQuery()->getResult();
548
    }
549
550
    /**
551
     * Get the last login from the track_e_login table.
552
     * This might be different from user.last_login in the case of legacy users
553
     * as user.last_login was only implemented in 1.10 version with a default
554
     * value of NULL (not the last record from track_e_login).
555
     *
556
     * @return null|TrackELogin
557
     */
558
    public function getLastLogin(User $user)
559
    {
560
        $qb = $this->createQueryBuilder('u');
561
562
        return $qb
563
            ->select('l')
564
            ->innerJoin('u.logins', 'l')
565
            ->where(
566
                $qb->expr()->eq('l.user', $user)
567
            )
568
            ->setMaxResults(1)
569
            ->orderBy('u.loginDate', Criteria::DESC)
570
            ->getQuery()
571
            ->getOneOrNullResult()
572
        ;
573
    }
574
575
    public function addAccessUrlQueryBuilder(int $accessUrlId, QueryBuilder $qb = null): QueryBuilder
576
    {
577
        $qb = $this->getOrCreateQueryBuilder($qb, 'u');
578
        $qb
579
            ->innerJoin('u.portals', 'p')
580
            ->andWhere('p.url = :url')
581
            ->setParameter('url', $accessUrlId, Types::INTEGER)
582
        ;
583
584
        return $qb;
585
    }
586
587
    public function addActiveAndNotAnonUserQueryBuilder(QueryBuilder $qb = null): QueryBuilder
588
    {
589
        $qb = $this->getOrCreateQueryBuilder($qb, 'u');
590
        $qb
591
            ->andWhere('u.active = 1')
592
            ->andWhere('u.status <> :status')
593
            ->setParameter('status', User::ANONYMOUS, Types::INTEGER)
594
        ;
595
596
        return $qb;
597
    }
598
599
    public function addExpirationDateQueryBuilder(QueryBuilder $qb = null): QueryBuilder
600
    {
601
        $qb = $this->getOrCreateQueryBuilder($qb, 'u');
602
        $qb
603
            ->andWhere('u.registrationDate IS NULL OR u.registrationDate > :now')
604
            ->setParameter('now', new Datetime(), Types::DATETIME_MUTABLE)
605
        ;
606
607
        return $qb;
608
    }
609
610
    private function addRoleQueryBuilder(string $role, QueryBuilder $qb = null): QueryBuilder
611
    {
612
        $qb = $this->getOrCreateQueryBuilder($qb, 'u');
613
        $qb
614
            ->andWhere('u.roles LIKE :roles')
615
            ->setParameter('roles', '%"'.$role.'"%', Types::STRING)
616
        ;
617
618
        return $qb;
619
    }
620
621
    private function addSearchByKeywordQueryBuilder(string $keyword, QueryBuilder $qb = null): QueryBuilder
622
    {
623
        $qb = $this->getOrCreateQueryBuilder($qb, 'u');
624
        $qb
625
            ->andWhere('
626
                u.firstname LIKE :keyword OR
627
                u.lastname LIKE :keyword OR
628
                u.email LIKE :keyword OR
629
                u.username LIKE :keyword
630
            ')
631
            ->setParameter('keyword', "%$keyword%", Types::STRING)
632
            ->orderBy('u.firstname', Criteria::ASC)
633
        ;
634
635
        return $qb;
636
    }
637
638
    private function addUserRelUserQueryBuilder(int $userId, int $relationType, QueryBuilder $qb = null): QueryBuilder
639
    {
640
        $qb = $this->getOrCreateQueryBuilder($qb, 'u');
641
        $qb->leftJoin('u.friends', 'relations');
642
        $qb
643
            ->andWhere('relations.relationType = :relationType')
644
            ->andWhere('relations.user = :userRelation AND relations.friend <> :userRelation')
645
            ->setParameter('relationType', $relationType)
646
            ->setParameter('userRelation', $userId)
647
        ;
648
649
        return $qb;
650
    }
651
652
    private function addOnlyMyFriendsQueryBuilder(int $userId, QueryBuilder $qb = null): QueryBuilder
653
    {
654
        $qb = $this->getOrCreateQueryBuilder($qb, 'u');
655
        $qb
656
            ->leftJoin('u.friends', 'relations')
657
            ->andWhere(
658
                $qb->expr()->notIn(
659
                    'relations.relationType',
660
                    [UserRelUser::USER_RELATION_TYPE_DELETED, UserRelUser::USER_RELATION_TYPE_RRHH]
661
                )
662
            )
663
            ->andWhere('relations.user = :user AND relations.friend <> :user')
664
            ->setParameter('user', $userId, Types::INTEGER)
665
        ;
666
667
        return $qb;
668
    }
669
670
    private function addNotCurrentUserQueryBuilder(int $userId, QueryBuilder $qb = null): QueryBuilder
671
    {
672
        $qb = $this->getOrCreateQueryBuilder($qb, 'u');
673
        $qb
674
            ->andWhere('u.id <> :id')
675
            ->setParameter('id', $userId, Types::INTEGER)
676
        ;
677
678
        return $qb;
679
    }
680
}
681