Passed
Push — main ( fcbce9...7a8937 )
by Greg
18:31 queued 12:38
created

ContactAction::handle()   B

Complexity

Conditions 11
Paths 98

Size

Total Lines 74
Code Lines 49

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 49
nc 98
nop 1
dl 0
loc 74
rs 7.3166
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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
/**
4
 * webtrees: online genealogy
5
 * Copyright (C) 2021 webtrees development team
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
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 General Public License for more details.
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16
 */
17
18
declare(strict_types=1);
19
20
namespace Fisharebest\Webtrees\Http\RequestHandlers;
21
22
use Fisharebest\Webtrees\Exceptions\HttpAccessDeniedException;
23
use Fisharebest\Webtrees\Exceptions\HttpNotFoundException;
24
use Fisharebest\Webtrees\FlashMessages;
25
use Fisharebest\Webtrees\GuestUser;
26
use Fisharebest\Webtrees\Http\ViewResponseTrait;
27
use Fisharebest\Webtrees\I18N;
28
use Fisharebest\Webtrees\Services\CaptchaService;
29
use Fisharebest\Webtrees\Services\EmailService;
30
use Fisharebest\Webtrees\Services\MessageService;
31
use Fisharebest\Webtrees\Services\UserService;
32
use Fisharebest\Webtrees\Tree;
33
use Fisharebest\Webtrees\Validator;
34
use Psr\Http\Message\ResponseInterface;
35
use Psr\Http\Message\ServerRequestInterface;
36
use Psr\Http\Server\RequestHandlerInterface;
37
38
use function assert;
39
use function e;
40
use function in_array;
41
use function preg_match;
42
use function preg_quote;
43
use function redirect;
44
use function route;
45
46
/**
47
 * Send a message from a visitor.
48
 */
49
class ContactAction implements RequestHandlerInterface
50
{
51
    use ViewResponseTrait;
52
53
    private CaptchaService $captcha_service;
54
55
    private EmailService $email_service;
56
57
    private MessageService $message_service;
58
59
    private UserService $user_service;
60
61
    /**
62
     * MessagePage constructor.
63
     *
64
     * @param CaptchaService $captcha_service
65
     * @param EmailService   $email_service
66
     * @param MessageService $message_service
67
     * @param UserService    $user_service
68
     */
69
    public function __construct(
70
        CaptchaService $captcha_service,
71
        EmailService $email_service,
72
        MessageService $message_service,
73
        UserService $user_service
74
    ) {
75
        $this->captcha_service = $captcha_service;
76
        $this->email_service   = $email_service;
77
        $this->user_service    = $user_service;
78
        $this->message_service = $message_service;
79
    }
80
81
    /**
82
     * @param ServerRequestInterface $request
83
     *
84
     * @return ResponseInterface
85
     */
86
    public function handle(ServerRequestInterface $request): ResponseInterface
87
    {
88
        $tree = $request->getAttribute('tree');
89
        assert($tree instanceof Tree);
90
91
        $base_url   = $request->getAttribute('base_url');
92
        $body       = Validator::parsedBody($request)->string('body') ?? '';
93
        $from_email = Validator::parsedBody($request)->string('from_email') ?? '';
94
        $from_name  = Validator::parsedBody($request)->string('from_name') ?? '';
95
        $subject    = Validator::parsedBody($request)->string('subject') ?? '';
96
        $to         = Validator::parsedBody($request)->string('to') ?? '';
97
        $url        = Validator::parsedBody($request)->localUrl($base_url)->string('url') ?? $base_url;
98
        $ip         = $request->getAttribute('client-ip');
99
        $to_user    = $this->user_service->findByUserName($to);
100
101
        if ($to_user === null) {
102
            throw new HttpNotFoundException();
103
        }
104
105
        if (!in_array($to_user, $this->message_service->validContacts($tree), false)) {
106
            throw new HttpAccessDeniedException('Invalid contact user id');
107
        }
108
109
        $errors = $body === '' || $subject === '' || $from_email === '' || $from_name === '';
110
111
        if ($this->captcha_service->isRobot($request)) {
112
            FlashMessages::addMessage(I18N::translate('Please try again.'), 'danger');
113
            $errors = true;
114
        }
115
116
        if (!$this->email_service->isValidEmail($from_email)) {
117
            FlashMessages::addMessage(I18N::translate('Please enter a valid email address.'), 'danger');
118
            $errors = true;
119
        }
120
121
        if (preg_match('/(?!' . preg_quote($base_url, '/') . ')(((?:ftp|http|https):\/\/)[a-zA-Z0-9.-]+)/', $subject . $body, $match)) {
122
            FlashMessages::addMessage(I18N::translate('You are not allowed to send messages that contain external links.') . ' ' . /* I18N: e.g. ‘You should delete the “https://” from “https://www.example.com” and try again.’ */
123
                I18N::translate('You should delete the “%1$s” from “%2$s” and try again.', $match[2], $match[1]), 'danger');
124
            $errors = true;
125
        }
126
127
        if ($errors) {
128
            return redirect(route(ContactPage::class, [
129
                'body'       => $body,
130
                'from_email' => $from_email,
131
                'from_name'  => $from_name,
132
                'subject'    => $subject,
133
                'to'         => $to,
134
                'tree'       => $tree->name(),
135
                'url'        => $url,
136
            ]));
137
        }
138
139
        $sender = new GuestUser($from_email, $from_name);
140
141
        if ($this->message_service->deliverMessage($sender, $to_user, $subject, $body, $url, $ip)) {
142
            FlashMessages::addMessage(I18N::translate('The message was successfully sent to %s.', e($to_user->realName())), 'success');
143
144
            return redirect($url);
145
        }
146
147
        FlashMessages::addMessage(I18N::translate('The message was not sent.'), 'danger');
148
149
        $redirect_url = route(ContactPage::class, [
150
            'body'       => $body,
151
            'from_email' => $from_email,
152
            'from_name'  => $from_name,
153
            'subject'    => $subject,
154
            'to'         => $to,
155
            'tree'       => $tree->name(),
156
            'url'        => $url,
157
        ]);
158
159
        return redirect($redirect_url);
160
    }
161
}
162