Completed
Push — symfony3 ( a82edd...ec9673 )
by Kamil
17:27
created

UserController::generateRequestPasswordResetUrl()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 1
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
        $syliusConfiguration = $request->attributes->get('_sylius');
55
        $formType = isset($syliusConfiguration['form']) ? $syliusConfiguration['form'] : 'sylius_user_change_password';
56
        $form = $this->createResourceForm($configuration, $formType, $changePassword);
57
58
        if (in_array($request->getMethod(), ['POST', 'PUT', 'PATCH']) && $form->submit($request->request->get($form->getName()), !$request->isMethod('PATCH'))->isValid()) {
59
            return $this->handleChangePassword($request, $configuration, $user, $changePassword->getNewPassword());
60
        }
61
62
        if (!$configuration->isHtmlRequest()) {
63
            return $this->viewHandler->handle($configuration, View::create($form, Response::HTTP_BAD_REQUEST));
64
        }
65
66
        return $this->container->get('templating')->renderResponse(
67
            $configuration->getTemplate('changePassword.html'),
68
            ['form' => $form->createView()]
69
        );
70
    }
71
72
    /**
73
     * @param Request $request
74
     *
75
     * @return Response
76
     */
77
    public function requestPasswordResetTokenAction(Request $request)
78
    {
79
        /** @var GeneratorInterface $generator */
80
        $generator = $this->container->get(sprintf('sylius.%s.token_generator.password_reset', $this->metadata->getName()));
81
82
        return $this->prepareResetPasswordRequest($request, $generator, UserEvents::REQUEST_RESET_PASSWORD_TOKEN);
83
    }
84
85
    /**
86
     * @param Request $request
87
     *
88
     * @return Response
89
     */
90
    public function requestPasswordResetPinAction(Request $request)
91
    {
92
        /** @var GeneratorInterface $generator */
93
        $generator = $this->container->get(sprintf('sylius.%s.pin_generator.password_reset', $this->metadata->getName()));
94
95
        return $this->prepareResetPasswordRequest($request, $generator, UserEvents::REQUEST_RESET_PASSWORD_PIN);
96
    }
97
98
    /**
99
     * @param Request $request
100
     * @param string $token
101
     *
102
     * @return Response
103
     */
104
    public function resetPasswordAction(Request $request, $token)
105
    {
106
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
107
        /** @var UserInterface $user */
108
        $user = $this->repository->findOneBy(['passwordResetToken' => $token]);
109
        if (null === $user) {
110
            throw new NotFoundHttpException('Token not found.');
111
        }
112
113
        $resetting = $this->metadata->getParameter('resetting');
114
        $lifetime = new \DateInterval($resetting['token']['ttl']);
115
        if (!$user->isPasswordRequestNonExpired($lifetime)) {
116
            return $this->handleExpiredToken($request, $configuration, $user);
117
        }
118
119
        $passwordReset = new PasswordReset();
120
        $syliusConfiguration = $request->attributes->get('_sylius');
121
        $formType = isset($syliusConfiguration['form']) ? $syliusConfiguration['form'] : 'sylius_user_reset_password';
122
        $form = $this->createResourceForm($configuration, $formType, $passwordReset);
123
124
        if (in_array($request->getMethod(), ['POST', 'PUT', 'PATCH']) && $form->submit($request->request->get($form->getName()), !$request->isMethod('PATCH'))->isValid()) {
125
            return $this->handleResetPassword($request, $configuration, $user, $passwordReset->getPassword());
126
        }
127
128
        if (!$configuration->isHtmlRequest()) {
129
            return $this->viewHandler->handle($configuration, View::create($form, Response::HTTP_BAD_REQUEST));
130
        }
131
132
        return $this->container->get('templating')->renderResponse(
133
            $configuration->getTemplate('resetPassword.html'),
134
            [
135
                'form' => $form->createView(),
136
                'user' => $user,
137
            ]
138
        );
139
    }
140
141
    /**
142
     * @param Request $request
143
     * @param string $token
144
     *
145
     * @return Response
146
     */
147
    public function verifyAction(Request $request, $token)
148
    {
149
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
150
        $syliusConfiguration = $request->attributes->get('_sylius');
151
        $redirectRoute = isset($syliusConfiguration['redirect']) ? $syliusConfiguration['redirect'] : null;
152
153
        $response = $this->redirectToRoute($redirectRoute);
154
155
        /** @var UserInterface $user */
156
        $user = $this->repository->findOneBy(['emailVerificationToken' => $token]);
157
        if (null === $user) {
158
            if (!$configuration->isHtmlRequest()) {
159
                return $this->viewHandler->handle($configuration, View::create($configuration, Response::HTTP_BAD_REQUEST));
160
            }
161
162
            $this->addFlash('error', 'sylius.user.verification.error');
163
164
            return $this->redirectToRoute($redirectRoute);
165
        }
166
167
        $eventDispatcher = $this->container->get('event_dispatcher');
168
        $eventDispatcher->dispatch(UserEvents::PRE_EMAIL_VERIFICATION, new GenericEvent($user));
169
170
        $user->setVerifiedAt(new \DateTime());
171
        $user->setEmailVerificationToken(null);
172
173
        $this->manager->flush();
174
175
        $eventDispatcher->dispatch(UserEvents::POST_EMAIL_VERIFICATION, new GenericEvent($user));
176
177
        if (!$configuration->isHtmlRequest()) {
178
            return $this->viewHandler->handle($configuration, View::create($user));
179
        }
180
181
        $this->addFlash(
182
            'success',
183
            isset($syliusConfiguration['flash']) ? $syliusConfiguration['flash'] : 'sylius.user.verification.success'
184
        );
185
186
        return $response;
187
    }
