Passed
Pull Request — master (#72)
by Daniel
05:33
created

AbstractUser::setUsername()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 5
ccs 3
cts 3
cp 1
crap 1
rs 10
c 0
b 0
f 0
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={"User:emailAddress", "Default"})
37
 */
38
abstract class AbstractUser implements SymfonyUserInterface, JWTUserInterface
39
{
40
    use IdTrait;
41
    use TimestampedTrait;
42
43
    /**
44
     * @Assert\NotBlank(groups={"Default"}, message="Please enter a username.")
45
     * @Groups({"User:superAdmin", "User:output"})
46
     */
47
    protected ?string $username;
48
49
    /**
50
     * @Assert\NotBlank(groups={"Default"})
51
     * @Assert\Email()
52
     * @Groups({"User:superAdmin", "User:output"})
53
     */
54
    protected ?string $emailAddress;
55
56
    /**
57
     * @Groups({"User:superAdmin"})
58
     */
59
    protected array $roles;
60
61
    /**
62
     * @Groups({"User:superAdmin"})
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={"User:password:create"})
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={"User:password:create"})
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
    public ?string $plainNewPasswordConfirmationToken = null;
90
91
    /**
92
     * @ApiProperty(readable=false, writable=false)
93
     */
94
    protected ?DateTime $passwordRequestedAt = null;
95
96
    /**
97
     * @ApiProperty(readable=false)
98
     * @UserPassword(message="You have not entered your current password correctly. Please try again.", groups={"User:password:change"})
99
     * @Groups({"User:input"})
100
     */
101
    protected ?string $oldPassword = null;
102
103
    /**
104
     * @ApiProperty(readable=false, writable=false)
105
     */
106
    protected ?DateTime $passwordUpdatedAt = null;
107
108
    /**
109
     * @Assert\NotBlank(groups={"User:emailAddress", "Default"}, allowNull=true)
110
     * @Assert\Email()
111
     * @Groups({"User:input", "User:output", "User:emailAddress"})
112
     */
113
    protected ?string $newEmailAddress = null;
114
115
    /**
116
     * Random string sent to the user's new email address in order to verify it.
117
     *
118
     * @ApiProperty(readable=false, writable=false)
119
     */
120
    protected ?string $newEmailConfirmationToken = null;
121
122
    /**
123
     *  @ApiProperty(readable=false, writable=false)
124
     */
125
    public ?string $plainNewEmailConfirmationToken = null;
126
127
    /**
128
     * @ApiProperty(readable=false, writable=false)
129
     */
130
    protected bool $emailAddressVerified = false;
131
132
    /**
133
     * Random string sent to previous email address when email is changed to permit email restore and password change.
134
     *
135
     * @ApiProperty(readable=false, writable=false)
136
     */
137
    protected ?string $emailAddressVerifyToken = null;
138
139
    /**
140
     *  @ApiProperty(readable=false, writable=false)
141
     */
142
    public ?string $plainEmailAddressVerifyToken = null;
143
144
    /**
145
     * @ApiProperty(readable=false, writable=false)
146
     */
147
    protected ?DateTime $emailLastUpdatedAt = null;
148
149 56
    public function __construct(string $username = '', string $emailAddress = '', bool $emailAddressVerified = false, array $roles = ['ROLE_USER'], string $password = '', bool $enabled = true)
150
    {
151 56
        $this->username = $username;
152 56
        $this->emailAddress = $emailAddress;
153 56
        $this->emailAddressVerified = $emailAddressVerified;
154 56
        $this->roles = $roles;
155 56
        $this->password = $password;
156 56
        $this->enabled = $enabled;
157 56
    }
158
159 23
    public function getUsername(): ?string
160
    {
161 23
        return $this->username;
162
    }
163
164 22
    public function setUsername(?string $username): self
165
    {
166 22
        $this->username = $username;
167
168 22
        return $this;
169
    }
170
171 18
    public function getEmailAddress(): ?string
172
    {
173 18
        return $this->emailAddress;
174
    }
175
176 24
    public function setEmailAddress(?string $emailAddress): self
177
    {
178 24
        $this->emailAddress = $emailAddress;
179 24
        if ($emailAddress) {
180 24
            $this->emailLastUpdatedAt = new \DateTime();
181
        }
182
183 24
        return $this;
184
    }
185
186 4
    public function getRoles(): array
187
    {
188 4
        return $this->roles;
189
    }
190
191 1
    public function setRoles(array $roles): self
192
    {
193 1
        $this->roles = $roles;
194
195 1
        return $this;
196
    }
197
198 6
    public function isEnabled(): bool
199
    {
200 6
        return $this->enabled;
201
    }
202
203 4
    public function setEnabled(bool $enabled): self
204
    {
205 4
        $this->enabled = $enabled;
206
207 4
        return $this;
208
    }
209
210 3
    public function getPassword(): ?string
211
    {
212 3
        return $this->password;
213
    }
214
215 2
    public function setPassword(string $password): self
216
    {
217 2
        $this->password = $password;
218
219 2
        return $this;
220
    }
221
222 1
    public function getPlainPassword(): ?string
223
    {
224 1
        return $this->plainPassword;
225
    }
226
227 1
    public function setPlainPassword(?string $plainPassword): self
228
    {
229 1
        $this->plainPassword = $plainPassword;
230 1
        if ($plainPassword) {
231
            // Needs to update mapped field to trigger update event which will encode the plain password
232 1
            $this->passwordUpdatedAt = new \DateTime();
233
        }
234
235 1
        return $this;
236
    }
237
238 1
    public function getNewPasswordConfirmationToken(): ?string
239
    {
240 1
        return $this->newPasswordConfirmationToken;
241
    }
242
243 3
    public function setNewPasswordConfirmationToken(?string $newPasswordConfirmationToken): self
244
    {
245 3
        $this->newPasswordConfirmationToken = $newPasswordConfirmationToken;
246
247 3
        return $this;
248
    }
249
250 2
    public function getPasswordRequestedAt(): ?DateTime
251
    {
252 2
        return $this->passwordRequestedAt;
253
    }
254
255 4
    public function setPasswordRequestedAt(?DateTime $passwordRequestedAt): self
256
    {
257 4
        $this->passwordRequestedAt = $passwordRequestedAt;
258
259 4
        return $this;
260
    }
261
262 1
    public function getOldPassword(): ?string
263
    {
264 1
        return $this->oldPassword;
265
    }
266
267 1
    public function setOldPassword(?string $oldPassword): self
268
    {
269 1
        $this->oldPassword = $oldPassword;
270
271 1
        return $this;
272
    }
273
274 7
    public function getNewEmailAddress(): ?string
275
    {
276 7
        return $this->newEmailAddress;
277
    }
278
279 6
    public function setNewEmailAddress(?string $newEmailAddress): self
280
    {
281 6
        $this->newEmailAddress = $newEmailAddress;
282
283 6
        return $this;
284
    }
285
286 1
    public function getNewEmailConfirmationToken(): ?string
287
    {
288 1
        return $this->newEmailConfirmationToken;
289
    }
290
291 2
    public function setNewEmailConfirmationToken(?string $newEmailConfirmationToken): self
292
    {
293 2
        $this->newEmailConfirmationToken = $newEmailConfirmationToken;
294
295 2
        return $this;
296
    }
297
298 6
    public function isEmailAddressVerified(): bool
299
    {
300 6
        return $this->emailAddressVerified;
301
    }
302
303 5
    public function setEmailAddressVerified(bool $emailAddressVerified): self
304
    {
305 5
        $this->emailAddressVerified = $emailAddressVerified;
306
307 5
        return $this;
308
    }
309
310
    public function getEmailAddressVerifyToken(): ?string
311
    {
312
        return $this->emailAddressVerifyToken;
313
    }
314
315
    public function setEmailAddressVerifyToken(?string $emailAddressVerifyToken): void
316
    {
317
        $this->emailAddressVerifyToken = $emailAddressVerifyToken;
318
    }
319
320 1
    public function isPasswordRequestLimitReached($ttl): bool
321
    {
322 1
        $lastRequest = $this->getPasswordRequestedAt();
323
324 1
        return $lastRequest instanceof DateTime &&
325 1
            $lastRequest->getTimestamp() + $ttl > time();
326
    }
327
328
    /** @see \Serializable::serialize() */
329 1
    public function serialize(): string
330
    {
331 1
        return serialize([
332 1
            (string) $this->id,
333 1
            $this->username,
334 1
            $this->emailAddress,
335 1
            $this->password,
336 1
            $this->enabled,
337 1
            $this->roles,
338
        ]);
339
    }
340
341
    /**
342
     * @see \Serializable::unserialize()
343
     */
344 2
    public function unserialize(string $serialized): self
345
    {
346 2
        $id = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $id is dead and can be removed.
Loading history...
347
        [
348
            $id,
349 2
            $this->username,
350 2
            $this->emailAddress,
351 2
            $this->password,
352 2
            $this->enabled,
353 2
            $this->roles,
354 2
        ] = unserialize($serialized, ['allowed_classes' => false]);
355 2
        $this->id = Uuid::fromString($id);
356
357 2
        return $this;
358
    }
359
360
    /**
361
     * Not needed - we use bcrypt.
362
     *
363
     * @ApiProperty(readable=false, writable=false)
364
     */
365
    public function getSalt()
366
    {
367
    }
368
369
    /**
370
     * Remove sensitive data - e.g. plain passwords etc.
371
     */
372 1
    public function eraseCredentials(): void
373
    {
374 1
        $this->plainPassword = null;
375 1
    }
376
377 2
    public function __toString()
378
    {
379 2
        return (string) $this->id;
380
    }
381
382
    public static function createFromPayload($username, array $payload)
383
    {
384
        return new static(
385
            $username,
386
            $payload['roles']
387
        );
388
    }
389
}
390