Passed
Push — trunk ( c83b87...a87e38 )
by Christian
22:40 queued 02:13
created

AuthController::loginPage()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 25
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 15
nc 2
nop 3
dl 0
loc 25
rs 9.7666
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace Shopware\Storefront\Controller;
4
5
use Shopware\Core\Checkout\Customer\Exception\BadCredentialsException;
6
use Shopware\Core\Checkout\Customer\Exception\CustomerAuthThrottledException;
7
use Shopware\Core\Checkout\Customer\Exception\CustomerNotFoundByHashException;
8
use Shopware\Core\Checkout\Customer\Exception\CustomerNotFoundException;
9
use Shopware\Core\Checkout\Customer\Exception\CustomerOptinNotCompletedException;
10
use Shopware\Core\Checkout\Customer\Exception\CustomerRecoveryHashExpiredException;
11
use Shopware\Core\Checkout\Customer\SalesChannel\AbstractLoginRoute;
12
use Shopware\Core\Checkout\Customer\SalesChannel\AbstractLogoutRoute;
13
use Shopware\Core\Checkout\Customer\SalesChannel\AbstractResetPasswordRoute;
14
use Shopware\Core\Checkout\Customer\SalesChannel\AbstractSendPasswordRecoveryMailRoute;
15
use Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException;
16
use Shopware\Core\Framework\RateLimiter\Exception\RateLimitExceededException;
17
use Shopware\Core\Framework\Routing\Annotation\Since;
18
use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
19
use Shopware\Core\Framework\Validation\Exception\ConstraintViolationException;
20
use Shopware\Core\PlatformRequest;
21
use Shopware\Core\System\SalesChannel\Context\SalesChannelContextServiceInterface;
22
use Shopware\Core\System\SalesChannel\Context\SalesChannelContextServiceParameters;
23
use Shopware\Core\System\SalesChannel\SalesChannelContext;
24
use Shopware\Storefront\Checkout\Cart\SalesChannel\StorefrontCartFacade;
25
use Shopware\Storefront\Framework\Routing\Annotation\NoStore;
26
use Shopware\Storefront\Framework\Routing\RequestTransformer;
27
use Shopware\Storefront\Page\Account\Login\AccountGuestLoginPageLoadedHook;
28
use Shopware\Storefront\Page\Account\Login\AccountLoginPageLoadedHook;
29
use Shopware\Storefront\Page\Account\Login\AccountLoginPageLoader;
30
use Shopware\Storefront\Page\Account\RecoverPassword\AccountRecoverPasswordPageLoadedHook;
31
use Shopware\Storefront\Page\Account\RecoverPassword\AccountRecoverPasswordPageLoader;
32
use Symfony\Component\HttpFoundation\Request;
33
use Symfony\Component\HttpFoundation\Response;
34
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
35
use Symfony\Component\Routing\Annotation\Route;
36
37
/**
38
 * @package storefront
39
 *
40
 * @Route(defaults={"_routeScope"={"storefront"}})
41
 *
42
 * @internal
43
 */
