Passed
Push — master ( 80e8d3...7b53d1 )
by Daniel
07:04
created

AbstractUser   A

Complexity

Total Complexity 34

Size/Duplication

Total Lines 308
Duplicated Lines 0 %

Test Coverage

Coverage 94.17%

Importance

Changes 0
Metric Value
eloc 85
dl 0
loc 308
ccs 97
cts 103
cp 0.9417
rs 9.68
c 0
b 0
f 0
wmc 34

32 Methods

Rating   Name   Duplication   Size   Complexity  
A getEmailAddress() 0 3 1
A serialize() 0 9 1
A getNewPasswordConfirmationToken() 0 3 1
A getOldPassword() 0 3 1
A setEmailAddressVerified() 0 5 1
A getNewEmailAddress() 0 3 1
A setNewEmailAddress() 0 5 1
A getNewEmailVerificationToken() 0 3 1
A getPlainPassword() 0 3 1
A getRoles() 0 3 1
A setEmailAddress() 0 5 1
A setPlainPassword() 0 9 2
A setEnabled() 0 5 1
A setNewPasswordConfirmationToken() 0 5 1
A isEnabled() 0 3 1
A getPasswordRequestedAt() 0 3 1
A setPasswordRequestedAt() 0 5 1
A getPassword() 0 3 1
A setNewEmailVerificationToken() 0 5 1
A setPassword() 0 5 1
A setUsername() 0 5 1
A setRoles() 0 5 1
A isEmailAddressVerified() 0 3 1
A isPasswordRequestLimitReached() 0 6 2
A getUsername() 0 3 1
A setOldPassword() 0 5 1
A __construct() 0 8 1
A unserialize() 0 14 1
A __toString() 0 3 1
A eraseCredentials() 0 3 1
A createFromPayload() 0 5 1
A getSalt() 0 2 1
1
<?php
2
3
/*
4
 * This file is part of the Silverback API Components Bundle Project
5
 *
6
 * (c) Daniel West <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Silverback\ApiComponentsBundle\Entity\User;
15
16
use ApiPlatform\Core\Annotation\ApiProperty;
17
use DateTime;
18
use Lexik\Bundle\JWTAuthenticationBundle\Security\User\JWTUserInterface;
19
use Ramsey\Uuid\Uuid;
20
use Silverback\ApiComponentsBundle\Annotation as Silverback;
21
use Silverback\ApiComponentsBundle\Entity\Utility\IdTrait;
22
use Silverback\ApiComponentsBundle\Entity\Utility\TimestampedTrait;
23
use Silverback\ApiComponentsBundle\Validator\Constraints as AcbAssert;
24
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
25
use Symfony\Component\Security\Core\User\UserInterface as SymfonyUserInterface;
26
use Symfony\Component\Security\Core\Validator\Constraints\UserPassword;
27
use Symfony\Component\Serializer\Annotation\Groups;
28
use Symfony\Component\Validator\Constraints as Assert;
29
30
/**
31
 * @author Daniel West <[email protected]>
32
 *
33
 * @Silverback\Timestamped
34
 * @UniqueEntity(fields={"username"}, errorPath="username", message="Sorry, that user already exists in the database.")
35
 * @UniqueEntity(fields={"emailAddress"}, errorPath="emailAddress", message="Sorry, that email address already exists in the database.")
36
 * @AcbAssert\NewEmailAddress(groups={"new_email_address", "Default"})
37
 */
