sendRegistrationEmailWithRas()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 48
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 30
nc 1
nop 6
dl 0
loc 48
rs 9.44
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Copyright 2016 SURFnet B.V.
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
namespace Surfnet\StepupMiddleware\CommandHandlingBundle\Identity\Service;
20
21
use Assert\Assertion;
22
use DateInterval;
23
use Psr\Log\LoggerInterface;
24
use Surfnet\Stepup\Configuration\Value\Institution;
25
use Surfnet\Stepup\DateTime\DateTime;
26
use Surfnet\Stepup\Identity\Value\SecondFactorId;
27
use Surfnet\StepupMiddleware\ApiBundle\Configuration\Service\InstitutionConfigurationOptionsService;
28
use Surfnet\StepupMiddleware\ApiBundle\Configuration\Service\RaLocationService;
29
use Surfnet\StepupMiddleware\ApiBundle\Identity\Service\IdentityService;
30
use Surfnet\StepupMiddleware\ApiBundle\Identity\Service\RaListingService;
31
use Surfnet\StepupMiddleware\ApiBundle\Identity\Service\SecondFactorService;
32
use Surfnet\StepupMiddleware\ApiBundle\Identity\Value\RegistrationAuthorityCredentials;
33
use Surfnet\StepupMiddleware\CommandHandlingBundle\Configuration\Service\EmailTemplateService;
34
use Surfnet\StepupMiddleware\CommandHandlingBundle\Value\Sender;
35
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
36
use Symfony\Component\Mailer\MailerInterface as Mailer;
37
use Symfony\Component\Mime\Address;
38
use Symfony\Contracts\Translation\TranslatorInterface;
39
40
/**
41
 * @SuppressWarnings("PHPMD.CouplingBetweenObjects")
42
 */