44
class AuthController extends StorefrontController
45
{
46
    private AccountLoginPageLoader $loginPageLoader;
47
48
    private AbstractSendPasswordRecoveryMailRoute $sendPasswordRecoveryMailRoute;
49
50
    private AbstractResetPasswordRoute $resetPasswordRoute;
51
52
    private AbstractLoginRoute $loginRoute;
53
54
    private AbstractLogoutRoute $logoutRoute;
55
56
    private StorefrontCartFacade $cartFacade;
57
58
    private AccountRecoverPasswordPageLoader $recoverPasswordPageLoader;
59
60
    private SalesChannelContextServiceInterface $salesChannelContext;
61
62
    /**
63
     * @internal
64
     */
65
    public function __construct(
66
        AccountLoginPageLoader $loginPageLoader,
67
        AbstractSendPasswordRecoveryMailRoute $sendPasswordRecoveryMailRoute,
68
        AbstractResetPasswordRoute $resetPasswordRoute,
69
        AbstractLoginRoute $loginRoute,
70
        AbstractLogoutRoute $logoutRoute,
71
        StorefrontCartFacade $cartFacade,
72
        AccountRecoverPasswordPageLoader $recoverPasswordPageLoader,
73
        SalesChannelContextServiceInterface $salesChannelContextService
74
    ) {
75
        $this->loginPageLoader = $loginPageLoader;
76
        $this->sendPasswordRecoveryMailRoute = $sendPasswordRecoveryMailRoute;
77
        $this->resetPasswordRoute = $resetPasswordRoute;
78
        $this->loginRoute = $loginRoute;
79
        $this->logoutRoute = $logoutRoute;
80
        $this->cartFacade = $cartFacade;
81
        $this->recoverPasswordPageLoader = $recoverPasswordPageLoader;
82
        $this->salesChannelContext = $salesChannelContextService;
83
    }
84
85
    /**
86
     * @Since("6.0.0.0")
87
     * @Route("/account/login", name="frontend.account.login.page", methods={"GET"})
88
     * @NoStore
89
     */
90
    public function loginPage(Request $request, RequestDataBag $data, SalesChannelContext $context): Response
91
    {
92
        /** @var string $redirect */
93
        $redirect = $request->get('redirectTo', 'frontend.account.home.page');
94
95
        $customer = $context->getCustomer();
96
97
        if ($customer !== null && $customer->getGuest() === false) {
98
            $request->request->set('redirectTo', $redirect);
99
100
            return $this->createActionResponse($request);
101
        }
102
103
        $page = $this->loginPageLoader->load($request, $context);
104
105
        $this->hook(new AccountLoginPageLoadedHook($page, $context));
106
107
        return $this->renderStorefront('@Storefront/storefront/page/account/register/index.html.twig', [
108
            'redirectTo' => $redirect,
109
            'redirectParameters' => $request->get('redirectParameters', json_encode([])),
110
            'page' => $page,
111
            'loginError' => (bool) $request->get('loginError'),
112
            'waitTime' => $request->get('waitTime'),
113
            'errorSnippet' => $request->get('errorSnippet'),
114
            'data' => $data,
115
        ]);
116
    }
117
118
    /**
119
     * @Since("6.3.4.1")
120
     * @Route("/account/guest/login", name="frontend.account.guest.login.page", methods={"GET"})
121
     * @NoStore
122
     */
123
    public function guestLoginPage(Request $request, SalesChannelContext $context): Response
124
    {
125
        /** @var string $redirect */
126
        $redirect = $request->get('redirectTo', 'frontend.account.home.page');
127
128
        $customer = $context->getCustomer();
129
130
        if ($customer !== null) {
131
            $request->request->set('redirectTo', $redirect);
132
133
            return $this->createActionResponse($request);
134
        }
135
136
        $waitTime = (int) $request->get('waitTime');
137
        if ($waitTime) {
138
            $this->addFlash(self::INFO, $this->trans('account.loginThrottled', ['%seconds%' => $waitTime]));
139
        }
140
141
        if ((bool) $request->get('loginError')) {
142
            $this->addFlash(self::DANGER, $this->trans('account.orderGuestLoginWrongCredentials'));
143
        }
144
145
        $page = $this->loginPageLoader->load($request, $context);
146
147
        $this->hook(new AccountGuestLoginPageLoadedHook($page, $context));
148
149
        return $this->renderStorefront('@Storefront/storefront/page/account/guest-auth.html.twig', [
150
            'redirectTo' => $redirect,
151
            'redirectParameters' => $request->get('redirectParameters', json_encode([])),
152
            'page' => $page,
153
        ]);
154
    }
155
156
    /**
157
     * @Since("6.0.0.0")
158
     * @Route("/account/logout", name="frontend.account.logout.page", methods={"GET"})
159
     */
160
    public function logout(Request $request, SalesChannelContext $context, RequestDataBag $dataBag): 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

160
    public function logout(/** @scrutinizer ignore-unused */ Request $request, SalesChannelContext $context, RequestDataBag $dataBag): 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...
161
    {
162
        if ($context->getCustomer() === null) {
163
            return $this->redirectToRoute('frontend.account.login.page');
164
        }
165
166
        try {
167
            $this->logoutRoute->logout($context, $dataBag);
168
            $this->addFlash(self::SUCCESS, $this->trans('account.logoutSucceeded'));
169
170
            $parameters = [];
171
        } catch (ConstraintViolationException $formViolations) {
172
            $parameters = ['formViolations' => $formViolations];
173
        }
174
175
        return $this->redirectToRoute('frontend.account.login.page', $parameters);
176
    }
177
178
    /**
179
     * @Since("6.0.0.0")
180
     * @Route("/account/login", name="frontend.account.login", methods={"POST"}, defaults={"XmlHttpRequest"=true})
181
     */
182
    public function login(Request $request, RequestDataBag $data, SalesChannelContext $context): Response
183
    {
184
        $customer = $context->getCustomer();
185
186
        if ($customer !== null && $customer->getGuest() === false) {
187
            return $this->createActionResponse($request);
188
        }
189
190
        try {
191
            $token = $this->loginRoute->login($data, $context)->getToken();
192
            $cartBeforeNewContext = $this->cartFacade->get($token, $context);
193
194
            $newContext = $this->salesChannelContext->get(
195
                new SalesChannelContextServiceParameters(
196
                    $context->getSalesChannelId(),
197
                    $token,
198
                    $context->getLanguageIdChain()[0],
199
                    $context->getCurrencyId(),
200
                    $context->getDomainId(),
201
                    $context->getContext()
202
                )
203
            );
204
205
            // Update the sales channel context for CacheResponseSubscriber
206
            $request->attributes->set(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_CONTEXT_OBJECT, $newContext);
207
208
            if (!empty($token)) {
209
                $this->addCartErrors($cartBeforeNewContext);
210
211
                return $this->createActionResponse($request);
212
            }
213
        } catch (BadCredentialsException | UnauthorizedHttpException | CustomerOptinNotCompletedException | CustomerAuthThrottledException $e) {
214
            if ($e instanceof CustomerOptinNotCompletedException) {
215
                $errorSnippet = $e->getSnippetKey();
216
            }
217
218
            if ($e instanceof CustomerAuthThrottledException) {
219
                $waitTime = $e->getWaitTime();
220
            }
221
        }
222
223
        $data->set('password', null);
224
225
        return $this->forwardToRoute(
226
            'frontend.account.login.page',
227
            [
228
                'loginError' => true,
229
                'errorSnippet' => $errorSnippet ?? null,
230
                'waitTime' => $waitTime ?? null,
231
            ]
232
        );
233
    }
234
235
    /**
236
     * @Since("6.1.0.0")
237
     * @Route("/account/recover", name="frontend.account.recover.page", methods={"GET"})
238
     */
239
    public function recoverAccountForm(Request $request, SalesChannelContext $context): Response
240
    {
241
        $page = $this->loginPageLoader->load($request, $context);
242
243
        return $this->renderStorefront('@Storefront/storefront/page/account/profile/recover-password.html.twig', [
244
            'page' => $page,
245
        ]);
246
    }
247
248
    /**
249
     * @Since("6.1.0.0")
250
     * @Route("/account/recover", name="frontend.account.recover.request", methods={"POST"})
251
     */
252
    public function generateAccountRecovery(Request $request, RequestDataBag $data, SalesChannelContext $context): Response
253
    {
254
        try {
255
            $data->get('email')
256
                ->set('storefrontUrl', $request->attributes->get(RequestTransformer::STOREFRONT_URL));
257
258
            $this->sendPasswordRecoveryMailRoute->sendRecoveryMail(
259
                $data->get('email')->toRequestDataBag(),
260
                $context,
261
                false
262
            );
263
264
            $this->addFlash(self::SUCCESS, $this->trans('account.recoveryMailSend'));
265
        } catch (CustomerNotFoundException $e) {
266
            $this->addFlash(self::SUCCESS, $this->trans('account.recoveryMailSend'));
267
        } catch (InconsistentCriteriaIdsException $e) {
268
            $this->addFlash(self::DANGER, $this->trans('error.message-default'));
269
        } catch (RateLimitExceededException $e) {
270
            $this->addFlash(self::INFO, $this->trans('error.rateLimitExceeded', ['%seconds%' => $e->getWaitTime()]));
271
        }
272
273
        return $this->redirectToRoute('frontend.account.recover.page');
274
    }
275
276
    /**
277
     * @Since("6.1.0.0")
278
     * @Route("/account/recover/password", name="frontend.account.recover.password.page", methods={"GET"})
279
     */
280
    public function resetPasswordForm(Request $request, SalesChannelContext $context): Response
281
    {
282
        /** @var ?string $hash */
283
        $hash = $request->get('hash');
284
285
        if (!$hash || !\is_string($hash)) {
286
            $this->addFlash(self::DANGER, $this->trans('account.passwordHashNotFound'));
287
288
            return $this->redirectToRoute('frontend.account.recover.request');
289
        }
290
291
        try {
292
            $page = $this->recoverPasswordPageLoader->load($request, $context, $hash);
293
        } catch (ConstraintViolationException $e) {
294
            $this->addFlash(self::DANGER, $this->trans('account.passwordHashNotFound'));
295
296
            return $this->redirectToRoute('frontend.account.recover.request');
297
        }
298
299
        $this->hook(new AccountRecoverPasswordPageLoadedHook($page, $context));
300
301
        if ($page->getHash() === null || $page->isHashExpired()) {
302
            $this->addFlash(self::DANGER, $this->trans('account.passwordHashNotFound'));
303
304
            return $this->redirectToRoute('frontend.account.recover.request');
305
        }
306
307
        return $this->renderStorefront('@Storefront/storefront/page/account/profile/reset-password.html.twig', [
308
            'page' => $page,
309
            'formViolations' => $request->get('formViolations'),
310
        ]);
311
    }
312
313
    /**
314
     * @Since("6.1.0.0")
315
     * @Route("/account/recover/password", name="frontend.account.recover.password.reset", methods={"POST"})
316
     */
317
    public function resetPassword(RequestDataBag $data, SalesChannelContext $context): Response
318
    {
319
        $hash = $data->get('password')->get('hash');
320
321
        try {
322
            $pw = $data->get('password');
323
324
            $this->resetPasswordRoute->resetPassword($pw->toRequestDataBag(), $context);
325
326
            $this->addFlash(self::SUCCESS, $this->trans('account.passwordChangeSuccess'));
327
        } catch (ConstraintViolationException $formViolations) {
328
            $this->addFlash(self::DANGER, $this->trans('account.passwordChangeNoSuccess'));
329
330
            return $this->forwardToRoute(
331
                'frontend.account.recover.password.page',
332
                ['hash' => $hash, 'formViolations' => $formViolations, 'passwordFormViolation' => true]
333
            );
334
        } catch (CustomerNotFoundByHashException $e) {
335
            $this->addFlash(self::DANGER, $this->trans('account.passwordChangeNoSuccess'));
336
337
            return $this->forwardToRoute('frontend.account.recover.request');
338
        } catch (CustomerRecoveryHashExpiredException $e) {
339
            $this->addFlash(self::DANGER, $this->trans('account.passwordHashExpired'));
340
341
            return $this->forwardToRoute('frontend.account.recover.request');
342
        }
343
344
        return $this->redirectToRoute('frontend.account.profile.page');
345
    }
346
}
347