xref: /webtrees/app/Services/MessageService.php (revision a46dd5a607d241e1aa0a9a0cf913792d4ac2ea06)
1e381f98dSGreg Roach<?php
2e381f98dSGreg Roach
3e381f98dSGreg Roach/**
4e381f98dSGreg Roach * webtrees: online genealogy
51fe542e9SGreg 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\Services;
21e381f98dSGreg Roach
22e381f98dSGreg Roachuse Fisharebest\Webtrees\Auth;
23e381f98dSGreg Roachuse Fisharebest\Webtrees\Contracts\UserInterface;
24e381f98dSGreg Roachuse Fisharebest\Webtrees\I18N;
25d97083feSGreg Roachuse Fisharebest\Webtrees\Registry;
26e381f98dSGreg Roachuse Fisharebest\Webtrees\SiteUser;
27e381f98dSGreg Roachuse Fisharebest\Webtrees\Tree;
287c4add84SGreg Roachuse Fisharebest\Webtrees\User;
29e381f98dSGreg Roachuse Illuminate\Database\Capsule\Manager as DB;
30e381f98dSGreg Roachuse Illuminate\Support\Collection;
31e381f98dSGreg Roach
32e381f98dSGreg Roachuse function array_filter;
33e381f98dSGreg Roachuse function in_array;
34e381f98dSGreg Roachuse function view;
35e381f98dSGreg Roach
36e381f98dSGreg Roach/**
37e381f98dSGreg Roach * Send messages between users and from visitors to the site.
38e381f98dSGreg Roach */
39e381f98dSGreg Roachclass MessageService
40e381f98dSGreg Roach{
41*a46dd5a6SGreg Roach    private const BROADCAST_ALL   = 'all';
42*a46dd5a6SGreg Roach    private const BROADCAST_NEVER = 'never';
43*a46dd5a6SGreg Roach    private const BROADCAST_GONE  = 'gone';
44*a46dd5a6SGreg Roach
45c4943cffSGreg Roach    private EmailService $email_service;
46e381f98dSGreg Roach
47c4943cffSGreg Roach    private UserService $user_service;
48e381f98dSGreg Roach
49e381f98dSGreg Roach    /**
50e381f98dSGreg Roach     * MessageService constructor.
51e381f98dSGreg Roach     *
52e381f98dSGreg Roach     * @param EmailService $email_service
53e381f98dSGreg Roach     * @param UserService  $user_service
54e381f98dSGreg Roach     */
55e381f98dSGreg Roach    public function __construct(EmailService $email_service, UserService $user_service)
56e381f98dSGreg Roach    {
57e381f98dSGreg Roach        $this->email_service = $email_service;
58e381f98dSGreg Roach        $this->user_service  = $user_service;
59e381f98dSGreg Roach    }
60e381f98dSGreg Roach
61e381f98dSGreg Roach    /**
62e381f98dSGreg Roach     * Contact messages can only be sent to the designated contacts
63e381f98dSGreg Roach     *
64e381f98dSGreg Roach     * @param Tree $tree
65e381f98dSGreg Roach     *
6609482a55SGreg Roach     * @return array<UserInterface>
67e381f98dSGreg Roach     */
68e381f98dSGreg Roach    public function validContacts(Tree $tree): array
69e381f98dSGreg Roach    {
70e381f98dSGreg Roach        $contacts = [
71e381f98dSGreg Roach            $this->user_service->find((int) $tree->getPreference('CONTACT_USER_ID')),
72e381f98dSGreg Roach            $this->user_service->find((int) $tree->getPreference('WEBMASTER_USER_ID')),
73e381f98dSGreg Roach        ];
74e381f98dSGreg Roach
75e381f98dSGreg Roach        return array_filter($contacts);
76e381f98dSGreg Roach    }
77e381f98dSGreg Roach
78e381f98dSGreg Roach    /**
79e381f98dSGreg Roach     * Add a message to a user's inbox, send it to them via email, or both.
80e381f98dSGreg Roach     *
81e381f98dSGreg Roach     * @param UserInterface $sender
82e381f98dSGreg Roach     * @param UserInterface $recipient
83e381f98dSGreg Roach     * @param string        $subject
84e381f98dSGreg Roach     * @param string        $body
85e381f98dSGreg Roach     * @param string        $url
86e381f98dSGreg Roach     * @param string        $ip
87e381f98dSGreg Roach     *
88e381f98dSGreg Roach     * @return bool
89e381f98dSGreg Roach     */
90e381f98dSGreg Roach    public function deliverMessage(UserInterface $sender, UserInterface $recipient, string $subject, string $body, string $url, string $ip): bool
91e381f98dSGreg Roach    {
92e381f98dSGreg Roach        $success = true;
93e381f98dSGreg Roach
94e381f98dSGreg Roach        // Temporarily switch to the recipient's language
95e381f98dSGreg Roach        $old_language = I18N::languageTag();
961fe542e9SGreg Roach        I18N::init($recipient->getPreference(UserInterface::PREF_LANGUAGE));
97e381f98dSGreg Roach
98e381f98dSGreg Roach        $body_text = view('emails/message-user-text', [
99e381f98dSGreg Roach            'sender'    => $sender,
100e381f98dSGreg Roach            'recipient' => $recipient,
101e381f98dSGreg Roach            'message'   => $body,
102e381f98dSGreg Roach            'url'       => $url,
103e381f98dSGreg Roach        ]);
104e381f98dSGreg Roach
105e381f98dSGreg Roach        $body_html = view('emails/message-user-html', [
106e381f98dSGreg Roach            'sender'    => $sender,
107e381f98dSGreg Roach            'recipient' => $recipient,
108e381f98dSGreg Roach            'message'   => $body,
109e381f98dSGreg Roach            'url'       => $url,
110e381f98dSGreg Roach        ]);
111e381f98dSGreg Roach
112e381f98dSGreg Roach        // Send via the internal messaging system.
113e381f98dSGreg Roach        if ($this->sendInternalMessage($recipient)) {
114e381f98dSGreg Roach            DB::table('message')->insert([
115e381f98dSGreg Roach                'sender'     => Auth::check() ? Auth::user()->email() : $sender->email(),
116e381f98dSGreg Roach                'ip_address' => $ip,
117e381f98dSGreg Roach                'user_id'    => $recipient->id(),
118e381f98dSGreg Roach                'subject'    => $subject,
119e381f98dSGreg Roach                'body'       => $body_text,
120e381f98dSGreg Roach            ]);
121e381f98dSGreg Roach        }
122e381f98dSGreg Roach
123e381f98dSGreg Roach        // Send via email
124e381f98dSGreg Roach        if ($this->sendEmail($recipient)) {
125e381f98dSGreg Roach            $success = $this->email_service->send(
126e381f98dSGreg Roach                new SiteUser(),
127e381f98dSGreg Roach                $recipient,
128e381f98dSGreg Roach                $sender,
129e381f98dSGreg Roach                I18N::translate('webtrees message') . ' - ' . $subject,
130e381f98dSGreg Roach                $body_text,
131e381f98dSGreg Roach                $body_html
132e381f98dSGreg Roach            );
133e381f98dSGreg Roach        }
134e381f98dSGreg Roach
135e381f98dSGreg Roach        I18N::init($old_language);
136e381f98dSGreg Roach
137e381f98dSGreg Roach        return $success;
138e381f98dSGreg Roach    }
139e381f98dSGreg Roach
140e381f98dSGreg Roach    /**
141e381f98dSGreg Roach     * Should we send messages to this user via internal messaging?
142e381f98dSGreg Roach     *
143e381f98dSGreg Roach     * @param UserInterface $user
144e381f98dSGreg Roach     *
145e381f98dSGreg Roach     * @return bool
146e381f98dSGreg Roach     */
147e381f98dSGreg Roach    public function sendInternalMessage(UserInterface $user): bool
148e381f98dSGreg Roach    {
1491fe542e9SGreg Roach        return in_array($user->getPreference(UserInterface::PREF_CONTACT_METHOD), [
150e381f98dSGreg Roach            'messaging',
151e381f98dSGreg Roach            'messaging2',
152e381f98dSGreg Roach            'mailto',
153e381f98dSGreg Roach            'none',
154e381f98dSGreg Roach        ], true);
155e381f98dSGreg Roach    }
156e381f98dSGreg Roach
157e381f98dSGreg Roach    /**
158e381f98dSGreg Roach     * Should we send messages to this user via email?
159e381f98dSGreg Roach     *
160e381f98dSGreg Roach     * @param UserInterface $user
161e381f98dSGreg Roach     *
162e381f98dSGreg Roach     * @return bool
163e381f98dSGreg Roach     */
164e381f98dSGreg Roach    public function sendEmail(UserInterface $user): bool
165e381f98dSGreg Roach    {
1661fe542e9SGreg Roach        return in_array($user->getPreference(UserInterface::PREF_CONTACT_METHOD), [
167e381f98dSGreg Roach            'messaging2',
168e381f98dSGreg Roach            'messaging3',
169e381f98dSGreg Roach            'mailto',
170e381f98dSGreg Roach            'none',
171e381f98dSGreg Roach        ], true);
172e381f98dSGreg Roach    }
173e381f98dSGreg Roach
174e381f98dSGreg Roach    /**
175e381f98dSGreg Roach     * Convert a username (or mailing list name) into an array of recipients.
176e381f98dSGreg Roach     *
177e381f98dSGreg Roach     * @param string $to
178e381f98dSGreg Roach     *
17936779af1SGreg Roach     * @return Collection<int,User>
180e381f98dSGreg Roach     */
181e381f98dSGreg Roach    public function recipientUsers(string $to): Collection
182e381f98dSGreg Roach    {
183e381f98dSGreg Roach        switch ($to) {
184e381f98dSGreg Roach            default:
185*a46dd5a6SGreg Roach            case self::BROADCAST_ALL:
186e381f98dSGreg Roach                return $this->user_service->all();
187*a46dd5a6SGreg Roach            case self::BROADCAST_NEVER:
188e381f98dSGreg Roach                return $this->user_service->all()->filter(static function (UserInterface $user): bool {
1891fe542e9SGreg Roach                    return $user->getPreference(UserInterface::PREF_IS_ACCOUNT_APPROVED) === '1' && $user->getPreference(UserInterface::PREF_TIMESTAMP_REGISTERED) > $user->getPreference(UserInterface::PREF_TIMESTAMP_ACTIVE);
190e381f98dSGreg Roach                });
191*a46dd5a6SGreg Roach            case self::BROADCAST_GONE:
192d97083feSGreg Roach                $six_months_ago = Registry::timestampFactory()->now()->subtractMonths(6)->timestamp();
193e381f98dSGreg Roach
194e381f98dSGreg Roach                return $this->user_service->all()->filter(static function (UserInterface $user) use ($six_months_ago): bool {
1951fe542e9SGreg Roach                    $session_time = (int) $user->getPreference(UserInterface::PREF_TIMESTAMP_ACTIVE);
196e381f98dSGreg Roach
197e381f98dSGreg Roach                    return $session_time > 0 && $session_time < $six_months_ago;
198e381f98dSGreg Roach                });
199e381f98dSGreg Roach        }
200e381f98dSGreg Roach    }
201e381f98dSGreg Roach
202e381f98dSGreg Roach    /**
203*a46dd5a6SGreg Roach     * Recipients for broadcast messages
204e381f98dSGreg Roach     *
205*a46dd5a6SGreg Roach     * @return array<string,string>
206e381f98dSGreg Roach     */
207*a46dd5a6SGreg Roach    public function recipientTypes(): array
208e381f98dSGreg Roach    {
209*a46dd5a6SGreg Roach        return [
210*a46dd5a6SGreg Roach            self::BROADCAST_ALL   => I18N::translate('Send a message to all users'),
211*a46dd5a6SGreg Roach            self::BROADCAST_NEVER => I18N::translate('Send a message to users who have never signed in'),
212*a46dd5a6SGreg Roach            self::BROADCAST_GONE  => I18N::translate('Send a message to users who have not signed in for 6 months'),
213*a46dd5a6SGreg Roach        ];
214e381f98dSGreg Roach    }
215f91b18ebSGreg Roach
216f91b18ebSGreg Roach    /**
217f91b18ebSGreg Roach     * A list of contact methods (e.g. for an edit control).
218f91b18ebSGreg Roach     *
21924f2a3afSGreg Roach     * @return array<string>
220f91b18ebSGreg Roach     */
221f91b18ebSGreg Roach    public function contactMethods(): array
222f91b18ebSGreg Roach    {
223f91b18ebSGreg Roach        return [
224f91b18ebSGreg Roach            'messaging'  => I18N::translate('Internal messaging'),
225f91b18ebSGreg Roach            'messaging2' => I18N::translate('Internal messaging with emails'),
226f91b18ebSGreg Roach            'messaging3' => I18N::translate('webtrees sends emails with no storage'),
227f91b18ebSGreg Roach            'mailto'     => I18N::translate('Mailto link'),
228f91b18ebSGreg Roach            'none'       => I18N::translate('No contact'),
229f91b18ebSGreg Roach        ];
230f91b18ebSGreg Roach    }
231e381f98dSGreg Roach}
232