1e381f98dSGreg Roach<?php 2e381f98dSGreg Roach 3e381f98dSGreg Roach/** 4e381f98dSGreg Roach * webtrees: online genealogy 589f7189bSGreg Roach * Copyright (C) 2021 webtrees development team 6e381f98dSGreg Roach * This program is free software: you can redistribute it and/or modify 7e381f98dSGreg Roach * it under the terms of the GNU General Public License as published by 8e381f98dSGreg Roach * the Free Software Foundation, either version 3 of the License, or 9e381f98dSGreg Roach * (at your option) any later version. 10e381f98dSGreg Roach * This program is distributed in the hope that it will be useful, 11e381f98dSGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 12e381f98dSGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13e381f98dSGreg Roach * GNU General Public License for more details. 14e381f98dSGreg Roach * You should have received a copy of the GNU General Public License 1589f7189bSGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>. 16e381f98dSGreg Roach */ 17e381f98dSGreg Roach 18e381f98dSGreg Roachdeclare(strict_types=1); 19e381f98dSGreg Roach 20e381f98dSGreg Roachnamespace Fisharebest\Webtrees\Http\RequestHandlers; 21e381f98dSGreg Roach 22e381f98dSGreg Roachuse Fisharebest\Webtrees\FlashMessages; 23e381f98dSGreg Roachuse Fisharebest\Webtrees\GuestUser; 24*81b729d3SGreg Roachuse Fisharebest\Webtrees\Http\Exceptions\HttpAccessDeniedException; 25*81b729d3SGreg Roachuse Fisharebest\Webtrees\Http\Exceptions\HttpNotFoundException; 26e381f98dSGreg Roachuse Fisharebest\Webtrees\Http\ViewResponseTrait; 27e381f98dSGreg Roachuse Fisharebest\Webtrees\I18N; 2870ca9c90SGreg Roachuse Fisharebest\Webtrees\Services\CaptchaService; 2904626e75SGreg Roachuse Fisharebest\Webtrees\Services\EmailService; 30e381f98dSGreg Roachuse Fisharebest\Webtrees\Services\MessageService; 31e381f98dSGreg Roachuse Fisharebest\Webtrees\Services\UserService; 32e381f98dSGreg Roachuse Fisharebest\Webtrees\Tree; 338d9c2b68SGreg Roachuse Fisharebest\Webtrees\Validator; 34e381f98dSGreg Roachuse Psr\Http\Message\ResponseInterface; 35e381f98dSGreg Roachuse Psr\Http\Message\ServerRequestInterface; 36e381f98dSGreg Roachuse Psr\Http\Server\RequestHandlerInterface; 37e381f98dSGreg Roach 38e381f98dSGreg Roachuse function assert; 39e381f98dSGreg Roachuse function e; 40e381f98dSGreg Roachuse function in_array; 41e381f98dSGreg Roachuse function preg_match; 42e381f98dSGreg Roachuse function preg_quote; 43e381f98dSGreg Roachuse function redirect; 44e381f98dSGreg Roachuse function route; 45e381f98dSGreg Roach 46e381f98dSGreg Roach/** 47e381f98dSGreg Roach * Send a message from a visitor. 48e381f98dSGreg Roach */ 49e381f98dSGreg Roachclass ContactAction implements RequestHandlerInterface 50e381f98dSGreg Roach{ 51e381f98dSGreg Roach use ViewResponseTrait; 52e381f98dSGreg Roach 53c4943cffSGreg Roach private CaptchaService $captcha_service; 5470ca9c90SGreg Roach 55c4943cffSGreg Roach private EmailService $email_service; 5604626e75SGreg Roach 57c4943cffSGreg Roach private MessageService $message_service; 58e381f98dSGreg Roach 59c4943cffSGreg Roach private UserService $user_service; 60e381f98dSGreg Roach 61e381f98dSGreg Roach /** 62e381f98dSGreg Roach * MessagePage constructor. 63e381f98dSGreg Roach * 6470ca9c90SGreg Roach * @param CaptchaService $captcha_service 6504626e75SGreg Roach * @param EmailService $email_service 66e381f98dSGreg Roach * @param MessageService $message_service 67e381f98dSGreg Roach * @param UserService $user_service 68e381f98dSGreg Roach */ 6970ca9c90SGreg Roach public function __construct( 7070ca9c90SGreg Roach CaptchaService $captcha_service, 7104626e75SGreg Roach EmailService $email_service, 7270ca9c90SGreg Roach MessageService $message_service, 7370ca9c90SGreg Roach UserService $user_service 7470ca9c90SGreg Roach ) { 7570ca9c90SGreg Roach $this->captcha_service = $captcha_service; 7604626e75SGreg Roach $this->email_service = $email_service; 77e381f98dSGreg Roach $this->user_service = $user_service; 78e381f98dSGreg Roach $this->message_service = $message_service; 79e381f98dSGreg Roach } 80e381f98dSGreg Roach 81e381f98dSGreg Roach /** 82e381f98dSGreg Roach * @param ServerRequestInterface $request 83e381f98dSGreg Roach * 84e381f98dSGreg Roach * @return ResponseInterface 85e381f98dSGreg Roach */ 86e381f98dSGreg Roach public function handle(ServerRequestInterface $request): ResponseInterface 87e381f98dSGreg Roach { 88e381f98dSGreg Roach $tree = $request->getAttribute('tree'); 89e381f98dSGreg Roach assert($tree instanceof Tree); 90e381f98dSGreg Roach 918d9c2b68SGreg Roach $base_url = $request->getAttribute('base_url'); 928d9c2b68SGreg Roach $body = Validator::parsedBody($request)->string('body') ?? ''; 938d9c2b68SGreg Roach $from_email = Validator::parsedBody($request)->string('from_email') ?? ''; 948d9c2b68SGreg Roach $from_name = Validator::parsedBody($request)->string('from_name') ?? ''; 958d9c2b68SGreg Roach $subject = Validator::parsedBody($request)->string('subject') ?? ''; 968d9c2b68SGreg Roach $to = Validator::parsedBody($request)->string('to') ?? ''; 97*81b729d3SGreg Roach $url = Validator::parsedBody($request)->isLocalUrl($base_url)->string('url') ?? $base_url; 98e381f98dSGreg Roach $ip = $request->getAttribute('client-ip'); 99e381f98dSGreg Roach $to_user = $this->user_service->findByUserName($to); 100e381f98dSGreg Roach 101e381f98dSGreg Roach if ($to_user === null) { 102d501c45dSGreg Roach throw new HttpNotFoundException(); 103e381f98dSGreg Roach } 104e381f98dSGreg Roach 105e381f98dSGreg Roach if (!in_array($to_user, $this->message_service->validContacts($tree), false)) { 106d501c45dSGreg Roach throw new HttpAccessDeniedException('Invalid contact user id'); 107e381f98dSGreg Roach } 108e381f98dSGreg Roach 109e381f98dSGreg Roach $errors = $body === '' || $subject === '' || $from_email === '' || $from_name === ''; 110e381f98dSGreg Roach 11170ca9c90SGreg Roach if ($this->captcha_service->isRobot($request)) { 11270ca9c90SGreg Roach FlashMessages::addMessage(I18N::translate('Please try again.'), 'danger'); 11370ca9c90SGreg Roach $errors = true; 11470ca9c90SGreg Roach } 11570ca9c90SGreg Roach 11604626e75SGreg Roach if (!$this->email_service->isValidEmail($from_email)) { 117e381f98dSGreg Roach FlashMessages::addMessage(I18N::translate('Please enter a valid email address.'), 'danger'); 118e381f98dSGreg Roach $errors = true; 119e381f98dSGreg Roach } 120e381f98dSGreg Roach 121e381f98dSGreg Roach if (preg_match('/(?!' . preg_quote($base_url, '/') . ')(((?:ftp|http|https):\/\/)[a-zA-Z0-9.-]+)/', $subject . $body, $match)) { 122ad3143ccSGreg Roach 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.’ */ 123e381f98dSGreg Roach I18N::translate('You should delete the “%1$s” from “%2$s” and try again.', $match[2], $match[1]), 'danger'); 124e381f98dSGreg Roach $errors = true; 125e381f98dSGreg Roach } 126e381f98dSGreg Roach 127e381f98dSGreg Roach if ($errors) { 128e381f98dSGreg Roach return redirect(route(ContactPage::class, [ 129e381f98dSGreg Roach 'body' => $body, 130e381f98dSGreg Roach 'from_email' => $from_email, 131e381f98dSGreg Roach 'from_name' => $from_name, 132e381f98dSGreg Roach 'subject' => $subject, 133e381f98dSGreg Roach 'to' => $to, 134e381f98dSGreg Roach 'tree' => $tree->name(), 135e381f98dSGreg Roach 'url' => $url, 136e381f98dSGreg Roach ])); 137e381f98dSGreg Roach } 138e381f98dSGreg Roach 139e381f98dSGreg Roach $sender = new GuestUser($from_email, $from_name); 140e381f98dSGreg Roach 141e381f98dSGreg Roach if ($this->message_service->deliverMessage($sender, $to_user, $subject, $body, $url, $ip)) { 142e381f98dSGreg Roach FlashMessages::addMessage(I18N::translate('The message was successfully sent to %s.', e($to_user->realName())), 'success'); 143e381f98dSGreg Roach 144e381f98dSGreg Roach return redirect($url); 145e381f98dSGreg Roach } 146e381f98dSGreg Roach 147e381f98dSGreg Roach FlashMessages::addMessage(I18N::translate('The message was not sent.'), 'danger'); 148e381f98dSGreg Roach 149e381f98dSGreg Roach $redirect_url = route(ContactPage::class, [ 150e381f98dSGreg Roach 'body' => $body, 151e381f98dSGreg Roach 'from_email' => $from_email, 152e381f98dSGreg Roach 'from_name' => $from_name, 153e381f98dSGreg Roach 'subject' => $subject, 154e381f98dSGreg Roach 'to' => $to, 155e381f98dSGreg Roach 'tree' => $tree->name(), 156e381f98dSGreg Roach 'url' => $url, 157e381f98dSGreg Roach ]); 158e381f98dSGreg Roach 159e381f98dSGreg Roach return redirect($redirect_url); 160e381f98dSGreg Roach } 161e381f98dSGreg Roach} 162