Completed
Push — master ( 31741c...acf815 )
by Benjamin
11:01 queued 06:10
created

SecurityController::resetPassword()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 37
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
eloc 23
c 0
b 0
f 0
dl 0
loc 37
ccs 0
cts 24
cp 0
rs 9.552
cc 4
nc 3
nop 4
crap 20
1
<?php
2
3
namespace Obblm\Core\Controller;
4
5
use Doctrine\ORM\EntityManagerInterface;
6
use Obblm\Core\Entity\Coach;
7
use Obblm\Core\Event\ActivateCoachEvent;
8
use Obblm\Core\Event\RegisterCoachEvent;
9
use Obblm\Core\Event\ResetPasswordCoachEvent;
10
use Obblm\Core\Form\Security\ForgotPasswordForm;
11
use Obblm\Core\Form\Security\PasswordConfirmType;
12
use Obblm\Core\Form\Security\RegistrationForm;
13
use LogicException;
14
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
15
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
16
use Symfony\Component\HttpFoundation\Request;
17
use Symfony\Component\HttpFoundation\Response;
18
use Symfony\Component\Routing\Annotation\Route;
19
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
20
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
21
22
/**
23
 * @Route("/", name="obblm_")
24
 */
25
class SecurityController extends AbstractController
26
{
27
    /**
28
     * @Route("/login", name="login")
29
     */
30
    public function login(AuthenticationUtils $authenticationUtils, Request $request): Response
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

30
    public function login(AuthenticationUtils $authenticationUtils, /** @scrutinizer ignore-unused */ Request $request): Response

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
31
    {
32
        if ($this->getUser()) {
33
            return $this->redirectToRoute('obblm_dashboard');
34
        }
35
36
        // get the login error if there is one
37
        $error = $authenticationUtils->getLastAuthenticationError();
38
        // last username entered by the user
39
        $lastUsername = $authenticationUtils->getLastUsername();
40
41
        return $this->render('@ObblmCore/security/login.html.twig', [
42
            'last_username' => $lastUsername,
43
            'error' => $error,
44
        ]);
45
    }
46
47
    /**
48
     * @Route("/logout", name="logout")
49
     */
50
    public function logout()
51
    {
52
        throw new LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
53
    }
54
55
    /**
56
     * @Route("/register", name="register")
57
     */
58
    public function register(Request $request, UserPasswordEncoderInterface $passwordEncoder, EventDispatcherInterface $dispatcher):Response
59
    {
60
        $coach = new Coach();
61
        $form = $this->createForm(RegistrationForm::class, $coach);
62
63
        $form->handleRequest($request);
64
        if ($form->isSubmitted() && $form->isValid()) {
65
            $password = $passwordEncoder->encodePassword($coach, $coach->getPlainPassword());
0 ignored issues
show
Bug introduced by
It seems like $coach->getPlainPassword() can also be of type null; however, parameter $plainPassword of Symfony\Component\Securi...rface::encodePassword() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

65
            $password = $passwordEncoder->encodePassword($coach, /** @scrutinizer ignore-type */ $coach->getPlainPassword());
Loading history...
66
            $coach->setPassword($password)
67
                ->setHash($this->getHashFor($coach->getEmail()));
68
69
            $entityManager = $this->getDoctrine()->getManager();
70
            $entityManager->persist($coach);
71
72
            $event = new RegisterCoachEvent($coach);
73
            $dispatcher->dispatch($event, RegisterCoachEvent::NAME);
74
75
            $entityManager->flush();
76
77
            $this->addFlash(
78
                'success',
79
                'obblm.flash.account.created'
80
            );
81
            return $this->redirectToRoute('obblm_login');
82
        }
83
84
        return $this->render('@ObblmCore/security/register.html.twig', [
85
            'form' => $form->createView(),
86
        ]);
87
    }
88
89
    /**
90
     * @Route("/activate/{hash}", name="activate_account")
91
     */
92
    public function activate(string $hash, EventDispatcherInterface $dispatcher):Response
93
    {
94
        $entityManager = $this->getDoctrine()->getManager();
95
96
        /** @var ?Coach $coach */
97
        $coach = $entityManager->getRepository(Coach::class)->findOneByHash($hash);
98
99
        if (!$coach) {
100
            $this->addFlash(
101
                'error',
102
                'obblm.flash.account.not_found_by_hash'
103
            );
104
105
            return $this->redirectToRoute('obblm_login');
106
        }
107
108
        if (!$coach->isActive()) {
109
            $coach->setHash(null)->setActive(true);
110
            $entityManager->persist($coach);
111
112
            $event = new ActivateCoachEvent($coach);
113
            $dispatcher->dispatch($event, ActivateCoachEvent::NAME);
114
            $entityManager->flush();
115
116
            $this->addFlash(
117
                'success',
118
                'obblm.flash.account.activated'
119
            );
120
121
            return $this->redirectToRoute('obblm_login');
122
        }
123
124
        $this->addFlash(
125
            'success',
126
            'obblm.flash.account.already_activated'
127
        );
128
129
        return $this->redirectToRoute('obblm_login');
130
    }
131
132
    /**
133
     * @Route("/forgot-password", name="forgot_password")
134
     */
135
    public function forgotPassword(Request $request, EventDispatcherInterface $dispatcher):Response
136
    {
137
        $form = $this->createForm(ForgotPasswordForm::class);
138
139
        $form->handleRequest($request);
140
141
        if ($form->isSubmitted() && $form->isValid()) {
142
            $data = $form->getData();
143
            $em = $this->getDoctrine()->getManager();
144
            /** @var Coach $coach */
145
            $coach = $em->getRepository(Coach::class)->findOneByEmail($data['email']);
146
            if ($coach) {
0 ignored issues
show
introduced by
$coach is of type Obblm\Core\Entity\Coach, thus it always evaluated to true.
Loading history...
147
                $coach
148
                    ->setResetPasswordAt(new \DateTime())
149
                    ->setResetPasswordHash($this->getHashFor(random_bytes(10)));
150
                $em->persist($coach);
151
                $em->flush();
152
                $dispatcher->dispatch(new ResetPasswordCoachEvent($coach), ResetPasswordCoachEvent::NAME);
153
154
                $this->addFlash(
155
                    'success',
156
                    'obblm.flash.account.forgot_password.sent'
157
                );
158
159
                return $this->redirectToRoute('obblm_login');
160
            }
161
        }
162
163
        return $this->render('@ObblmCore/security/forgot-password.html.twig', [
164
            'form' => $form->createView(),
165
        ]);
166
    }
167
168
    /**
169
     * @Route("/reset-password/{hash}", name="reset_password")
170
     */
171
    public function resetPassword(string $hash, Request $request, UserPasswordEncoderInterface $passwordEncoder, EventDispatcherInterface $dispatcher):Response
0 ignored issues
show
Unused Code introduced by
The parameter $dispatcher is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

171
    public function resetPassword(string $hash, Request $request, UserPasswordEncoderInterface $passwordEncoder, /** @scrutinizer ignore-unused */ EventDispatcherInterface $dispatcher):Response

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
172
    {
173
        $em = $this->getDoctrine()->getManager();
174
175
        /** @var Coach $coach */
176
        $coach = $em->getRepository(Coach::class)->findOneForPasswordReset($hash);
177
178
        if ($coach) {
0 ignored issues
show
introduced by
$coach is of type Obblm\Core\Entity\Coach, thus it always evaluated to true.
Loading history...
179
            $form = $this->createForm(PasswordConfirmType::class);
180
181
            $form->handleRequest($request);
182
183
            if ($form->isSubmitted() && $form->isValid()) {
184
                $data = $form->getData();
185
                $password = $passwordEncoder->encodePassword($coach, $data['plainPassword']);
186
                $coach->setPassword($password)
187
                    ->setResetPasswordHash(null)
188
                    ->setResetPasswordAt(null);
189
                $em->persist($coach);
190
                $em->flush();
191
                $this->addFlash(
192
                    'success',
193
                    'obblm.flash.account.forgot_password.changed'
194
                );
195
                return $this->redirectToRoute('obblm_login');
196
            }
197
198
            return $this->render('@ObblmCore/security/reset-password.html.twig', [
199
                'form' => $form->createView(),
200
            ]);
201
        }
202
203
        $this->addFlash(
204
            'error',
205
            'obblm.flash.account.forgot_password.not_found'
206
        );
207
        return $this->redirectToRoute('obblm_forgot_password');
208
    }
209
210
    private function getHashFor($value)
211
    {
212
        return hash('sha256', $value);
213
    }
214
}
215