Completed
Push — symfony3-parameterbag ( 01d59d )
by Kamil
81:16 queued 62:48
created

UserController::prepareResetPasswordRequest()   C

Complexity

Conditions 7
Paths 8

Size

Total Lines 46
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 46
rs 6.7272
c 1
b 0
f 0
cc 7
eloc 27
nc 8
nop 3
1
<?php
2
3
/*
4
 * This file is part of the Sylius package.
5
 *
6
 * (c) Paweł Jędrzejewski
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
namespace Sylius\Bundle\UserBundle\Controller;
13
14
use FOS\RestBundle\View\View;
15
use Sylius\Bundle\ResourceBundle\Controller\RequestConfiguration;
16
use Sylius\Bundle\ResourceBundle\Controller\ResourceController;
17
use Sylius\Bundle\UserBundle\Form\Model\ChangePassword;
18
use Sylius\Bundle\UserBundle\Form\Model\PasswordReset;
19
use Sylius\Bundle\UserBundle\Form\Model\PasswordResetRequest;
20
use Sylius\Bundle\UserBundle\UserEvents;
21
use Sylius\Component\User\Model\UserInterface;
22
use Sylius\Component\User\Security\Generator\GeneratorInterface;
23
use Symfony\Component\EventDispatcher\GenericEvent;
24
use Symfony\Component\Form\FormInterface;
25
use Symfony\Component\HttpFoundation\RedirectResponse;
26
use Symfony\Component\HttpFoundation\Request;
27
use Symfony\Component\HttpFoundation\Response;
28
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
29
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
30
use Webmozart\Assert\Assert;
31
32
/**
33
 * @author Łukasz Chruściel <[email protected]>
34
 * @author Jan Góralski <[email protected]>
35
 */
