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