Failed Conditions
Push — master ( 931993...be49f9 )
by Sylvain
09:53
created

UserRepository::deleteOldRegistrations()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 20
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 13
c 1
b 0
f 0
dl 0
loc 20
ccs 0
cts 14
cp 0
rs 9.8333
cc 3
nc 3
nop 0
crap 12
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Application\Repository;
6
7
use Application\DBAL\Types\BookingTypeType;
8
use Application\Model\User;
9
use Cake\Chronos\Chronos;
10
use Doctrine\DBAL\Connection;
11
use Ecodev\Felix\Repository\LimitedAccessSubQuery;
12
13
class UserRepository extends AbstractRepository implements LimitedAccessSubQuery
14
{
15
    /**
16
     * Returns pure SQL to get ID of all objects that are accessible to given user.
17
     */
18 34
    public function getAccessibleSubQuery(?\Ecodev\Felix\Model\User $user): string
19
    {
20 34
        if (!$user) {
21 3
            return '-1';
22
        }
23
24 31
        return $this->getAllIdsQuery();
25
    }
26
27
    /**
28
     * Returns the user authenticated by its email and password
29
     */
30 2
    public function getOneByLoginPassword(string $login, string $password): ?User
31
    {
32
        /** @var null|User $user */
33 2
        $user = $this->getOneByLogin($login);
34
35 2
        if (!$user) {
36 1
            return null;
37
        }
38
39
        // Check user status
40 2
        if (!in_array($user->getStatus(), [User::STATUS_ACTIVE, User::STATUS_INACTIVE, User::STATUS_NEW], true)) {
41
            return null;
42
        }
43
44 2
        $hashFromDb = $user->getPassword();
45 2
        $isMd5 = mb_strlen($hashFromDb) === 32 && ctype_xdigit($hashFromDb);
46
47
        // If we found a user and he has a correct MD5 or correct new hash, then return the user
48 2
        if (($isMd5 && md5($password) === $hashFromDb) || password_verify($password, $hashFromDb)) {
49
50
            // Update the hash in DB, if we are still MD5, or if PHP default options changed
51 2
            if ($isMd5 || password_needs_rehash($hashFromDb, PASSWORD_DEFAULT)) {
52 2
                $user->setPassword($password);
53
            }
54 2
            $user->revokeToken();
55 2
            _em()->flush();
56
57 2
            return $user;
58
        }
59
60 1
        return null;
61
    }
62
63
    /**
64
     * Unsecured way to get a user from its ID.
65
     *
66
     * This should only be used in tests or controlled environment.
67
     */
68 20
    public function getOneById(int $id): ?User
69
    {
70 20
        $user = $this->getAclFilter()->runWithoutAcl(function () use ($id) {
71 20
            return $this->findOneById($id);
72 20
        });
73
74 20
        return $user;
75
    }
76
77
    /**
78
     * Unsecured way to get a user from its login.
79
     *
80
     * This should only be used in tests or controlled environment.
81
     */
82 94
    public function getOneByLogin(?string $login): ?User
83
    {
84 94
        $user = $this->getAclFilter()->runWithoutAcl(function () use ($login) {
85 94
            return $this->findOneByLogin($login);
86 94
        });
87
88 94
        return $user;
89
    }
90
91
    /**
92
     * Get all administrators to notify by email
93
     *
94
     * @return User[]
95
     */
96 2
    public function getAllAdministratorsToNotify(): array
97
    {
98 2
        $qb = $this->createQueryBuilder('user')
99 2
            ->andWhere('user.status = :status')
100 2
            ->andWhere('user.role = :role')
101 2
            ->andWhere("user.email IS NOT NULL AND user.email != ''")
102 2
            ->setParameter('status', User::STATUS_ACTIVE)
103 2
            ->setParameter('role', User::ROLE_ADMINISTRATOR);
104
105 2
        $result = $this->getAclFilter()->runWithoutAcl(function () use ($qb) {
106 2
            return $qb->getQuery()->getResult();
107 2
        });
108
109 2
        return $result;
110
    }
111
112 4
    public function getAllToQueueBalanceMessage(bool $onlyNegativeBalance = false): array
113
    {
114 4
        $qb = $this->createQueryBuilder('user')
115 4
            ->addSelect('account')
116 4
            ->addSelect('booking')
117 4
            ->addSelect('bookable')
118 4
            ->join('user.accounts', 'account')
119 4
            ->join('user.bookings', 'booking')
120 4
            ->join('booking.bookable', 'bookable')
121 4
            ->andWhere('user.status != :status')
122 4
            ->andWhere("user.email IS NOT NULL AND user.email != ''")
123 4
            ->andWhere('bookable.bookingType IN (:bookingType)')
124 4
            ->andWhere('bookable.isActive = true')
125 4
            ->andWhere('bookable.periodicPrice != 0')
126 4
            ->setParameter('bookingType', [BookingTypeType::MANDATORY, BookingTypeType::ADMIN_ONLY], Connection::PARAM_STR_ARRAY)
127 4
            ->setParameter('status', User::STATUS_ARCHIVED)
128 4
            ->addOrderBy('user.id')
129 4
            ->addOrderBy('bookable.name');
130
131 4
        if ($onlyNegativeBalance) {
132 2
            $qb->andWhere('account.balance < 0');
133
        }
134
135 4
        $result = $this->getAclFilter()->runWithoutAcl(function () use ($qb) {
136 4
            return $qb->getQuery()->getResult();
137 4
        });
138
139 4
        return $result;
140
    }
141
142
    /**
143
     * Return all users that are family owners (and should have Account)
144
     *
145
     * @return User[]
146
     */
147 1
    public function getAllFamilyOwners(): array
148
    {
149 1
        $qb = $this->createQueryBuilder('user')
150 1
            ->andWhere('user.owner IS NULL OR user.owner = user')
151 1
            ->addOrderBy('user.id');
152
153 1
        return $qb->getQuery()->getResult();
154
    }
155
156
    /**
157
     * Return all users that are not family owners but still have an Account
158
     *
159
     * @return User[]
160
     */
161 1
    public function getAllNonFamilyOwnersWithAccount(): array
162
    {
163 1
        $qb = $this->createQueryBuilder('user')
164 1
            ->join('user.accounts', 'account')
165 1
            ->andWhere('user.owner IS NOT NULL AND user.owner != user')
166 1
            ->addOrderBy('user.id');
167
168 1
        return $qb->getQuery()->getResult();
169
    }
170
171
    /**
172
     * Delete unconfirmed registrations older than a few days (user + account)
173
     *
174
     * @return int number of deleted users
175
     */
176
    public function deleteOldRegistrations(): int
177
    {
178
        $qb = $this->createQueryBuilder('user')
179
            ->addSelect('account')
180
            ->andWhere('user.login IS NULL AND user.creationDate < :creationDate')
181
            ->leftJoin('user.accounts', 'account')
182
            ->setParameter('creationDate', (new Chronos())->subDay(3));
183
184
        $users = $qb->getQuery()->getResult();
185
186
        foreach ($users as $user) {
187
            $account = $user->getAccount();
188
            if ($account) {
189
                _em()->remove($account);
190
            }
191
            _em()->remove($user);
192
        }
193
        _em()->flush();
194
195
        return count($users);
196
    }
197
}
198