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