Completed
Push — master ( 4f5e08...58c386 )
by Adrien
05:49
created

User::bookingRemoved()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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