Passed
Push — master ( 9c7250...52994a )
by Adrien
05:50
created

User::getGlobalPermissions()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 27
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 17
nc 3
nop 0
dl 0
loc 27
ccs 15
cts 15
cp 1
crap 3
rs 9.7
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Application\Model;
6
7
use Application\Acl\Acl;
8
use Application\Api\Exception;
9
use Application\ORM\Query\Filter\AclFilter;
10
use Application\Traits\HasDoorAccess;
11
use Application\Traits\HasName;
12
use Application\Traits\HasResponsible;
13
use Application\Utility;
14
use Cake\Chronos\Chronos;
15
use Cake\Chronos\Date;
16
use Doctrine\Common\Collections\ArrayCollection;
17
use Doctrine\Common\Collections\Collection;
18
use Doctrine\ORM\Mapping as ORM;
19
use GraphQL\Doctrine\Annotation as API;
20
21
/**
22
 * User
23
 *
24
 * @ORM\Entity(repositoryClass="Application\Repository\UserRepository")
25
 */
26
class User extends AbstractModel
27
{
28
    const ROLE_ANONYMOUS = 'anonymous';
29
    const ROLE_MEMBER = 'member';
30
    const ROLE_ADMINISTRATOR = 'administrator';
31
32
    use HasName;
33
    use HasResponsible;
34
    use HasDoorAccess;
35
36
    /**
37
     * @var User
38
     */
39
    private static $currentUser;
40
41
    /**
42
     * Set currently logged in user
43
     * WARNING: this method should only be called from \Application\Authentication\AuthenticationListener
44
     *
45
     * @param \Application\Model\User $user
46
     */
47 24
    public static function setCurrent(?self $user): void
48
    {
49 24
        self::$currentUser = $user;
50
51
        // Initalize ACL filter with current user if a logged in one exists
52 24
        _em()->getFilters()->getFilter(AclFilter::class)->setUser($user);
53 24
    }
54
55
    /**
56
     * Returns currently logged user or null
57
     *
58
     * @return null|self
59
     */
60 19
    public static function getCurrent(): ?self
61
    {
62 19
        return self::$currentUser;
63
    }
64
65
    /**
66
     * @var string
67
     *
68
     * @ORM\Column(type="string", length=50, unique=true)
69
     */
70
    private $login;
71
72
    /**
73
     * @var null|string
74
     *
75
     * @ORM\Column(type="string", length=255)
76
     */
77
    private $password;
78
79
    /**
80
     * @var string
81
     * @ORM\Column(type="string", length=191)
82
     */
83
    private $email;
84
85
    /**
86
     * @var string
87
     * @ORM\Column(type="UserRole", options={"default" = User::ROLE_MEMBER})
88
     */
89
    private $role = self::ROLE_MEMBER;
90
91
    /**
92
     * @var Chronos
93
     * @ORM\Column(type="datetime", nullable=true)
94
     */
95
    private $activeUntil;
96
97
    /**
98
     * @var string
99
     * @ORM\Column(type="string", length=25, options={"default" = ""})
100
     */
101
    private $phone = '';
102
103
    /**
104
     * @var null|Date
105
     * @ORM\Column(type="date", nullable=true)
106
     */
107
    private $birthday;
108
109
    /**
110
     * @var Collection
111
     * @ORM\OneToMany(targetEntity="Booking", mappedBy="responsible")
112
     */
113
    private $bookings;
114
115
    /**
116
     * @var Collection
117
     * @ORM\ManyToMany(targetEntity="License", mappedBy="users")
118
     */
119
    private $licenses;
120
121
    /**
122
     * @var Collection
123
     * @ORM\ManyToMany(targetEntity="UserTag", mappedBy="users")
124
     */
125
    private $tags;
126
127
    /**
128
     * Constructor
129
     *
130
     * @param string $role role for new user
131
     */
132 17
    public function __construct(string $role = self::ROLE_MEMBER)
133
    {
134 17
        $this->role = $role;
135 17
        $this->bookings = new ArrayCollection();
136 17
        $this->licenses = new ArrayCollection();
137 17
        $this->tags = new ArrayCollection();
138 17
    }
139
140
    /**
141
     * Set login (eg: johndoe)
142
     *
143
     * @API\Input(type="Application\Api\Scalar\LoginType")
144
     *
145
     * @param string $login
146
     */
147
    public function setLogin(string $login): void
148
    {
149
        $this->login = $login;
150
    }
151
152
    /**
153
     * Get login (eg: johndoe)
154
     *
155
     * @API\Field(type="Application\Api\Scalar\LoginType")
156
     *
157
     * @return string
158
     */
159 1
    public function getLogin(): string
160
    {
161 1
        return $this->login;
162
    }
163
164
    /**
165
     * Encrypt and change the user password
166
     *
167
     * @param string $password
168
     */
169 3
    public function setPassword(string $password): void
170
    {
171
        // Ignore empty password that could be sent "by mistake" by the client
172
        // when agreeing to terms
173 3
        if ($password === '') {
174 1
            return;
175
        }
176
177 3
        $this->password = password_hash($password, PASSWORD_DEFAULT);
178 3
    }
179
180
    /**
181
     * Returns the hashed password
182
     *
183
     * @API\Exclude
184
     *
185
     * @return null|string
186
     */
187 3
    public function getPassword(): ?string
188
    {
189 3
        return $this->password;
190
    }
191
192
    /**
193
     * Set email
194
     *
195
     * @API\Input(type="Email")
196
     *
197
     * @param string $email
198
     */
199 1
    public function setEmail(string $email): void
200
    {
201 1
        $this->email = $email;
202 1
    }
203
204
    /**
205
     * Get email
206
     *
207
     * @API\Field(type="Email")
208
     *
209
     * @return string
210
     */
211 1
    public function getEmail(): string
212
    {
213 1
        return $this->email;
214
    }
215
216
    /**
217
     * Returns whether the user is administrator and thus have can do anything.
218
     *
219
     * @API\Field(type="Application\Api\Enum\UserRoleType")
220
     */
221 14
    public function getRole(): string
222
    {
223 14
        return $this->role;
224
    }
225
226
    /**
227
     * Sets the user role
228
     *
229
     * The current user is allowed to promote another user up to the same role as himself. So
230
     * a Senior can promote a Student to Senior. Or an Admin can promote a Junior to Admin.
231
     *
232
     * But the current user is **not** allowed to demote a user who has a higher role than himself.
233
     * That means that a Senior cannot demote an Admin to Student.
234
     *
235
     * @param string $role
236
     */
237 7
    public function setRole(string $role): void
238
    {
239 7
        if ($role === $this->role) {
240 2
            return;
241
        }
242
243 5
        $currentRole = self::getCurrent() ? self::getCurrent()->getRole() : self::ROLE_ANONYMOUS;
244
        $orderedRoles = [
245 5
            self::ROLE_ANONYMOUS,
246 5
            self::ROLE_MEMBER,
247 5
            self::ROLE_ADMINISTRATOR,
248
        ];
249
250 5
        $newFound = false;
251 5
        $oldFound = false;
252 5
        foreach ($orderedRoles as $r) {
253 5
            if ($r === $this->role) {
254 3
                $oldFound = true;
255
            }
256 5
            if ($r === $role) {
257 2
                $newFound = true;
258
            }
259
260 5
            if ($r === $currentRole) {
261 5
                break;
262
            }
263
        }
264
265 5
        if (!$newFound || !$oldFound) {
266 3
            throw new Exception($currentRole . ' is not allowed to change role to ' . $role);
267
        }
268
269 2
        $this->role = $role;
270 2
    }
271
272
    /**
273
     * The date until the user is active. Or `null` if there is not limit in time
274
     *
275
     * @return null|Chronos
276
     */
277 5
    public function getActiveUntil(): ?Chronos
278
    {
279 5
        return $this->activeUntil;
280
    }
281
282
    /**
283
     * The date until the user is active. Or `null` if there is not limit in time
284
     *
285
     * @param null|Chronos $activeUntil
286
     */
287 2
    public function setActiveUntil(?Chronos $activeUntil): void
288
    {
289 2
        $this->activeUntil = $activeUntil;
290 2
    }
291
292
    /**
293
     * Get a list of global permissions for this user
294
     *
295
     * @API\Field(type="GlobalPermissionsList")
296
     *
297
     * @return array
298
     */
299 3
    public function getGlobalPermissions(): array
300
    {
301 3
        $acl = new Acl();
302
        $types = [
303 3
            Country::class,
304
            License::class,
305
            self::class,
306
        ];
307
308 3
        $permissions = ['create'];
309 3
        $result = [];
310
311 3
        $previousUser = self::getCurrent();
312 3
        self::setCurrent($this);
313 3
        foreach ($types as $type) {
314 3
            $instance = new $type();
315 3
            $sh = lcfirst(Utility::getShortClassName($instance));
316 3
            $result[$sh] = [];
317
318 3
            foreach ($permissions as $p) {
319 3
                $result[$sh][$p] = $acl->isCurrentUserAllowed($instance, $p);
320
            }
321
        }
322
323 3
        self::setCurrent($previousUser);
324
325 3
        return $result;
326
    }
327
328
    /**
329
     * @return string
330
     */
331
    public function getPhone(): string
332
    {
333
        return $this->phone;
334
    }
335
336
    /**
337
     * @param string $phone
338
     */
339
    public function setPhone(string $phone): void
340
    {
341
        $this->phone = $phone;
342
    }
343
344
    /**
345
     * @return null|Date
346
     */
347
    public function getBirthday(): ?Date
348
    {
349
        return $this->birthday;
350
    }
351
352
    /**
353
     * @param null|Date $birthday
354
     */
355
    public function setBirthday(?Date $birthday): void
356
    {
357
        $this->birthday = $birthday;
358
    }
359
360
    /**
361
     * Get bookings
362
     *
363
     * @return Collection
364
     */
365
    public function getBookings(): Collection
366
    {
367
        return $this->bookings;
368
    }
369
370
    /**
371
     * Notify the user that it has a new booking.
372
     * This should only be called by Booking::setResponsible()
373
     *
374
     * @param Booking $booking
375
     */
376
    public function bookingAdded(Booking $booking): void
377
    {
378
        $this->bookings->add($booking);
379
    }
380
381
    /**
382
     * @return Collection
383
     */
384
    public function getLicenses(): Collection
385
    {
386
        return $this->licenses;
387
    }
388
389
    /**
390
     * @return Collection
391
     */
392
    public function getTags(): Collection
393
    {
394
        return $this->tags;
395
    }
396
}
397