188
189
    /**
190
     * @param Request $request
191
     *
192
     * @return Response
193
     */
194
    public function requestVerificationTokenAction(Request $request)
195
    {
196
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
197
        $syliusConfiguration = $request->attributes->get('_sylius');
198
        $redirectRoute = isset($syliusConfiguration['redirect']) ? $syliusConfiguration['redirect'] : 'referer';
199
200
        /** @var UserInterface $user */
201
        $user = $this->container->get('sylius.context.customer')->getCustomer()->getUser();
202
        if (null !== $user->getVerifiedAt()) {
203
            if (!$configuration->isHtmlRequest()) {
204
                return $this->viewHandler->handle($configuration, View::create($configuration, Response::HTTP_BAD_REQUEST));
205
            }
206
207
            $this->addFlash('notice', 'sylius.user.verification.notice.verified');
208
209
            return $this->redirectHandler->redirectToRoute($configuration, $redirectRoute);
210
        }
211
212
        $tokenGenerator = $this->container->get(sprintf('sylius.%s.token_generator.email_verification', $this->metadata->getName()));
213
        $user->setEmailVerificationToken($tokenGenerator->generate());
214
215
        $this->manager->flush();
216
217
        $eventDispatcher = $this->container->get('event_dispatcher');
218
        $eventDispatcher->dispatch(UserEvents::REQUEST_VERIFICATION_TOKEN, new GenericEvent($user));
219
220
        if (!$configuration->isHtmlRequest()) {
221
            return $this->viewHandler->handle($configuration, View::create(null, Response::HTTP_NO_CONTENT));
222
        }
223
224
        $this->addFlash('success', 'sylius.user.verification.request.success');
225
226
        return $this->redirectHandler->redirectToRoute($configuration, $redirectRoute);
227
    }
228
229
    /**
230
     * @param Request $request
231
     * @param GeneratorInterface $generator
232
     * @param string $senderEvent
233
     *
234
     * @return Response
235
     */
236
    protected function prepareResetPasswordRequest(Request $request, GeneratorInterface $generator, $senderEvent)
237
    {
238
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
239
240
        $passwordReset = new PasswordResetRequest();
241
        $syliusConfiguration = $request->attributes->get('_sylius');
242
        $template = isset($syliusConfiguration['template']) ? $syliusConfiguration['template'] : 'SyliusUserBundle:User:requestPasswordReset.html.twig';
243
        $formType = isset($syliusConfiguration['form']) ? $syliusConfiguration['form'] : 'sylius_user_request_password_reset';
244
        $form = $this->createResourceForm($configuration, $formType, $passwordReset);
245
246
        if (in_array($request->getMethod(), ['POST', 'PUT', 'PATCH']) && $form->submit($request->request->get($form->getName()), !$request->isMethod('PATCH'))->isValid()) {
247
            $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...
248
            if (null !== $user) {
249
                $this->handleResetPasswordRequest($generator, $user, $senderEvent);
250
            }
251
252
            if (!$configuration->isHtmlRequest()) {
253
                return $this->viewHandler->handle($configuration, View::create(null, Response::HTTP_NO_CONTENT));
254
            }
255
256
            $this->addFlash('success', 'sylius.user.password.reset.requested');
257
            $redirectRoute = isset($syliusConfiguration['redirect']) ? $syliusConfiguration['redirect'] : 'sylius_user_security_login';
258
259
            if (is_array($redirectRoute)) {
260
                return $this->redirectHandler->redirectToRoute(
261
                    $configuration,
262
                    $configuration->getParameters()->get('redirect')['route'],
263
                    $configuration->getParameters()->get('redirect')['parameters']
264
                );
265
            }
266
267
            return $this->redirectHandler->redirectToRoute($configuration, $redirectRoute);
268
        }
269
270
        if (!$configuration->isHtmlRequest()) {
271
            return $this->viewHandler->handle($configuration, View::create($form, Response::HTTP_BAD_REQUEST));
272
        }
273
274
        return $this->container->get('templating')->renderResponse(
275
            $template,
276
            [
277
                'form' => $form->createView(),
278
            ]
279
        );
280
    }
281
282
    /**
283
     * @param string $type
284
     * @param string $message
285
     */
286
    protected function addFlash($type, $message)
287
    {
288
        $translator = $this->container->get('translator');
289
        $this->container->get('session')->getFlashBag()->add($type, $translator->trans($message, [], 'flashes'));
290
    }
291
292
    /**
293
     * @param RequestConfiguration $configuration
294
     * @param string $type
295
     * @param mixed $resource
296
     *
297
     * @return FormInterface
298
     */
