Test Failed
Pull Request — master (#67)
by Daniel
10:04 queued 04:16
created

PasswordManager::persistPlainPassword()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 1
dl 0
loc 7
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\Helper\User;
15
16
use ApiPlatform\Core\Bridge\Symfony\Validator\Exception\ValidationException;
17
use DateTime;
18
use Doctrine\ORM\EntityManagerInterface;
19
use Silverback\ApiComponentsBundle\Entity\User\AbstractUser;
20
use Silverback\ApiComponentsBundle\Exception\InvalidArgumentException;
21
use Silverback\ApiComponentsBundle\Exception\UnexpectedValueException;
22
use Silverback\ApiComponentsBundle\Repository\User\UserRepository;
23
use Silverback\ApiComponentsBundle\Security\TokenGenerator;
24
use Symfony\Component\Validator\Validator\ValidatorInterface;
25
26
/**
27
 * @author Daniel West <[email protected]>
28
 */
29
class PasswordManager
30
{
31
    private UserMailer $userMailer;
32
    private EntityManagerInterface $entityManager;
33
    private ValidatorInterface $validator;
34
    private UserRepository $userRepository;
35
    private int $tokenTtl;
36
37
    public function __construct(UserMailer $userMailer, EntityManagerInterface $entityManager, ValidatorInterface $validator, UserRepository $userRepository, int $tokenTtl = 8600)
38
    {
39
        $this->userMailer = $userMailer;
40
        $this->entityManager = $entityManager;
41
        $this->validator = $validator;
42
        $this->userRepository = $userRepository;
43
        $this->tokenTtl = $tokenTtl;
44
    }
45
46
    public function requestResetEmail(string $usernameQuery): void
47
    {
48
        $user = $this->userRepository->findOneBy(['username' => $usernameQuery]);
49
        if (!$user) {
50
            throw new UnexpectedValueException('Username not found');
51
        }
52
53
        if ($user->isPasswordRequestLimitReached($this->tokenTtl)) {
54
            return;
55
        }
56
57
        $username = $user->getUsername();
58
        if (!$username) {
59
            throw new InvalidArgumentException(sprintf('The entity %s should have a username set to send a password reset email.', AbstractUser::class));
60
        }
61
        $user->setNewPasswordConfirmationToken(TokenGenerator::generateToken());
62
        $user->setPasswordRequestedAt(new DateTime());
63
        $this->userMailer->sendPasswordResetEmail($user);
64
        $this->entityManager->flush();
65
    }
66
67
    public function passwordReset(string $username, string $token, string $newPassword): void
68
    {
69
        $user = $this->userRepository->findOneByPasswordResetToken($username, $token);
70
        if (!$user) {
71
            throw new UnexpectedValueException('Username not found');
72
        }
73
74
        $user->setPlainPassword($newPassword);
75
        $user->setNewPasswordConfirmationToken(null);
76
        $user->setPasswordRequestedAt(null);
77
        $errors = $this->validator->validate($user, null, ['User:password:create']);
78
        if (\count($errors)) {
79
            throw new ValidationException($errors);
80
        }
81
        $this->persistPlainPassword($user);
82
    }
83
84
    public function persistPlainPassword(AbstractUser $user): AbstractUser
85
    {
86
        $this->entityManager->persist($user);
87
        $this->entityManager->flush();
88
        $user->eraseCredentials();
89
90
        return $user;
91
    }
92
}
93