Test Failed
Pull Request — master (#72)
by Daniel
05:45
created

AbstractUser::getPreviousEmailAddress()   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 0
dl 0
loc 3
ccs 2
cts 2
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"})
110
     * @Groups({"User:input", "User:output", "User:emailAddress"})
111
     */
112
    protected ?string $newEmailAddress = null;
113
114
    /**
115
     * Random string sent to the user's new email address in order to verify it.
116
     *
117
     * @ApiProperty(readable=false, writable=false)
118
     */
119
    protected ?string $newEmailVerificationToken = null;
120
121 56
    /**
122
     *  @ApiProperty(readable=false, writable=false)
123 56
     */
124 56
    public ?string $plainNewEmailVerificationToken = null;
125 56
126 56
    /**
127 56
     * @ApiProperty(readable=false, writable=false)
128 56
     */
129 56
    protected bool $emailAddressVerified = false;
130
131 23
    /**
132
     * @ApiProperty(readable=false, writable=false)
133 23
     */
134
    protected ?string $previousEmailAddress = null;
135
136 22
    /**
137
     * Random string sent to previous email address when email is changed to permit email restore and password change.
138 22
     *
139
     * @ApiProperty(readable=false, writable=false)
140 22
     */
141
    protected ?string $restoreAccessToken = null;
142
143 18
    /**
144
     *  @ApiProperty(readable=false, writable=false)
145 18
     */
146
    protected ?string $plainRestoreAccessToken = null;
147
148 24
    /**
149
     * @ApiProperty(readable=false, writable=false)
150 24
     */
151
    protected ?DateTime $emailLastUpdatedAt = null;
152 24
153
    public function __construct(string $username = '', string $emailAddress = '', bool $emailAddressVerified = false, array $roles = ['ROLE_USER'], string $password = '', bool $enabled = true)
154
    {
155 4
        $this->username = $username;
156
        $this->emailAddress = $emailAddress;
157 4
        $this->emailAddressVerified = $emailAddressVerified;
158
        $this->roles = $roles;
159
        $this->password = $password;
160 1
        $this->enabled = $enabled;
161
    }
162 1
163
    public function getUsername(): ?string
164 1
    {
165
        return $this->username;
166
    }
167 6
168
    public function setUsername(?string $username): self
169 6
    {
170
        $this->username = $username;
171
172 4
        return $this;
173
    }
174 4
175
    public function getEmailAddress(): ?string
176 4
    {
177
        return $this->emailAddress;
178
    }
179 3
180
    public function setEmailAddress(?string $emailAddress): self
181 3
    {
182
        $this->emailAddress = $emailAddress;
183
        if ($emailAddress) {
184 2
            $this->emailLastUpdatedAt = new \DateTime();
185
        }
186 2
187
        return $this;
188 2
    }
189
190
    public function getRoles(): array
191 1
    {
192
        return $this->roles;
193 1
    }
194
195
    public function setRoles(array $roles): self
196 1
    {
197
        $this->roles = $roles;
198 1
199 1
        return $this;
200
    }
201 1
202
    public function isEnabled(): bool
203
    {
204 1
        return $this->enabled;
205
    }
206
207 3
    public function setEnabled(bool $enabled): self
208
    {
209 3
        $this->enabled = $enabled;
210
211
        return $this;
212 4
    }
213
214 4
    public function getPassword(): ?string
215
    {
216 4
        return $this->password;
217
    }
218
219 2
    public function setPassword(string $password): self
220
    {
221 2
        $this->password = $password;
222
223
        return $this;
224 4
    }
225
226 4
    public function getPlainPassword(): ?string
227
    {
228 4
        return $this->plainPassword;
229
    }
230
231 1
    public function setPlainPassword(?string $plainPassword): self
232
    {
233 1
        $this->plainPassword = $plainPassword;
234
        if ($plainPassword) {
235
            // Needs to update mapped field to trigger update event which will encode the plain password
236 1
            $this->passwordUpdatedAt = new \DateTime();
237
        }
238 1
239
        return $this;
240 1
    }
241
242
    public function getNewPasswordConfirmationToken(): ?string
243 7
    {
244
        return $this->newPasswordConfirmationToken;
245 7
    }
246
247
    public function setNewPasswordConfirmationToken(?string $newPasswordConfirmationToken): self
248 6
    {
249
        $this->newPasswordConfirmationToken = $newPasswordConfirmationToken;
250 6
251
        return $this;
252 6
    }
253
254
    public function getPasswordRequestedAt(): ?DateTime
255 5
    {
256
        return $this->passwordRequestedAt;
257 5
    }
258
259
    public function setPasswordRequestedAt(?DateTime $passwordRequestedAt): self
260 4
    {
261
        $this->passwordRequestedAt = $passwordRequestedAt;
262 4
263
        return $this;
264 4
    }
265
266
    public function getOldPassword(): ?string
267 6
    {
268
        return $this->oldPassword;
269 6
    }
270
271
    public function setOldPassword(?string $oldPassword): self
272 5
    {
273
        $this->oldPassword = $oldPassword;
274 5
275
        return $this;
276 5
    }
277
278
    public function getNewEmailAddress(): ?string
279 1
    {
280
        return $this->newEmailAddress;
281 1
    }
282
283 1
    public function setNewEmailAddress(?string $newEmailAddress): self
284 1
    {
285
        $this->newEmailAddress = $newEmailAddress;
286
287
        return $this;
288 1
    }
289
290 1
    public function getNewEmailVerificationToken(): ?string
291 1
    {
292 1
        return $this->newEmailVerificationToken;
293 1
    }
294 1
295 1
    public function setNewEmailVerificationToken(?string $newEmailVerificationToken): self
296 1
    {
297
        $this->newEmailVerificationToken = $newEmailVerificationToken;
298
299
        return $this;
300
    }
301
302
    public function isEmailAddressVerified(): bool
303 2
    {
304
        return $this->emailAddressVerified;
305 2
    }
306
307
    public function setEmailAddressVerified(bool $emailAddressVerified): self
308 2
    {
309 2
        $this->emailAddressVerified = $emailAddressVerified;
310 2
311 2
        return $this;
312 2
    }
313 2
314 2
    public function getPreviousEmailAddress(): ?string
315
    {
316 2
        return $this->previousEmailAddress;
317
    }
318
319
    public function setPreviousEmailAddress(?string $previousEmailAddress): void
320
    {
321
        $this->previousEmailAddress = $previousEmailAddress;
322
    }
323
324
    public function getRestoreAccessToken(): ?string
325
    {
326
        return $this->restoreAccessToken;
327
    }
328
329
    public function setRestoreAccessToken(?string $restoreAccessToken): void
330
    {
331 1
        $this->restoreAccessToken = $restoreAccessToken;
332
    }
333 1
334 1
    public function isPasswordRequestLimitReached($ttl): bool
335
    {
336 2
        $lastRequest = $this->getPasswordRequestedAt();
337
338 2
        return $lastRequest instanceof DateTime &&
339
            $lastRequest->getTimestamp() + $ttl > time();
340
    }
341
342
    /** @see \Serializable::serialize() */
343
    public function serialize(): string
344
    {
345
        return serialize([
346
            (string) $this->id,
347
            $this->username,
348
            $this->emailAddress,
349
            $this->password,
350
            $this->enabled,
351
            $this->roles,
352
        ]);
353
    }
354
355
    /**
356
     * @see \Serializable::unserialize()
357
     */
358
    public function unserialize(string $serialized): self
359
    {
360
        $id = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $id is dead and can be removed.
Loading history...
361
        [
362
            $id,
363
            $this->username,
364
            $this->emailAddress,
365
            $this->password,
366
            $this->enabled,
367
            $this->roles,
368
        ] = unserialize($serialized, ['allowed_classes' => false]);
369
        $this->id = Uuid::fromString($id);
370
371
        return $this;
372
    }
373
374
    /**
375
     * Not needed - we use bcrypt.
376
     *
377
     * @ApiProperty(readable=false, writable=false)
378
     */
379
    public function getSalt()
380
    {
381
    }
382
383
    /**
384
     * Remove sensitive data - e.g. plain passwords etc.
385
     */
386
    public function eraseCredentials(): void
387
    {
388
        $this->plainPassword = null;
389
    }
390
391
    public function __toString()
392
    {
393
        return (string) $this->id;
394
    }
395
396
    public static function createFromPayload($username, array $payload)
397
    {
398
        return new static(
399
            $username,
400
            $payload['roles']
401
        );
402
    }
403
}
404