36
class UserController extends ResourceController
37
{
38
    /**
39
     * @param Request $request
40
     *
41
     * @return Response
42
     */
43
    public function changePasswordAction(Request $request)
44
    {
45
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
46
47
        if (!$this->container->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
48
            throw new AccessDeniedException('You have to be registered user to access this section.');
49
        }
50
51
        $user = $this->container->get('security.token_storage')->getToken()->getUser();
52
53
        $changePassword = new ChangePassword();
54
        $formType = $this->getSyliusAttribute($request, 'form', 'sylius_user_change_password');
55
        $form = $this->createResourceForm($configuration, $formType, $changePassword);
56
57
        if (in_array($request->getMethod(), ['POST', 'PUT', 'PATCH']) && $form->submit($request, !$request->isMethod('PATCH'))->isValid()) {
58
            return $this->handleChangePassword($request, $configuration, $user, $changePassword->getNewPassword());
59
        }
60
61
        if (!$configuration->isHtmlRequest()) {
62
            return $this->viewHandler->handle($configuration, View::create($form, Response::HTTP_BAD_REQUEST));
63
        }
64
65
        return $this->container->get('templating')->renderResponse(
66
            $configuration->getTemplate('changePassword.html'),
67
            ['form' => $form->createView()]
68
        );
69
    }
70
71
    /**
72
     * @param Request $request
73
     *
74
     * @return Response
75
     */
76
    public function requestPasswordResetTokenAction(Request $request)
77
    {
78
        /** @var GeneratorInterface $generator */
79
        $generator = $this->container->get(sprintf('sylius.%s.token_generator.password_reset', $this->metadata->getName()));
80
81
        return $this->prepareResetPasswordRequest($request, $generator, UserEvents::REQUEST_RESET_PASSWORD_TOKEN);
82
    }
83
84
    /**
85
     * @param Request $request
86
     *
87
     * @return Response
88
     */
89
    public function requestPasswordResetPinAction(Request $request)
90
    {
91
        /** @var GeneratorInterface $generator */
92
        $generator = $this->container->get(sprintf('sylius.%s.pin_generator.password_reset', $this->metadata->getName()));
93
94
        return $this->prepareResetPasswordRequest($request, $generator, UserEvents::REQUEST_RESET_PASSWORD_PIN);
95
    }
96
97
    /**
98
     * @param Request $request
99
     * @param string $token
100
     *
101
     * @return Response
102
     */
103
    public function resetPasswordAction(Request $request, $token)
104
    {
105
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
106
        /** @var UserInterface $user */
107
        $user = $this->repository->findOneBy(['passwordResetToken' => $token]);
108
        if (null === $user) {
109
            throw new NotFoundHttpException('Token not found.');
110
        }
111
112
        $resetting = $this->metadata->getParameter('resetting');
113
        $lifetime = new \DateInterval($resetting['token']['ttl']);
114
        if (!$user->isPasswordRequestNonExpired($lifetime)) {
115
            return $this->handleExpiredToken($request, $configuration, $user);
116
        }
117
118
        $passwordReset = new PasswordReset();
119
        $formType = $this->getSyliusAttribute($request, 'form', 'sylius_user_reset_password');
120
        $form = $this->createResourceForm($configuration, $formType, $passwordReset);
121
122
        if (in_array($request->getMethod(), ['POST', 'PUT', 'PATCH']) && $form->submit($request, !$request->isMethod('PATCH'))->isValid()) {
123
            return $this->handleResetPassword($request, $configuration, $user, $passwordReset->getPassword());
124
        }
125
126
        if (!$configuration->isHtmlRequest()) {
127
            return $this->viewHandler->handle($configuration, View::create($form, Response::HTTP_BAD_REQUEST));
128
        }
129
130
        return $this->container->get('templating')->renderResponse(
131
            $configuration->getTemplate('resetPassword.html'),
132
            [
133
                'form' => $form->createView(),
134
                'user' => $user,
135
            ]
136
        );
137
    }
138
139
    /**
140
     * @param Request $request
141
     * @param string $token
142
     *
143
     * @return Response
144
     */
145
    public function verifyAction(Request $request, $token)
146
    {
147
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
148
        $redirectRoute = $this->getSyliusAttribute($request, 'redirect', null);
149
150
        $response = $this->redirectToRoute($redirectRoute);
151
152
        /** @var UserInterface $user */
153
        $user = $this->repository->findOneBy(['emailVerificationToken' => $token]);
154
        if (null === $user) {
155
            if (!$configuration->isHtmlRequest()) {
156
                return $this->viewHandler->handle($configuration, View::create($configuration, Response::HTTP_BAD_REQUEST));
157
            }
158
159
            $this->addFlash('error', 'sylius.user.verification.error');
160
161
            return $this->redirectToRoute($redirectRoute);
162
        }
163
164
        $eventDispatcher = $this->container->get('event_dispatcher');
165
        $eventDispatcher->dispatch(UserEvents::PRE_EMAIL_VERIFICATION, new GenericEvent($user));
166
167
        $user->setVerifiedAt(new \DateTime());
168
        $user->setEmailVerificationToken(null);
169
170
        $this->manager->flush();
171
172
        $eventDispatcher->dispatch(UserEvents::POST_EMAIL_VERIFICATION, new GenericEvent($user));
173
174
        if (!$configuration->isHtmlRequest()) {
175
            return $this->viewHandler->handle($configuration, View::create($user));
176
        }
177
178
        $flashMessage = $this->getSyliusAttribute($request, 'flash', 'sylius.user.verification.success');
179
        $this->addFlash('success', $flashMessage);
180
181
        return $response;
182
    }
183
184
    /**
185
     * @param Request $request
186
     *
187
     * @return Response
188
     */
189
    public function requestVerificationTokenAction(Request $request)
190
    {
191
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
192
        $redirectRoute = $this->getSyliusAttribute($request, 'redirect', 'referer');
193
194
        /** @var UserInterface $user */
195
        $user = $this->container->get('sylius.context.customer')->getCustomer()->getUser();
196
        if (null !== $user->getVerifiedAt()) {
197
            if (!$configuration->isHtmlRequest()) {
198
                return $this->viewHandler->handle($configuration, View::create($configuration, Response::HTTP_BAD_REQUEST));
199
            }
200
201
            $this->addFlash('notice', 'sylius.user.verification.notice.verified');
202
203
            return $this->redirectHandler->redirectToRoute($configuration, $redirectRoute);
204
        }
205
206
        $tokenGenerator = $this->container->get(sprintf('sylius.%s.token_generator.email_verification', $this->metadata->getName()));
207
        $user->setEmailVerificationToken($tokenGenerator->generate());
208
209
        $this->manager->flush();
210
211
        $eventDispatcher = $this->container->get('event_dispatcher');
212
        $eventDispatcher->dispatch(UserEvents::REQUEST_VERIFICATION_TOKEN, new GenericEvent($user));
213
214
        if (!$configuration->isHtmlRequest()) {
215
            return $this->viewHandler->handle($configuration, View::create(null, Response::HTTP_NO_CONTENT));
216
        }
217
218
        $this->addFlash('success', 'sylius.user.verification.request.success');
219
220
        return $this->redirectHandler->redirectToRoute($configuration, $redirectRoute);
221
    }
222
223
    /**
224
     * @param Request $request
225
     * @param GeneratorInterface $generator
226
     * @param string $senderEvent
227
     *
228
     * @return Response
229
     */
230
    protected function prepareResetPasswordRequest(Request $request, GeneratorInterface $generator, $senderEvent)
231
    {
232
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
233
234
        $passwordReset = new PasswordResetRequest();
235
        $formType = $this->getSyliusAttribute($request, 'form', 'sylius_user_request_password_reset');
236
        $form = $this->createResourceForm($configuration, $formType, $passwordReset);
237
        $template = $this->getSyliusAttribute($request, 'template', null);
238
        Assert::notNull($template, 'Template is not configured.');
239
240
        if (in_array($request->getMethod(), ['POST', 'PUT', 'PATCH']) && $form->submit($request, !$request->isMethod('PATCH'))->isValid()) {
241
            $user = $this->repository->findOneByEmail($passwordReset->getEmail());
0 ignored issues
show
Bug introduced by
The method findOneByEmail() does not exist on Sylius\Component\Resourc...ory\RepositoryInterface. Did you maybe mean findOneBy()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
242
            if (null !== $user) {
243
                $this->handleResetPasswordRequest($generator, $user, $senderEvent);
244
            }
245
246
            if (!$configuration->isHtmlRequest()) {
247
                return $this->viewHandler->handle($configuration, View::create(null, Response::HTTP_NO_CONTENT));
248
            }
249
250
            $this->addFlash('success', 'sylius.user.password.reset.requested');
251
            $redirectRoute = $this->getSyliusAttribute($request, 'redirect', null);
252
            Assert::notNull($redirectRoute, 'Redirect is not configured.');
253
254
            if (is_array($redirectRoute)) {
255
                return $this->redirectHandler->redirectToRoute(
256
                    $configuration,
257
                    $configuration->getParameters()->get('redirect')['route'],
258
                    $configuration->getParameters()->get('redirect')['parameters']
259
                );
260
            }
261
262
            return $this->redirectHandler->redirectToRoute($configuration, $redirectRoute);
263
        }
264
265
        if (!$configuration->isHtmlRequest()) {
266
            return $this->viewHandler->handle($configuration, View::create($form, Response::HTTP_BAD_REQUEST));
267
        }
268
269
        return $this->container->get('templating')->renderResponse(
270
            $template,
271
            [
272
                'form' => $form->createView(),
273
            ]
274
        );
275
    }
276
277
    /**
278
     * @param string $type
279
     * @param string $message
280
     */
281
    protected function addFlash($type, $message)
282
    {
283
        $translator = $this->container->get('translator');
284
        $this->container->get('session')->getFlashBag()->add($type, $translator->trans($message, [], 'flashes'));
285
    }
286
287
    /**
288
     * @param RequestConfiguration $configuration
289
     * @param string $type
290
     * @param mixed $resource
291
     *
292
     * @return FormInterface
293
     */
294
    protected function createResourceForm(RequestConfiguration $configuration, $type, $resource)
295
    {
296
        if (!$configuration->isHtmlRequest()) {
297
            return $this->container->get('form.factory')->createNamed('', $type, $resource, ['csrf_protection' => false]);
298
        }
299
300
        return $this->container->get('form.factory')->create($type, $resource);
301
    }
302
303
    /**
304
     * @param Request $request
305
     * @param RequestConfiguration $configuration
306
     * @param UserInterface $user
307
     *
308
     * @return RedirectResponse
309
     */
310
    protected function handleExpiredToken(Request $request, RequestConfiguration $configuration, UserInterface $user)
311
    {
312
        $user->setPasswordResetToken(null);
313
        $user->setPasswordRequestedAt(null);
314
315
        $this->manager->flush();
316
317
        if (!$configuration->isHtmlRequest()) {
318
            return $this->viewHandler->handle($configuration, View::create($user, Response::HTTP_BAD_REQUEST));
319
        }
320
321
        $this->addFlash('error', 'sylius.user.password.reset.token_expired');
322
323
        $redirectRouteName = $this->getSyliusAttribute($request, 'redirect', null);
324
        Assert::notNull($redirectRouteName, 'Redirect is not configured.');
325
326
        return new RedirectResponse($this->container->get('router')->generate($redirectRouteName));
327
    }
328
329
    /**
330
     * @param GeneratorInterface $generator
331
     * @param UserInterface $user
332
     * @param string $senderEvent
333
     */
334
    protected function handleResetPasswordRequest(GeneratorInterface $generator, UserInterface $user, $senderEvent)
335
    {
336
        $user->setPasswordResetToken($generator->generate());
337
        $user->setPasswordRequestedAt(new \DateTime());
338
339
        /* I have to use doctrine manager directly, because domain manager functions add a flash messages. I can't get rid of them.*/
340
        $manager = $this->container->get('doctrine.orm.default_entity_manager');
341
        $manager->persist($user);
342
        $manager->flush();
343
344
        $dispatcher = $this->container->get('event_dispatcher');
345
        $dispatcher->dispatch($senderEvent, new GenericEvent($user));
346
    }
347
348
    /**
349
     * @param Request $request
350
     * @param RequestConfiguration $configuration
351
     * @param UserInterface $user
352
     * @param string $newPassword
353
     *
354
     * @return Response
355
     */
356
    protected function handleResetPassword(Request $request, RequestConfiguration $configuration, UserInterface $user, $newPassword)
357
    {
358
        $user->setPlainPassword($newPassword);
359
        $user->setPasswordResetToken(null);
360
        $user->setPasswordRequestedAt(null);
361
362
        $dispatcher = $this->container->get('event_dispatcher');
363
        $dispatcher->dispatch(UserEvents::PRE_PASSWORD_RESET, new GenericEvent($user));
364
365
        $this->manager->flush();
366
        $this->addFlash('success', 'sylius.user.password.reset.success');
367
368
        $dispatcher->dispatch(UserEvents::POST_PASSWORD_RESET, new GenericEvent($user));
369
370
        if (!$configuration->isHtmlRequest()) {
371
            return $this->viewHandler->handle($configuration, View::create(null, Response::HTTP_NO_CONTENT));
372
        }
373
374
        $redirectRouteName = $this->getSyliusAttribute($request, 'redirect', null);
375
        Assert::notNull($redirectRouteName, 'Redirect is not configured.');
376
377
        return new RedirectResponse($this->container->get('router')->generate($redirectRouteName));
378
    }
379
380
    /**
381
     * @param Request $request
382
     * @param RequestConfiguration $configuration
383
     * @param UserInterface $user
384
     * @param string $newPassword
385
     *
386
     * @return Response
387
     */
388
    protected function handleChangePassword(Request $request, RequestConfiguration $configuration, UserInterface $user, $newPassword)
389
    {
390
        $user->setPlainPassword($newPassword);
391
392
        $dispatcher = $this->container->get('event_dispatcher');
393
        $dispatcher->dispatch(UserEvents::PRE_PASSWORD_CHANGE, new GenericEvent($user));
394
395
        $this->manager->flush();
396
        $this->addFlash('success', 'sylius.user.password.change.success');
397
398
        $dispatcher->dispatch(UserEvents::POST_PASSWORD_CHANGE, new GenericEvent($user));
399
400
        if (!$configuration->isHtmlRequest()) {
401
            return $this->viewHandler->handle($configuration, View::create(null, Response::HTTP_NO_CONTENT));
402
        }
403
404
        $redirectRouteName = $this->getSyliusAttribute($request, 'redirect', null);
405
        Assert::notNull($redirectRouteName, 'Redirect is not configured.');
406
407
        return new RedirectResponse($this->container->get('router')->generate($redirectRouteName));
408
    }
409
410
    /**
411
     * @param Request $request
412
     * @param string $attribute
413
     * @param mixed $default
414
     *
415
     * @return mixed
416
     */
417
    private function getSyliusAttribute(Request $request, $attribute, $default = null)
418
    {
419
        $attributes = $request->attributes->get('_sylius');
420
421
        return isset($attributes[$attribute]) ? $attributes[$attribute] : $default;
422
    }
423
}
424