Passed
Push — master ( a8b983...5b3176 )
by Adrien
10:48
created

User::setRole()   B

Complexity

Conditions 9
Paths 37

Size

Total Lines 34
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 9

Importance

Changes 0
Metric Value
cc 9
eloc 20
nc 37
nop 1
dl 0
loc 34
ccs 20
cts 20
cp 1
crap 9
rs 8.0555
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Application\Model;
6
7
use Application\DBAL\Types\MembershipType;
8
use Application\Repository\LogRepository;
9
use Application\Repository\UserRepository;
10
use Application\Traits\HasAddress;
11
use Application\Traits\HasSubscriptionLastReview;
12
use Application\Traits\IsImportable;
13
use Cake\Chronos\Chronos;
14
use Doctrine\Common\Collections\ArrayCollection;
15
use Doctrine\Common\Collections\Collection;
16
use Doctrine\ORM\Mapping as ORM;
17
use Ecodev\Felix\Api\Exception;
18
use Ecodev\Felix\Model\CurrentUser;
19
use Ecodev\Felix\Model\Traits\HasPassword;
20
use GraphQL\Doctrine\Annotation as API;
21
22
/**
23
 * User
24
 *
25
 * @ORM\Entity(repositoryClass="Application\Repository\UserRepository")
26
 * @ORM\HasLifecycleCallbacks
27
 * @ORM\AssociationOverrides({
28
 *     @ORM\AssociationOverride(name="owner", inversedBy="users")
29
 * })
30
 */