43
class RegistrationMailService
44
{
45
    private readonly string $fallbackLocale;
46
47
    /**
48
     * @SuppressWarnings("PHPMD.ExcessiveParameterList")
49
     */
50
    public function __construct(
51
        private readonly Mailer $mailer,
52
        private readonly Sender $sender,
53
        private readonly TranslatorInterface $translator,
54
        private readonly EmailTemplateService $emailTemplateService,
55
        string $fallbackLocale,
56
        private readonly string $selfServiceUrl,
57
        public InstitutionConfigurationOptionsService $institutionConfigurationOptionsService,
58
        private readonly IdentityService $identityService,
59
        private readonly SecondFactorService $secondFactorService,
60
        private readonly RaLocationService $raLocationsService,
61
        private readonly RaListingService $raListingService,
62
        private readonly LoggerInterface $logger,
63
    ) {
64
        Assertion::string($fallbackLocale, 'Fallback locale "%s" expected to be string, type %s given');
65
        $this->fallbackLocale = $fallbackLocale;
0 ignored issues
show
Bug introduced by
The property fallbackLocale is declared read-only in Surfnet\StepupMiddleware...RegistrationMailService.
Loading history...
66
    }
67
68
    public function send(string $identityId, string $secondFactorId): void
69
    {
70
        $this->logger->notice(sprintf('Start processing of a registration email for %s', $identityId));
71
        $identity = $this->identityService->find($identityId);
72
        $institution = new Institution($identity->institution->getInstitution());
73
        $institutionConfigurationOptions = $this->institutionConfigurationOptionsService
74
            ->findInstitutionConfigurationOptionsFor($institution);
75
        $verifiedSecondFactor = $this->secondFactorService->findVerified(new SecondFactorId($secondFactorId));
76
77
        if ($institutionConfigurationOptions->useRaLocationsOption->isEnabled()) {
78
            $this->logger->notice('Sending a registration mail with ra locations');
79
80
            $this->sendRegistrationEmailWithRaLocations(
81
                $identity->preferredLocale->getLocale(),
82
                $identity->commonName->getCommonName(),
83
                $identity->email->getEmail(),
84
                $verifiedSecondFactor->registrationCode,
85
                $this->getExpirationDateOfRegistration(
86
                    DateTime::fromString($verifiedSecondFactor->registrationRequestedAt->format(DateTime::FORMAT)),
87
                ),
88
                $this->raLocationsService->listRaLocationsFor($institution),
89
            );
90
91
            return;
92
        }
93
94
        $ras = $this->raListingService->listRegistrationAuthoritiesFor($identity->institution);
95
        if ($institutionConfigurationOptions->showRaaContactInformationOption->isEnabled()) {
96
            $this->logger->notice('Sending a registration mail with raa contact information');
97
            $this->sendRegistrationEmailWithRas(
98
                $identity->preferredLocale->getLocale(),
99
                $identity->commonName->getCommonName(),
100
                $identity->email->getEmail(),
101
                $verifiedSecondFactor->registrationCode,
102
                $this->getExpirationDateOfRegistration(
103
                    DateTime::fromString($verifiedSecondFactor->registrationRequestedAt->format(DateTime::FORMAT)),
104
                ),
105
                $ras,
106
            );
107
            return;
108
        }
109
110
        $rasWithoutRaas = array_filter($ras, fn(RegistrationAuthorityCredentials $ra): bool => !$ra->isRaa());
111
        $this->logger->notice(
112
            'Sending a registration mail with ra contact information as there are no RAAs at this location',
113
        );
114
        $this->sendRegistrationEmailWithRas(
115
            $identity->preferredLocale->getLocale(),
116
            $identity->commonName->getCommonName(),
117
            $identity->email->getEmail(),
118
            $verifiedSecondFactor->registrationCode,
119
            $this->getExpirationDateOfRegistration(
120
                DateTime::fromString($verifiedSecondFactor->registrationRequestedAt->format(DateTime::FORMAT)),
121
            ),
122
            $rasWithoutRaas,
123
        );
124
    }
125
126
    private function sendRegistrationEmailWithRas(
127
        string $locale,
128
        string $commonName,
129
        string $email,
130
        string $registrationCode,
131
        DateTime $expirationDate,
132
        array $ras,
133
    ): void {
134
        $subject = $this->translator->trans(
135
            'ss.mail.registration_email.subject',
136
            ['%commonName%' => $commonName],
137
            'messages',
138
            $locale,
139
        );
140
141
        $emailTemplate = $this->emailTemplateService->findByName(
142
            'registration_code_with_ras',
143
            $locale,
144
            $this->fallbackLocale,
145
        );
146
147
        // In TemplatedEmail email is a reserved keyword, we also use it as a parameter that can be used in the mail
148
        // message, to prevent having to update all templates, and prevent a 500 error from the mailer, we perform a
149
        // search and replace of the {email} parameter in the template.
150
        $emailTemplate->htmlContent = str_replace(
151
            '{email}',
152
            '{emailAddress}',
153
            $emailTemplate->htmlContent,
154
        );
155
        $parameters = [
156
            'templateString' => $emailTemplate->htmlContent,
157
            'locale' => $locale,
158
            'commonName' => $commonName,
159
            'emailAddress' => $email,
160
            'registrationCode' => $registrationCode,
161
            'expirationDate' => (string)$expirationDate,
162
            'ras' => $ras,
163
            'selfServiceUrl' => $this->selfServiceUrl,
164
        ];
165
166
        $message = new TemplatedEmail();
167
        $message
168
            ->from(new Address($this->sender->getEmail(), $this->sender->getName()))
169
            ->to(new Address($email, $commonName))
170
            ->subject($subject)
171
            ->htmlTemplate('@SurfnetStepupMiddlewareCommandHandling/SecondFactorMailService/email.html.twig')
172
            ->context($parameters);
173
        $this->mailer->send($message);
174
    }
175
176
    private function sendRegistrationEmailWithRaLocations(
177
        string $locale,
178
        string $commonName,
179
        string $email,
180
        string $registrationCode,
181
        DateTime $expirationDate,
182
        array $raLocations,
183
    ): void {
184
        $subject = $this->translator->trans(
185
            'ss.mail.registration_email.subject',
186
            ['%commonName%' => $commonName],
187
            'messages',
188
            $locale,
189
        );
190
191
        $emailTemplate = $this->emailTemplateService->findByName(
192
            'registration_code_with_ra_locations',
193
            $locale,
194
            $this->fallbackLocale,
195
        );
196
        // In TemplatedEmail email is a reserved keyword, we also use it as a parameter that can be used in the mail
197
        // message, to prevent having to update all templates, and prevent a 500 error from the mailer, we perform a
198
        // search and replace of the {email} parameter in the template.
199
        $emailTemplate->htmlContent = str_replace(
200
            '{email}',
201
            '{emailAddress}',
202
            $emailTemplate->htmlContent,
203
        );
204
205
        $parameters = [
206
            'templateString' => $emailTemplate->htmlContent,
207
            'locale' => $locale,
208
            'commonName' => $commonName,
209
            'emailAddress' => $email,
210
            'registrationCode' => $registrationCode,
211
            'expirationDate' => (string)$expirationDate,
212
            'raLocations' => $raLocations,
213
            'selfServiceUrl' => $this->selfServiceUrl,
214
        ];
215
216
        $message = new TemplatedEmail();
217
        $message
218
            ->from(new Address($this->sender->getEmail(), $this->sender->getName()))
219
            ->to(new Address($email, $commonName))
220
            ->subject($subject)
221
            ->htmlTemplate('@SurfnetStepupMiddlewareCommandHandling/SecondFactorMailService/email.html.twig')
222
            ->context($parameters);
223
        $this->mailer->send($message);
224
    }
225
226
    private function getExpirationDateOfRegistration(DateTime $date): DateTime
227
    {
228
        return $date->add(
229
            new DateInterval('P14D'),
230
        );
231
    }
232
}
233