Passed
Pull Request — main (#308)
by Paul
29:45 queued 20:02
created

displayVettingTypesAction()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 56
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 32
nc 4
nop 2
dl 0
loc 56
rs 8.7857
c 1
b 0
f 0

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 2014 SURFnet bv
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
0 ignored issues
show
Coding Style introduced by
PHP version not specified
Loading history...
Coding Style introduced by
Missing @category tag in file comment
Loading history...
Coding Style introduced by
Missing @package tag in file comment
Loading history...
Coding Style introduced by
Missing @author tag in file comment
Loading history...
Coding Style introduced by
Missing @license tag in file comment
Loading history...
Coding Style introduced by
Missing @link tag in file comment
Loading history...
20
21
namespace Surfnet\StepupSelfService\SelfServiceBundle\Controller;
22
23
use DateInterval;
24
use Mpdf\Mpdf;
25
use Mpdf\Output\Destination as MpdfDestination;
26
use Psr\Log\LoggerInterface;
27
use Surfnet\StepupMiddlewareClientBundle\Identity\Dto\VerifiedSecondFactor;
28
use Surfnet\StepupSelfService\SelfServiceBundle\Service\ControllerCheckerService;
29
use Surfnet\StepupSelfService\SelfServiceBundle\Service\InstitutionConfigurationOptionsService;
30
use Surfnet\StepupSelfService\SelfServiceBundle\Service\RaLocationService;
31
use Surfnet\StepupSelfService\SelfServiceBundle\Service\RaService;
32
use Surfnet\StepupSelfService\SelfServiceBundle\Service\SecondFactorAvailabilityHelper;
33
use Surfnet\StepupSelfService\SelfServiceBundle\Service\SecondFactorService;
34
use Surfnet\StepupSelfService\SelfServiceBundle\Service\VettingTypeService;
35
use Surfnet\StepupSelfService\SelfServiceBundle\Value\VettingType\VettingTypeInterface;
36
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
37
use Symfony\Component\HttpFoundation\RedirectResponse;
38
use Symfony\Component\HttpFoundation\Request;
39
use Symfony\Component\HttpFoundation\Response;
40
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
41
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
42
use Symfony\Component\Routing\Attribute\Route;
43
44
/**
45
 * TODO: split into smaller controllers
46
 * TODO: create PDF generation in dedicated service
47
 */
0 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @package tag in class comment
Loading history...
Coding Style introduced by
Missing @author tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
48
class RegistrationController extends AbstractController
49
{
50
    public function __construct(
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __construct()
Loading history...
51
        private readonly VettingTypeService $vettingTypeService,
52
        private readonly InstitutionConfigurationOptionsService $configurationOptionsService,
53
        private readonly SecondFactorService $secondFactorService,
54
        private readonly LoggerInterface $logger,
55
        private readonly SecondFactorAvailabilityHelper $secondFactorAvailabilityHelper,
56
        private readonly RaService $raService,
57
        private readonly RaLocationService $raLocationService,
58
        private readonly ControllerCheckerService $checkerService,
59
    ) {
60
    }
61
62
    #[Route(
63
        path: '/registration/select-token',
64
        name: 'ss_registration_display_types',
65
        methods: ['GET'],
66
    )]
67
    public function displaySecondFactorTypes(): Response
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function displaySecondFactorTypes()
Loading history...
68
    {
69
        $institution = $this->getUser()->getIdentity()->institution;
70
        $institutionConfigurationOptions = $this->configurationOptionsService
71
            ->getInstitutionConfigurationOptionsFor($institution);
72
73
        $identity = $this->getUser()->getIdentity();
74
75
        // Get all available second factors from the config.
76
        $allSecondFactors = $this->getParameter('ss.enabled_second_factors');
77
78
        $secondFactors = $this->secondFactorService->getSecondFactorsForIdentity(
79
            $identity,
80
            $allSecondFactors,
81
            $institutionConfigurationOptions->allowedSecondFactors,
82
            $institutionConfigurationOptions->numberOfTokensPerIdentity
83
        );
84
85
        if ($secondFactors->getRegistrationsLeft() <= 0) {
86
            $this->logger->notice(
87
                'User tried to register a new token but maximum number of tokens is reached. Redirecting to overview'
88
            );
89
            return $this->forward(
90
                'Surfnet\StepupSelfService\SelfServiceBundle\Controller\SecondFactor\SecondFactorListController'
91
            );
92
        }
93
94
        $availableTokens = $this->secondFactorAvailabilityHelper->filter($secondFactors);
95
96
        return $this->render(
97
            'registration/display_second_factor_types.html.twig',
98
            [
99
                'commonName' => $this->getUser()->getIdentity()->commonName,
100
                'availableSecondFactors' => $availableTokens,
101
                'verifyEmail' => $this->checkerService->emailVerificationIsRequired(),
102
            ]
103
        );
104
    }
105
106
    #[Route(
107
        path: '/second-factor/{secondFactorId}/vetting-types',
