Passed
Push — develop ( 499cd2...bb078f )
by Greg
11:09 queued 01:48
created

MessageService::sendEmail()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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