299
    protected function createResourceForm(RequestConfiguration $configuration, $type, $resource)
300
    {
301
        if (!$configuration->isHtmlRequest()) {
302
            return $this->container->get('form.factory')->createNamed('', $type, $resource, ['csrf_protection' => false]);
303
        }
304
305
        return $this->container->get('form.factory')->create($type, $resource);
306
    }
307
308
    /**
309
     * @param Request $request
310
     * @param RequestConfiguration $configuration
311
     * @param UserInterface $user
312
     *
313
     * @return RedirectResponse
314
     */
315
    protected function handleExpiredToken(Request $request, RequestConfiguration $configuration, UserInterface $user)
316
    {
317
        $user->setPasswordResetToken(null);
318
        $user->setPasswordRequestedAt(null);
319
320
        $this->manager->flush();
321
322
        if (!$configuration->isHtmlRequest()) {
323
            return $this->viewHandler->handle($configuration, View::create($user, Response::HTTP_BAD_REQUEST));
324
        }
325
326
        $this->addFlash('error', 'sylius.user.password.reset.token_expired');
327
328
        $redirectRouteName = $request->attributes->get('_sylius[redirect]', null, true);
0 ignored issues
show
Unused Code introduced by
The call to ParameterBag::get() has too many arguments starting with true.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
329
        Assert::notNull($redirectRouteName, 'Redirect is not configured.');
330
331
        return new RedirectResponse($this->container->get('router')->generate($redirectRouteName));
332
    }
333
334
    /**
335
     * @param GeneratorInterface $generator
336
     * @param UserInterface $user
337
     * @param string $senderEvent
338
     */
339
    protected function handleResetPasswordRequest(GeneratorInterface $generator, UserInterface $user, $senderEvent)
340
    {
341
        $user->setPasswordResetToken($generator->generate());
342
        $user->setPasswordRequestedAt(new \DateTime());
343
344
        /* I have to use doctrine manager directly, because domain manager functions add a flash messages. I can't get rid of them.*/
345
        $manager = $this->container->get('doctrine.orm.default_entity_manager');
346
        $manager->persist($user);
347
        $manager->flush();
348
349
        $dispatcher = $this->container->get('event_dispatcher');
350
        $dispatcher->dispatch($senderEvent, new GenericEvent($user));
351
    }
352
353
    /**
354
     * @param Request $request
355
     * @param RequestConfiguration $configuration
356
     * @param UserInterface $user
357
     * @param string $newPassword
358
     *
359
     * @return Response
360
     */
361
    protected function handleResetPassword(Request $request, RequestConfiguration $configuration, UserInterface $user, $newPassword)
362
    {
363
        $user->setPlainPassword($newPassword);
364
        $user->setPasswordResetToken(null);
365
        $user->setPasswordRequestedAt(null);
366
367
        $dispatcher = $this->container->get('event_dispatcher');
368
        $dispatcher->dispatch(UserEvents::PRE_PASSWORD_RESET, new GenericEvent($user));
369
370
        $this->manager->flush();
371
        $this->addFlash('success', 'sylius.user.password.reset.success');
372
373
        $dispatcher->dispatch(UserEvents::POST_PASSWORD_RESET, new GenericEvent($user));
374
375
        if (!$configuration->isHtmlRequest()) {
376
            return $this->viewHandler->handle($configuration, View::create(null, Response::HTTP_NO_CONTENT));
377
        }
378
379
        $syliusConfiguration = $request->attributes->get('_sylius');
380
        $redirectRoute = isset($syliusConfiguration['redirect']) ? $syliusConfiguration['redirect'] : 'sylius_user_security_login';
381
382
        return new RedirectResponse($this->container->get('router')->generate($redirectRoute));
383
    }
384
385
    /**
386
     * @param Request $request
387
     * @param RequestConfiguration $configuration
388
     * @param UserInterface $user
389
     * @param string $newPassword
390
     *
391
     * @return Response
392
     */
393
    protected function handleChangePassword(Request $request, RequestConfiguration $configuration, UserInterface $user, $newPassword)
394
    {
395
        $user->setPlainPassword($newPassword);
396
397
        $dispatcher = $this->container->get('event_dispatcher');
398
        $dispatcher->dispatch(UserEvents::PRE_PASSWORD_CHANGE, new GenericEvent($user));
399
400
        $this->manager->flush();
401
        $this->addFlash('success', 'sylius.user.password.change.success');
402
403
        $dispatcher->dispatch(UserEvents::POST_PASSWORD_CHANGE, new GenericEvent($user));
404
405
        if (!$configuration->isHtmlRequest()) {
406
            return $this->viewHandler->handle($configuration, View::create(null, Response::HTTP_NO_CONTENT));
407
        }
408
409
        $syliusConfiguration = $request->attributes->get('_sylius');
410
        $redirectRoute = isset($syliusConfiguration['redirect']) ? $syliusConfiguration['redirect'] : 'sylius_account_profile_show';
411
412
        return new RedirectResponse($this->container->get('router')->generate($redirectRoute));
413
    }
414
}
415