108
        name: 'ss_second_factor_vetting_types',
109
        methods:  ['GET'],
110
    )]
111
    public function displayVettingTypes(Request $request, string $secondFactorId): Response
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function displayVettingTypes()
Loading history...
112
    {
113
        /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
114
         * @var VettingTypeService
115
         */
116
        $vettingTypeService = $this->vettingTypeService;
117
        $vettingTypeCollection = $vettingTypeService->vettingTypes($this->getUser()->getIdentity(), $secondFactorId);
118
119
        $nudgeSelfAssertedTokens = $vettingTypeCollection->isPreferred(VettingTypeInterface::SELF_ASSERTED_TOKENS);
120
        $nudgeRaVetting = $vettingTypeCollection->isPreferred(VettingTypeInterface::ON_PREMISE);
121
122
        // Nudging section: helping the Identity into choosing the right vetting type:
123
124
        // Option 1: A self-asserted token registration nudge was requested via query string (?activate=self)
125
        if ($nudgeSelfAssertedTokens && $vettingTypeCollection->allowSelfAssertedTokens()) {
126
            $this->logger->notice('Nudging (forcing) self-asserted token registration');
127
            return $this->forward(
128
                'Surfnet\StepupSelfService\SelfServiceBundle\Controller\SelfAssertedTokensController::selfAssertedTokenRegistration',
129
                ['secondFactorId' => $secondFactorId]
130
            );
131
        }
132
133
        // Option 2: A ra-vetting nudge was requested via query string (?activate=ra)
134
        if ($nudgeRaVetting) {
135
            $this->logger->notice('Nudging (forcing) RA vetting');
136
            return $this->forward(
137
                'Surfnet\StepupSelfService\SelfServiceBundle\Controller\RegistrationController::sendRegistrationEmail',
138
                ['secondFactorId' => $secondFactorId]
139
            );
140
        }
141
142
        // Option 3: non-formal nudge, skip over selection screen. As only ra vetting is available.
143
        if (!$vettingTypeCollection->allowSelfVetting() && !$vettingTypeCollection->allowSelfAssertedTokens()) {
144
            $this->logger
145
                ->notice(
146
                    'Skipping ahead to the RA vetting option as self vetting or self-asserted tokens are not allowed'
147
                );
148
            return $this->forward(
149
                'Surfnet\StepupSelfService\SelfServiceBundle\Controller\RegistrationController::sendRegistrationEmail',
150
                ['secondFactorId' => $secondFactorId]
151
            );
152
        }
153
154
        $institution = $this->getUser()->getIdentity()->institution;
155
        $currentLocale = $request->getLocale();
156
        $vettingTypeHint = $vettingTypeService->vettingTypeHint($institution, $currentLocale);
157
158
        return $this->render(
159
            'registration/display_vetting_types.html.twig',
160
            [
161
                'allowSelfVetting' => $vettingTypeCollection->allowSelfVetting(),
162
                'allowSelfAssertedTokens' => $vettingTypeCollection->allowSelfAssertedTokens(),
163
                'hasVettingTypeHint' => !is_null($vettingTypeHint),
164
                'vettingTypeHint' => $vettingTypeHint,
165
                'verifyEmail' => $this->checkerService->emailVerificationIsRequired(),
166
                'secondFactorId' => $secondFactorId,
167
            ]
168
        );
169
    }
170
171
172
    #[Route(
173
        path: '/registration/{secondFactorId}/email-verification-email-sent',
174
        name: 'ss_registration_email_verification_email_sent',
175
        methods: ['GET'],
176
    )]
177
    public function emailVerificationEmailSent(): Response
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function emailVerificationEmailSent()
Loading history...
178
    {
179
        return $this->render(
180
            view: 'registration/email_verification_email_sent.html.twig',
181
            parameters: ['email' => $this->getUser()->getIdentity()->email]);
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 8 spaces, but found 12.
Loading history...
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
182
    }
183
184
    #[Route(
185
        path: '/verify-email',
186
        name: 'ss_registration_verify_email',
187
        methods: ['GET'],
188
    )]
189
    public function verifyEmail(Request $request): Response
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function verifyEmail()
Loading history...
190
    {
191
        $nonce = $request->query->get('n', '');
192
        $identityId = $this->getUser()->getIdentity()->id;
193
        $secondFactor = $this->secondFactorService->findUnverifiedByVerificationNonce($identityId, $nonce);
194
195
        if ($secondFactor === null) {
196
            throw new NotFoundHttpException('No second factor can be verified using this URL.');
197
        }
198
199
        if ($this->secondFactorService->verifyEmail($identityId, $nonce)) {
200
            return $this->redirectToRoute(
201
                'ss_second_factor_vetting_types',
202
                ['secondFactorId' => $secondFactor->id]
203
            );
204
        }
205
206
        return $this->render('registration/verify_email.html.twig');
207
    }
208
209
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $secondFactorId should have a doc-comment as per coding-style.
Loading history...
210
     * Intermediate action where the registration mail is sent. After which the