38
abstract class AbstractUser implements SymfonyUserInterface, JWTUserInterface
39
{
40
    use IdTrait;
41
    use TimestampedTrait;
42
43
    /**
44
     * @Assert\NotBlank(groups={"Default"})
45
     * @Groups({"User:super_admin", "User:output"})
46
     */
47
    protected ?string $username;
48
49
    /**
50
     * @Assert\NotBlank(groups={"Default"})
51
     * @Assert\Email()
52
     * @Groups({"User:super_admin", "User:output"})
53
     */
54
    protected ?string $emailAddress;
55
56
    /**
57
     * @Groups({"User:super_admin"})
58
     */
59
    protected array $roles;
60
61
    /**
62
     * @Groups({"User:super_admin"})
63
     */
64
    protected bool $enabled;
65
66
    /**
67
     * @ApiProperty(readable=false, writable=false)
68
     */
69
    protected string $password;
70
71
    /**
72
     * @ApiProperty(readable=false)
73
     * @Assert\NotBlank(message="Please enter your desired password", groups={"password_reset", "change_password"})
74
     * @Assert\Length(max="4096", min="6", maxMessage="Your password cannot be over 4096 characters", minMessage="Your password must be more than 6 characters long", groups={"Default", "password_reset", "change_password"})
75
     * @Groups({"User:input"})
76
     */
77
    protected ?string $plainPassword = null;
78
79
    /**
80
     * Random string sent to the user email address in order to verify it.
81
     *
82
     * @ApiProperty(readable=false, writable=false)
83
     */
84
    protected ?string $newPasswordConfirmationToken = null;
85
86
    /**
87
     * @ApiProperty(readable=false, writable=false)
88
     */
89
    protected ?DateTime $passwordRequestedAt = null;
90
91
    /**
92
     * @ApiProperty(readable=false)
93
     * @UserPassword(message="You have not entered your current password correctly. Please try again.", groups={"change_password"})
94
     * @Groups({"User:input"})
95
     */
96
    protected ?string $oldPassword = null;
97
98
    /**
99
     * @ApiProperty(readable=false, writable=false)
100
     */
101
    protected ?DateTime $passwordLastUpdated = null;
102
103
    /**
104
     * @Assert\NotBlank(groups={"new_email_address"})
105
     * @Groups({"User:input", "User:output", "new_email_address"})
106
     */
107
    protected ?string $newEmailAddress = null;
108
109
    /**
110
     * Random string sent to the user's new email address in order to verify it.
111
     *
112
     * @ApiProperty(readable=false, writable=false)
113
     */
114
    protected ?string $newEmailVerificationToken = null;
115
116
    /**
117
     * @ApiProperty(readable=false, writable=false)
118
     */
119
    protected bool $emailAddressVerified = false;
120
121 55
    public function __construct(string $username = '', string $emailAddress = '', bool $emailAddressVerified = false, array $roles = ['ROLE_USER'], string $password = '', bool $enabled = true)
122
    {
123 55
        $this->username = $username;
124 55
        $this->emailAddress = $emailAddress;
125 55
        $this->emailAddressVerified = $emailAddressVerified;
126 55
        $this->roles = $roles;
127 55
        $this->password = $password;
128 55
        $this->enabled = $enabled;
129 55
    }
130
131 28
    public function getUsername(): ?string
132
    {
133 28
        return $this->username;
134
    }
135
136 21
    public function setUsername(?string $username): self
137
    {
138 21
        $this->username = $username;
139
140 21
        return $this;
141
    }
142
143 25
    public function getEmailAddress(): ?string
144
    {
145 25
        return $this->emailAddress;
146
    }
147
148 23
    public function setEmailAddress(?string $emailAddress): self
149
    {
150 23
        $this->emailAddress = $emailAddress;
151
152 23
        return $this;
153
    }
154
155 4
    public function getRoles(): array
156
    {
157 4
        return $this->roles;
158
    }
159
160 1
    public function setRoles(?array $roles): self
161
    {
162 1
        $this->roles = $roles;
163
164 1
        return $this;
165
    }
166
167 6
    public function isEnabled(): bool
168
    {
169 6
        return $this->enabled;
170
    }
171
172 4
    public function setEnabled(bool $enabled): self
173
    {
174 4
        $this->enabled = $enabled;
175
176 4
        return $this;
177
    }
178
179 3
    public function getPassword(): ?string
180
    {
181 3
        return $this->password;
182
    }
183
184 2
    public function setPassword(string $password): self
185
    {
186 2
        $this->password = $password;
187
188 2
        return $this;
189
    }
190
191 6
    public function getPlainPassword(): ?string
192
    {
193 6
        return $this->plainPassword;
194
    }
195
196 1
    public function setPlainPassword(?string $plainPassword): self
197
    {
198 1
        $this->plainPassword = $plainPassword;
199 1
        if ($plainPassword) {
200
            // Needs to update mapped field to trigger update event which will encode the plain password
201 1
            $this->passwordLastUpdated = new \DateTime();
202
        }
203
204 1
        return $this;
205
    }
206
207 3
    public function getNewPasswordConfirmationToken(): ?string
208
    {
209 3
        return $this->newPasswordConfirmationToken;
210
    }
211
212 4
    public function setNewPasswordConfirmationToken(?string $newPasswordConfirmationToken): self
213
    {
214 4
        $this->newPasswordConfirmationToken = $newPasswordConfirmationToken;
215
216 4
        return $this;
217
    }
218
219 2
    public function getPasswordRequestedAt(): ?DateTime
220
    {
221 2
        return $this->passwordRequestedAt;
222
    }
223
224 4
    public function setPasswordRequestedAt(?DateTime $passwordRequestedAt): self
225
    {
226 4
        $this->passwordRequestedAt = $passwordRequestedAt;
227
228 4
        return $this;
229
    }
230
231 1
    public function getOldPassword(): ?string
232
    {
233 1
        return $this->oldPassword;
234
    }
235
236 1
    public function setOldPassword(?string $oldPassword): self
237
    {
238 1
        $this->oldPassword = $oldPassword;
239
240 1
        return $this;
241
    }
242
243 5
    public function getNewEmailAddress(): ?string
244
    {
245 5
        return $this->newEmailAddress;
246
    }
247
248 9
    public function setNewEmailAddress(?string $newEmailAddress): self
249
    {
250 9
        $this->newEmailAddress = $newEmailAddress;
251
252 9
        return $this;
253
    }
254
255 10
    public function getNewEmailVerificationToken(): ?string
256
    {
257 10
        return $this->newEmailVerificationToken;
258
    }
259
260 4
    public function setNewEmailVerificationToken(?string $newEmailVerificationToken): self
261
    {
262 4
        $this->newEmailVerificationToken = $newEmailVerificationToken;
263
264 4
        return $this;
265
    }
266
267 3
    public function isEmailAddressVerified(): bool
268
    {
269 3
        return $this->emailAddressVerified;
270
    }
271
272 9
    public function setEmailAddressVerified(bool $emailAddressVerified): self
273
    {
274 9
        $this->emailAddressVerified = $emailAddressVerified;
275
276 9
        return $this;
277
    }
278
279 1
    public function isPasswordRequestLimitReached($ttl): bool
280
    {
281 1
        $lastRequest = $this->getPasswordRequestedAt();
282
283 1
        return $lastRequest instanceof DateTime &&
284 1
            $lastRequest->getTimestamp() + $ttl > time();
285
    }
286
287
    /** @see \Serializable::serialize() */
288 1
    public function serialize(): string
289
    {
290 1
        return serialize([
291 1
            (string) $this->id,
292 1
            $this->username,
293 1
            $this->emailAddress,
294 1
            $this->password,
295 1
            $this->enabled,
296 1
            $this->roles,
297
        ]);
298
    }
299
300
    /**
301
     * @see \Serializable::unserialize()
302
     */
303 2
    public function unserialize(string $serialized): self
304
    {
305 2
        $id = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $id is dead and can be removed.
Loading history...
306
        [
307
            $id,
308 2
            $this->username,
309 2
            $this->emailAddress,
310 2
            $this->password,
311 2
            $this->enabled,
312 2
            $this->roles,
313 2
        ] = unserialize($serialized, ['allowed_classes' => false]);
314 2
        $this->id = Uuid::fromString($id);
315
316 2
        return $this;
317
    }
318
319
    /**
320
     * Not needed - we use bcrypt.
321
     *
322
     * @ApiProperty(readable=false, writable=false)
323
     */
324
    public function getSalt()
325
    {
326
    }
327
328
    /**
329
     * Remove sensitive data - e.g. plain passwords etc.
330
     */
331 1
    public function eraseCredentials(): void
332
    {
333 1
        $this->plainPassword = null;
334 1
    }
335
336 1
    public function __toString()
337
    {
338 1
        return (string) $this->id;
339
    }
340
341
    public static function createFromPayload($username, array $payload)
342
    {
343
        return new static(
344
            $username,
345
            $payload['roles']
346
        );
347
    }
348
}
349