Passed
Branch main (b6a268)
by Iain
04:04
created

PasswordResetConfirm::process()   B

Complexity

Conditions 9
Paths 20

Size

Total Lines 64
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 9
eloc 39
c 1
b 0
f 0
nc 20
nop 1
dl 0
loc 64
rs 7.7404

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * Copyright Humbly Arrogant Ltd 2020-2022.
7
 *
8
 * Use of this software is governed by the Business Source License included in the LICENSE file and at https://getparthenon.com/docs/next/license.
9
 *
10
 * Change Date: TBD ( 3 years after 2.0.0 release )
11
 *
12
 * On the date above, in accordance with the Business Source License, use of this software will be governed by the open source license specified in the LICENSE file.
13
 */
14
15
namespace Parthenon\User\RequestProcessor;
16
17
use Parthenon\Common\Exception\NoEntityFoundException;
18
use Parthenon\Common\LoggerAwareTrait;
19
use Parthenon\Common\RequestHandler\JsonRequestHandler;
20
use Parthenon\Common\RequestHandler\RequestHandlerManagerInterface;
21
use Parthenon\User\Entity\UserInterface;
22
use Parthenon\User\Event\PostPasswordResetConfirmEvent;
23
use Parthenon\User\Event\PostUserConfirmEvent;
24
use Parthenon\User\Event\PrePasswordResetConfirmEvent;
25
use Parthenon\User\Repository\ForgotPasswordCodeRepositoryInterface;
26
use Parthenon\User\Repository\UserRepositoryInterface;
27
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
28
use Symfony\Component\HttpFoundation\JsonResponse;
29
use Symfony\Component\HttpFoundation\RedirectResponse;
30
use Symfony\Component\HttpFoundation\Request;
31
use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactoryInterface;
32
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
33
34
class PasswordResetConfirm
35
{
36
    use LoggerAwareTrait;
37
38
    public function __construct(
39
        private UserRepositoryInterface $userRepository,
40
        private ForgotPasswordCodeRepositoryInterface $forgotPasswordCodeRepository,
41
        private PasswordHasherFactoryInterface $encoderFactory,
42
        private EventDispatcherInterface $eventDispatcher,
43
        private UrlGeneratorInterface $urlGenerator,
44
        private RequestHandlerManagerInterface $requestHandlerManager,
45
    ) {
46
    }
47
48
    public function process(Request $request)
49
    {
50
        $requestHandler = $this->requestHandlerManager->getRequestHandler($request);
51
52
        $code = $request->get('code');
53
        try {
54
            $passwordReset = $this->forgotPasswordCodeRepository->findActiveByCode($code);
55
        } catch (NoEntityFoundException $e) {
56
            return $requestHandler->generateErrorOutput(null);
57
        }
58
59
        if ($passwordReset->isUsed()) {
60
            $this->getLogger()->warning('A user has tried to reset their password with an used code', ['code' => $code]);
61
62
            return $requestHandler->generateErrorOutput(null);
63
        }
64
65
        if ($passwordReset->isExpired()) {
66
            $this->getLogger()->warning('A user has tried to reset their password with an expired code', ['code' => $code]);
67
68
            return $requestHandler->generateErrorOutput(null);
69
        }
70
71
        if (!$request->isMethod('POST')) {
72
            return $requestHandler->generateDefaultOutput(null);
73
        }
74
75
        $passwordReset->setUsed(true);
76
        $passwordReset->setUsedAt(new \DateTime('now'));
77
        /** @var UserInterface $user */
78
        $user = $this->userRepository->getById($passwordReset->getUserId());
79
80
        $this->eventDispatcher->dispatch(new PrePasswordResetConfirmEvent($user), PrePasswordResetConfirmEvent::NAME);
81
82
        if ($requestHandler instanceof JsonRequestHandler) {
83
            $json = json_decode($request->getContent(), true);
84
            $newPassword = $json['password'];
85
        } else {
86
            $newPassword = $request->get('password');
87
        }
88
        $newPasswordHash = $this->encoderFactory->getPasswordHasher($user)->hash($newPassword);
89
90
        $user->setPassword($newPasswordHash);
91
        $hasActivatedUser = false;
92
        if (!$user->isConfirmed()) {
93
            $user->setActivatedAt(new \DateTime('now'));
94
            $user->setIsConfirmed(true);
95
            $hasActivatedUser = true;
96
        }
97
        $this->userRepository->save($user);
98
        $this->forgotPasswordCodeRepository->save($passwordReset);
99
100
        if ($hasActivatedUser) {
101
            $this->eventDispatcher->dispatch(new PostUserConfirmEvent($user), PostUserConfirmEvent::NAME);
102
        }
103
104
        $this->eventDispatcher->dispatch(new PostPasswordResetConfirmEvent($user), PostPasswordResetConfirmEvent::NAME);
105
        $this->getLogger()->info('A user has reset their password', ['email' => $user->getEmail()]);
106
107
        if ($requestHandler instanceof JsonRequestHandler) {
108
            return new JsonResponse(['success' => true]);
109
        }
110
111
        return new RedirectResponse($this->urlGenerator->generate('parthenon_user_login'));
112
    }
113
}
114