211
     * email-sent page is displayed. Preventing the mail message from being sent
212
     * over and over again when the user performs a page reload.
213
     */
0 ignored issues
show
Coding Style introduced by
There must be no blank lines after the function comment
Loading history...
Coding Style introduced by
Missing @return tag in function comment
Loading history...
214
    #[Route(
215
        path: '/registration/{secondFactorId}/send-registration-email',
216
        name: 'ss_registration_send_registration_email',
217
        methods: ['GET'],
218
    )]
219
220
    public function sendRegistrationEmail(string $secondFactorId): RedirectResponse
221
    {
222
        // Send the registration email
223
        $this->raService
224
            ->sendRegistrationMailMessage($this->getUser()->getIdentity()->id, $secondFactorId);
225
        return $this->redirectToRoute(
226
            'ss_registration_registration_email_sent',
227
            ['secondFactorId' => $secondFactorId]
228
        );
229
    }
230
231
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
232
     * @param $secondFactorId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
233
     * @return Response
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
234
     */
235
    #[Route(
236
        path: '/registration/{secondFactorId}/registration-email-sent',
237
        name: 'ss_registration_registration_email_sent',
238
        methods: ['GET'],
239
    )]
240
    public function registrationEmailSent($secondFactorId): Response
241
    {
242
        $parameters = $this->buildRegistrationActionParameters($secondFactorId);
243
        // Report that it was sent
244
        return $this->render(
245
            'registration/registration_email_sent.html.twig',
246
            $parameters
247
        );
248
    }
249
250
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
251
     * @param $secondFactorId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
252
     * @return Response
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
253
     */
254
    #[Route(
255
        path: '/registration/{secondFactorId}/registration-pdf',
256
        name: 'ss_registration_registration_pdf',
257
        methods: ['GET'],
258
    )]
259
    public function registrationPdf($secondFactorId): Response
260
    {
261
        $parameters = $this->buildRegistrationActionParameters($secondFactorId);
262
263
        $response = $this->render(
264
            'registration/registration_email_sent_pdf.html.twig',
265
            $parameters
266
        );
267
        $content = $response->getContent();
268
269
        $mpdf = new Mpdf(
270
            ['tempDir' => sys_get_temp_dir()]
271
        );
272
        $mpdf->setLogger($this->logger);
273
274
        $mpdf->WriteHTML($content);
275
        $output = $mpdf->Output('registration-code.pdf', MpdfDestination::STRING_RETURN);
276
277
        $response = new Response($output);
278
        $disposition = $response->headers->makeDisposition(
279
            ResponseHeaderBag::DISPOSITION_ATTACHMENT,
280
            'registration-code.pdf'
281
        );
282
283
        $response->headers->set('Content-Disposition', $disposition);
284
        $response->headers->set('Content-Description', 'File Transfer');
285
        $response->headers->set('Content-Transfer-Encoding', 'binary');
286
        $response->headers->set('Cache-Control', 'public, must-revalidate, max-age=0');
287
        $response->headers->set('Pragma', 'public');
288
        $response->headers->set('Expires', 'Sat, 26 Jul 1997 05:00:00 GMT');
289
        $response->headers->set('Last-Modified', '' . gmdate('D, d M Y H:i:s') . ' GMT');
290
        $response->headers->set('Content-Type', 'application/pdf');
291
292
        return $response;
293
    }
294
295
    private function buildRegistrationActionParameters($secondFactorId): array
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function buildRegistrationActionParameters()
Loading history...
Coding Style introduced by
Private method name "RegistrationController::buildRegistrationActionParameters" must be prefixed with an underscore
Loading history...
296
    {
297
        $identity = $this->getUser()->getIdentity();
298
299
        /** @var VerifiedSecondFactor $secondFactor */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
300
        $secondFactor = $this->secondFactorService->findOneVerified($secondFactorId);
301
302
        $parameters = [
303
            'email'            => $identity->email,
304
            'secondFactorId'   => $secondFactor->id,
305
            'registrationCode' => $secondFactor->registrationCode,
306
            'expirationDate'   => $secondFactor->registrationRequestedAt->add(
307
                new DateInterval('P14D')
308
            ),
309
            'locale'           => $identity->preferredLocale,
310
            'verifyEmail'      => $this->checkerService->emailVerificationIsRequired(),
311
        ];
312
313
        $institutionConfigurationOptions = $this->configurationOptionsService
314
            ->getInstitutionConfigurationOptionsFor($identity->institution);
315
316
        if ($institutionConfigurationOptions->useRaLocations) {
317
            $parameters['raLocations'] = $this->raLocationService->listRaLocationsFor($identity->institution);
318
        } elseif (!$institutionConfigurationOptions->showRaaContactInformation) {
319
            $parameters['ras'] = $this->raService->listRasWithoutRaas($identity->institution);
320
        } else {
321
            $parameters['ras'] = $this->raService->listRas($identity->institution);
322
        }
323
324
        return $parameters;
325
    }
326
}
327