31
class User extends AbstractModel implements \Ecodev\Felix\Model\HasPassword, \Ecodev\Felix\Model\User
32
{
33
    const ROLE_ANONYMOUS = 'anonymous';
34
    const ROLE_MEMBER = 'member';
35
    const ROLE_FACILITATOR = 'facilitator';
36
    const ROLE_ADMINISTRATOR = 'administrator';
37
38
    use HasAddress;
39
    use HasSubscriptionLastReview;
40
    use HasPassword;
41
    use IsImportable;
42
43
    /**
44
     * @var User
45
     */
46
    private static $currentUser;
47
48
    /**
49
     * Set currently logged in user
50
     * WARNING: this method should only be called from \Application\Authentication\AuthenticationListener
51
     *
52
     * @param \Application\Model\User $user
53
     */
54 130
    public static function setCurrent(?self $user): void
55
    {
56 130
        self::$currentUser = $user;
57
58
        // Initalize ACL filter with current user if a logged in one exists
59
        /** @var UserRepository $userRepository */
60 130
        $userRepository = _em()->getRepository(self::class);
61 130
        $aclFilter = $userRepository->getAclFilter();
62 130
        $aclFilter->setUser($user);
63
64 130
        CurrentUser::set($user);
65 130
    }
66
67
    /**
68
     * Returns currently logged user or null
69
     */
70 73
    public static function getCurrent(): ?self
71
    {
72 73
        return self::$currentUser;
73
    }
74
75
    /**
76
     * @var string
77
     * @ORM\Column(type="string", length=191, unique=true)
78
     */
79
    private $email;
80
81
    /**
82
     * @var string
83
     * @ORM\Column(type="UserRole", options={"default" = User::ROLE_MEMBER})
84
     */
85
    private $role = self::ROLE_MEMBER;
86
87
    /**
88
     * @var string
89
     * @ORM\Column(type="Membership", options={"default" = MembershipType::NONE})
90
     */
91
    private $membership = MembershipType::NONE;
92
93
    /**
94
     * @var null|string
95
     * @ORM\Column(type="ProductType", nullable=true)
96
     */
97
    private $subscriptionType;
98
99
    /**
100
     * @var string
101
     * @ORM\Column(type="string", length=25, options={"default" = ""})
102
     */
103
    private $phone = '';
104
105
    /**
106
     * @var bool
107
     * @ORM\Column(type="boolean", options={"default" = 0})
108
     */
109
    private $webTemporaryAccess = false;
110
111
    /**
112
     * @var Collection
113
     * @ORM\ManyToMany(targetEntity="Session", mappedBy="facilitators")
114
     */
115
    private $sessions;
116
117
    /**
118
     * @var Collection
119
     * @ORM\OneToMany(targetEntity="User", mappedBy="owner")
120
     */
121
    private $users;
122
123
    /**
124
     * Constructor
125
     *
126
     * @param string $role role for new user
127
     */
128 14
    public function __construct(string $role = self::ROLE_MEMBER)
129
    {
130 14
        $this->role = $role;
131 14
        $this->sessions = new ArrayCollection();
132 14
        $this->users = new ArrayCollection();
133 14
    }
134
135
    /**
136
     * Get full name
137
     */
138 9
    public function getName(): string
139
    {
140 9
        return implode(' ', array_filter([$this->getFirstName(), $this->getLastName()]));
141
    }
142
143
    /**
144
     * Set email
145
     *
146
     * @API\Input(type="Email")
147
     *
148
     * @param string $email
149
     */
150 4
    public function setEmail(?string $email): void
151
    {
152 4
        $this->email = $email;
153 4
    }
154
155
    /**
156
     * Get email
157
     *
158
     * @API\Field(type="Email")
159
     */
160 14
    public function getEmail(): ?string
161
    {
162 14
        return $this->email;
163
    }
164
165
    /**
166
     * Use email as technical identifier of user
167
     *
168
     * @API\Exclude
169
     */
170 5
    public function getLogin(): ?string
171
    {
172 5
        return $this->getEmail();
173
    }
174
175
    /**
176
     * Returns whether the user is administrator and thus have can do anything.
177
     *
178
     * @API\Field(type="Application\Api\Enum\UserRoleType")
179
     */
180 43
    public function getRole(): string
181
    {
182 43
        return $this->role;
183
    }
184
185
    /**
186
     * Sets the user role
187
     *
188
     * The current user is allowed to promote another user up to the same role as himself. So
189
     * a Responsible can promote a Member to Responsible. Or an Admin can promote a Individual to Admin.
190
     *
191
     * But the current user is **not** allowed to demote a user who has a higher role than himself.
192
     * That means that a Responsible cannot demote an Admin to Individual.
193
     */
194 7
    public function setRole(string $role): void
195
    {
196 7
        if ($role === $this->role) {
197 2
            return;
198
        }
199
200 5
        $currentRole = self::getCurrent() ? self::getCurrent()->getRole() : self::ROLE_ANONYMOUS;
201
        $orderedRoles = [
202 5
            self::ROLE_ANONYMOUS,
203 5
            self::ROLE_MEMBER,
204 5
            self::ROLE_FACILITATOR,
205 5
            self::ROLE_ADMINISTRATOR,
206
        ];
207
208 5
        $newFound = false;
209 5
        $oldFound = false;
210 5
        foreach ($orderedRoles as $r) {
211 5
            if ($r === $this->role) {
212 3
                $oldFound = true;
213
            }
214 5
            if ($r === $role) {
215 2
                $newFound = true;
216
            }
217
218 5
            if ($r === $currentRole) {
219 5
                break;
220
            }
221
        }
222
223 5
        if (!$newFound || !$oldFound) {
224 3
            throw new Exception($currentRole . ' is not allowed to change role from ' . $this->role . ' to ' . $role);
225
        }
226
227 2
        $this->role = $role;
228 2
    }
229
230 1
    public function initialize(): void
231
    {
232 1
        $this->role = self::ROLE_MEMBER; // Bypass security
233 1
    }
234
235 1
    public function getPhone(): string
236
    {
237 1
        return $this->phone;
238
    }
239
240
    public function setPhone(string $phone): void
241
    {
242
        $this->phone = $phone;
243
    }
244
245
    public function getSessions(): Collection
246
    {
247
        return $this->sessions;
248
    }
249
250
    /**
251
     * Notify the user that it has a new session.
252
     * This should only be called by Session::addFacilitator()
253
     */
254
    public function sessionAdded(Session $session): void
255
    {
256
        $this->sessions->add($session);
257
    }
258
259
    /**
260
     * Notify the user that a session was removed.
261
     * This should only be called by Session::removeFacilitator()
262
     */
263
    public function sessionRemoved(Session $session): void
264
    {
265
        $this->sessions->removeElement($session);
266
    }
267
268 1
    public function getMembership(): string
269
    {
270 1
        return $this->membership;
271
    }
272
273
    /**
274
     * @API\Exclude
275
     */
276
    public function setMembership(string $membership): void
277
    {
278
        $this->membership = $membership;
279
    }
280
281 2
    public function getWebTemporaryAccess(): bool
282
    {
283 2
        return $this->webTemporaryAccess;
284
    }
285
286
    /**
287
     * @API\Exclude
288
     */
289 1
    public function setWebTemporaryAccess(bool $webTemporaryAccess): void
290
    {
291 1
        $this->webTemporaryAccess = $webTemporaryAccess;
292 1
    }
293
294
    /**
295
     * Get the first login date
296
     */
297
    public function getFirstLogin(): ?Chronos
298
    {
299
        /** @var LogRepository $logRepository */
300
        $logRepository = _em()->getRepository(Log::class);
301
302
        return $logRepository->getLoginDate($this, true);
303
    }
304
305
    /**
306
     * Get the last login date
307
     */
308
    public function getLastLogin(): ?Chronos
309
    {
310
        /** @var LogRepository $logRepository */
311
        $logRepository = _em()->getRepository(Log::class);
312
313
        return $logRepository->getLoginDate($this, false);
314
    }
315
316
    /**
317
     * Override parent to prevents users created from administration to be family of the administrator
318
     *
319
     * The owner must be explicitly set for all users.
320
     */
321 3
    protected function getOwnerForCreation(): ?self
322
    {
323 3
        return null;
324
    }
325
326
    /**
327
     * Set subscription type
328
     *
329
     * @API\Exclude
330
     */
331
    public function setSubscriptionType(?string $subscriptionType): void
332
    {
333
        $this->subscriptionType = $subscriptionType;
334
    }
335
336
    /**
337
     * Get subscription type
338
     *
339
     * @API\Field(type="?ProductType")
340
     */
341 2
    public function getSubscriptionType(): ?string
342
    {
343 2
        return $this->subscriptionType;
344
    }
345
}
346