ConfirmationEmailSender::sendConfirmation1()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 3
eloc 9
nc 2
nop 1
dl 0
loc 14
rs 9.9666
c 3
b 0
f 0
1
<?php
2
/*
3
 * Copyright (C) 2020  Jan Böhmer
4
 *
5
 * This program is free software: you can redistribute it and/or modify
6
 * it under the terms of the GNU Affero General Public License as published
7
 * by the Free Software Foundation, either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU Affero General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Affero General Public License
16
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17
 */
18
19
namespace App\Services\EmailConfirmation;
20
21
use App\Entity\PaymentOrder;
22
use DateTime;
23
use Doctrine\ORM\EntityManagerInterface;
24
use InvalidArgumentException;
25
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
26
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
27
use Symfony\Component\Mailer\MailerInterface;
28
use Symfony\Component\Mime\Email;
29
use Symfony\Contracts\Translation\TranslatorInterface;
30
31
/**
32
 * This service is responsible for sending the confirmation emails for a payment_order.
33
 */
34
class ConfirmationEmailSender
35
{
36
    private $mailer;
37
    private $tokenGenerator;
38
    private $entityManager;
39
    private $translator;
40
41
    private $fsb_email;
42
    private $hhv_email;
43
    private $send_notifications;
44
    private $notifications_bcc;
45
46
    public function __construct(MailerInterface $mailer, ConfirmationTokenGenerator $tokenGenerator,
47
        EntityManagerInterface $entityManager, TranslatorInterface $translator,
48
        string $fsb_email, string $hhv_email, bool $send_notifications, array $notifications_bcc)
49
    {
50
        $this->mailer = $mailer;
51
        $this->tokenGenerator = $tokenGenerator;
52
        $this->entityManager = $entityManager;
53
        $this->translator = $translator;
54
55
        $this->fsb_email = $fsb_email;
56
        $this->hhv_email = $hhv_email;
57
        $this->send_notifications = $send_notifications;
58
        $this->notifications_bcc = $notifications_bcc;
59
    }
60
61
    /**
62
     * Send the confirmation email to the first verification person for the given payment_order.
63
     * Email addresses are taken from department (and are added as BCC)
64
     * A token is generated, send via email and saved in hashed form in the payment order.
65
     * Calling this function will flush database.
66
     * If no applicable emails are found (or email notifications are disabled) the payment order will be confirmed and
67
     * no email is sent.
68
     */
69
    public function sendConfirmation1(PaymentOrder $paymentOrder): void
70
    {
71
        $token = $this->tokenGenerator->getToken();
72
        $paymentOrder->setConfirm1Token($this->hash_token($token));
73
        $email = $paymentOrder->getDepartment()
74
            ->getEmailHhv();
75
        //Dont send the confirmation email if no email is set, otherwise just confirm it
76
        if (!empty($email) && $this->send_notifications) {
77
            $this->sendConfirmation($paymentOrder, $email, $token, 1);
78
        } else {
79
            $paymentOrder->setConfirm1Timestamp(new DateTime());
80
        }
81
82
        $this->entityManager->flush();
83
    }
84
85
    /**
86
     * Send the confirmation email to the second verification person for the given payment_order.
87
     * Email addresses are taken from department (and are added as BCC)
88
     * A token is generated, send via email and saved in hashed form in the payment order.
89
     * Calling this function will flush database.
90
     * If no applicable emails are found (or email notifications are disabled) the payment order will be confirmed and
91
     * no email is sent.
92
     */
93
    public function sendConfirmation2(PaymentOrder $paymentOrder): void
94
    {
95
        $token = $this->tokenGenerator->getToken();
96
        $paymentOrder->setConfirm2Token($this->hash_token($token));
97
        $email = $paymentOrder->getDepartment()
98
            ->getEmailTreasurer();
99
        //Dont send the confirmation email if no email is set, otherwise just confirm it
100
        if (!empty($email) && $this->send_notifications) {
101
            $this->sendConfirmation($paymentOrder, $email, $token, 2);
102
        } else {
103
            $paymentOrder->setConfirm2Timestamp(new DateTime());
104
        }
105
        $this->entityManager->flush();
106
    }
107
108
    /**
109
     * Sents a confirmation email for the given payment order for a plaintext token.
110
     *
111
     * @param PaymentOrder $paymentOrder        The paymentOrder for which the email should be generated
112
     * @param string[]     $email_addresses     The mail addresses that should be added as BCC
113
     * @param string       $token               The plaintext token to access confirmation page.
114
     * @param int          $verification_number The verification step (1 or 2)
115
     *
116
     * @throws TransportExceptionInterface
117
     */
118
    private function sendConfirmation(PaymentOrder $paymentOrder, array $email_addresses, string $token, int $verification_number): void
119
    {
120
        //We can not continue if the payment order is not serialized / has an ID (as we cannot generate an URL for it)
121
        if (null === $paymentOrder->getId()) {
0 ignored issues
show
introduced by
The condition null === $paymentOrder->getId() is always false.
Loading history...
122
            throw new InvalidArgumentException('$paymentOrder must be serialized / have an ID so than an confirmation URL can be generated!');
123
        }
124
125
        $email = new TemplatedEmail();
126
127
        $email->priority(Email::PRIORITY_HIGH);
128
        $email->replyTo($paymentOrder->getDepartment()->isFSR() ? $this->fsb_email : $this->hhv_email);
129
130
        $email->subject(
131
            $this->translator->trans(
132
                'payment_order.confirmation_email.subject',
133
                [
134
                    '%project%' => $paymentOrder->getProjectName(),
135
                ]
136
            ));
137
138
        $email->htmlTemplate('mails/confirmation.html.twig');
139
        $email->context([
140
            'payment_order' => $paymentOrder,
141
            'token' => $token,
142
            'verification_number' => $verification_number,
143
        ]);
144
145
        $email->addBcc(...$email_addresses);
146
        $this->mailer->send($email);
147
    }
148
149
    /**
150
     * Resend all confirmation emails for cases where a confirmation is missing.
151
     * If some part is already confirmed this confirmation is not sent again.
152
     * If a confirmation is missing a new token will be generated and sent via email.
153
     */
154
    public function resendConfirmations(PaymentOrder $paymentOrder): void
155
    {
156
        //Resend emails that not already were confirmed
157
        if (null === $paymentOrder->getConfirm1Timestamp()) {
158
            $this->sendConfirmation1($paymentOrder);
159
        }
160
161
        if (null === $paymentOrder->getConfirm2Timestamp()) {
162
            $this->sendConfirmation2($paymentOrder);
163
        }
164
    }
165
166
    private function hash_token(string $token): string
167
    {
168
        return password_hash($token, PASSWORD_DEFAULT);
0 ignored issues
show
Bug Best Practice introduced by
The expression return password_hash($to...ation\PASSWORD_DEFAULT) could return the type null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
169
    }
170
}
171