PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 2.11.0
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v2.11.0
2.11.0 2.10.0 2.10.01 2.9.1 2.9.0 2.8.1 2.8.0 2.7.7 2.7.5 2.7.0 2.6.01 2.6.0 2.5.0 2.4.01 trunk 1.0.90 1.0.91 1.0.92 1.0.93 1.0.94 1.0.95 1.0.96 1.0.97 1.0.98 1.0.99 All 78 releases
← All changes | app/Hooks/Handlers/EmailNotificationHandler.php +236 -162 1.0.932.11.0 View file →
@@ -1,16 +1,13 @@
1 1 <?php
2 2
3 3 namespace FluentCommunity\App\Hooks\Handlers;
4 4
5 -use FluentCommunity\App\App;
6 5 use FluentCommunity\App\Functions\Utility;
7 6 use FluentCommunity\App\Models\Comment;
8 7 use FluentCommunity\App\Models\Feed;
9 8 use FluentCommunity\App\Models\Notification;
10 -use FluentCommunity\App\Models\NotificationSubscriber;
11 9 use FluentCommunity\App\Models\BaseSpace;
12 -use FluentCommunity\App\Models\NotificationSubscription;
13 10 use FluentCommunity\App\Models\SpaceUserPivot;
14 11 use FluentCommunity\App\Models\User;
15 12 use FluentCommunity\App\Models\XProfile;
16 13 use FluentCommunity\App\Services\Helper;
@@ -15,8 +12,9 @@
15 12 use FluentCommunity\App\Models\XProfile;
16 13 use FluentCommunity\App\Services\Helper;
17 14 use FluentCommunity\App\Services\Libs\DailyDigest;
18 15 use FluentCommunity\App\Services\Libs\Mailer;
16 +use FluentCommunity\App\Services\FeedsHelper;
19 17 use FluentCommunity\App\Services\NotificationPref;
20 18 use FluentCommunity\App\Services\ProfileHelper;
21 19 use FluentCommunity\Framework\Support\Arr;
22 20
@@ -21,11 +19,13 @@
21 19 use FluentCommunity\Framework\Support\Arr;
22 20
23 21 class EmailNotificationHandler
24 22 {
23 + private $maxRunTime = 0;
24 +
25 25 public function register()
26 26 {
27 - add_action('fluent_community/space_feed/created', [$this, 'handleSpaceFeedCreated'], 10, 1);
27 + add_action('fluent_community/space_feed/created', [$this, 'handleSpaceFeedCreated'], 20, 1);
28 28 add_action('fluent_community/email_notify_new_posts', [$this, 'notifyOnPostCreatedAsync'], 10, 1);
29 29
30 30 add_action('fluent_community/comment_added', [$this, 'handleNewCommentEvent'], 30, 2);
31 31 add_action('fluent_community/comment_added_async', [$this, 'handleNewCommentNotificationAsync'], 10, 2);
@@ -36,10 +36,21 @@
36 36 add_action('fluent_community/email_notify_users_everyone_tag', [$this, 'emailNotifyUsersForEveryoneTag'], 10, 2);
37 37
38 38 add_action('fluent_community_send_daily_digest', [$this, 'maybeSendDailyDigest'], 10);
39 39 add_action('fluent_community/space/join_requested', [$this, 'handleCommunityJoinRequest'], 10, 2);
40 +
41 + add_action('fluent_community/send_new_user_notification', [$this, 'sendNewUserNotificationAsync'], 10, 1);
40 42 }
41 43
44 + public function sendNewUserNotificationAsync($userId)
45 + {
46 + $userId = (int) $userId;
47 + if (!$userId || !get_userdata($userId)) {
48 + return;
49 + }
50 + wp_new_user_notification($userId, null, 'user');
51 + }
52 +
42 53 public function handleSpaceFeedCreated($feed)
43 54 {
44 55 if (did_action('fluent_community/feed/scheduling_everyone_tag')) {
45 56 return;
@@ -49,23 +60,28 @@
49 60 if (!$space) {
50 61 return false;
51 62 }
52 63
53 - $types = ['np_by_member_mail'];
64 + $events = ['np_by_member'];
54 65 $spaceRole = $feed->user->getSpaceRole($feed->space);
55 - if (!in_array($spaceRole, ['admin', 'moderator'])) {
56 - $types[] = 'np_by_admin_mail';
66 + if (in_array($spaceRole, ['admin', 'moderator'])) {
67 + $events[] = 'np_by_admin';
57 68 }
58 69
59 - $hasSubscribers = User::whereHas('notificationSubscriptions', function ($query) use ($types, $space) {
60 - $query->where(function ($q) use ($types, $space) {
61 - $q->whereIn('notification_type', $types)
70 + $hasSubscribers = User::query()->where(function ($query) use ($events, $space, $feed) {
71 + $query->whereHas('notificationPreferences', function ($query) use ($events, $space) {
72 + $query->where('channel', 'mail')
73 + ->whereIn('event_key', $events)
62 74 ->where('object_id', $space->id)
63 - ->where('is_read', 1);
75 + ->where('value', 1);
64 76 });
77 +
78 + do_action_ref_array('fluent_community/space_feed/email_notify_sub_query', [&$query, $feed, $space, $events]);
79 +
80 + return $query;
65 81 })->exists();
66 82
67 - if ($hasSubscribers) {
83 + if ($hasSubscribers || Arr::get($feed->meta, 'mentioned_user_ids', [])) {
68 84 // We are scheduling this after 2 minutes of the post publish for performance
69 85 as_schedule_single_action(time() + 120, 'fluent_community/email_notify_new_posts', [
70 86 $feed->id
71 87 ], 'fluent-community');
@@ -73,8 +89,12 @@
73 89 }
74 90
75 91 public function notifyOnPostCreatedAsync($feedId)
76 92 {
93 + if (!$this->maxRunTime) {
94 + $this->maxRunTime = Utility::getMaxRunTime();
95 + }
96 +
77 97 if (is_numeric($feedId)) {
78 98 $feed = Feed::find($feedId);
79 99 } else {
80 100 $feed = $feedId;
@@ -88,20 +108,32 @@
88 108 if (!$space || !$feed->user) {
89 109 return;
90 110 }
91 111
92 - $types = ['np_by_member_mail'];
112 + $events = ['np_by_member'];
93 113 $spaceRole = $feed->user->getSpaceRole($feed->space);
94 114 if (in_array($spaceRole, ['admin', 'moderator'])) {
95 - $types[] = 'np_by_admin_mail';
115 + $events[] = 'np_by_admin';
96 116 }
97 117
98 118 $lastSendUserId = (int)$feed->getCustomMeta('_last_email_user_id', 0);
119 + $usersQuery = User::query()->where(function ($query) use ($events, $space, $feed) {
120 + $query->whereHas('notificationPreferences', function ($query) use ($events, $space) {
121 + $query->where('channel', 'mail')
122 + ->whereIn('event_key', $events)
123 + ->where('object_id', $space->id)
124 + ->where('value', 1);
125 + });
99 126
100 - $users = User::whereHas('notificationSubscriptions', function ($query) use ($types, $space) {
101 - $query->whereIn('notification_type', $types)
102 - ->where('object_id', $space->id)
103 - ->where('is_read', 1);
127 + $mentionedUserIds = Arr::get($feed->meta, 'mentioned_user_ids', []);
128 +
129 + if ($mentionedUserIds) {
130 + $query->orWhereIn('ID', $mentionedUserIds);
131 + }
132 +
133 + do_action_ref_array('fluent_community/space_feed/email_notify_sub_query', [&$query, $feed, $space, $events]);
134 +
135 + return $query;
104 136 })
105 137 ->whereHas('space_pivot', function ($query) use ($space) {
106 138 $query->where('space_id', $space->id)
107 139 ->where('status', 'active');
@@ -112,23 +144,26 @@
112 144 ->whereHas('xprofile', function ($query) {
113 145 return $query->where('status', 'active');
114 146 })
115 147 ->orderBy('ID', 'ASC')
116 - ->limit(60)
117 - ->get();
148 + ->limit(60);
118 149
150 + $users = $usersQuery->get();
151 +
119 152 if ($users->isEmpty()) {
120 153 return; // It's done
121 154 }
122 155
156 + $undeliverableEmails = Helper::getUndeliverableEmails($users->pluck('user_email')->toArray());
157 +
123 158 $emailSubject = \sprintf(
124 159 /* translators: %1$s is the author name and %2$s is the post excerpt (max 30 chars) */
125 160 __('New Post By %1$s: %2$s', 'fluent-community'),
126 - $feed->user->getDisplayName(),
161 + $feed->user->getPublicDisplayName(),
127 162 $feed->getHumanExcerpt(30)
128 163 );
129 164
130 - $emailBody = $this->getFeedHtml($feed, true);
165 + $emailBody = $feed->getFeedHtml(true);
131 166
132 167 /*
133 168 * must need to replace these two strings
134 169 * ##feed_permalink##
@@ -144,8 +179,12 @@
144 179 if ($user->ID == $feed->user_id) {
145 180 continue;
146 181 }
147 182
183 + if ($undeliverableEmails && in_array(strtolower($user->user_email), $undeliverableEmails)) {
184 + continue;
185 + }
186 +
148 187 $newEmailBody = str_replace([
149 188 '##feed_permalink##',
150 189 '##email_notification_url##'
151 190 ], [
@@ -152,13 +191,31 @@
152 191 ProfileHelper::signUserUrlWithAuthHash($feedLink, $user->ID),
153 192 ProfileHelper::getSignedNotificationPrefUrl($user->ID)
154 193 ], $emailBody);
155 194
195 + $notificationBagde = $this->getNotificationBadges($user->ID);
196 + if ($notificationBagde) {
197 + $newEmailBody = str_replace('<!--before_footer_section-->', $notificationBagde, $newEmailBody);
198 + }
199 +
200 + $hooksSections = apply_filters('fluent_community/new_feed_notification/email_sections', [
201 + 'before_content' => '',
202 + 'after_content' => ''
203 + ], $user, $feed);
204 +
205 + if (!empty($hooksSections['before_content'])) {
206 + $newEmailBody = str_replace('<!--email_content_before-->', $hooksSections['before_content'], $newEmailBody);
207 + }
208 +
209 + if (!empty($hooksSections['after_content'])) {
210 + $newEmailBody = str_replace('<!--email_content_after-->', $hooksSections['after_content'], $newEmailBody);
211 + }
212 +
156 213 $mailer = new Mailer('', $emailSubject, $newEmailBody);
157 214 $mailer->to($user->user_email, $user->display_name);
158 215 $mailer->send();
159 216
160 - if (microtime(true) - FLUENT_COMMUNITY_START_TIME > 50) {
217 + if (microtime(true) - FLUENT_COMMUNITY_START_TIME > $this->maxRunTime) {
161 218 // It's been 45 seconds, let's stop and schedule the next one and schedule a new one
162 219 as_schedule_single_action(time(), 'fluent_community/email_notify_new_posts', [$feed->id], 'fluent-community');
163 220 return true;
164 221 }
@@ -165,13 +222,12 @@
165 222
166 223 if (($index + 1) % $maxSendPerSecond == 0) {
167 224 $timeTaken = microtime(true) - $startTime;
168 225 if ($timeTaken < 1) {
169 - usleep(1000000 - ($timeTaken * 1000000));
226 + usleep((int)(1000000 - ($timeTaken * 1000000)));
170 227 }
171 228 $startTime = microtime(true);
172 229 }
173 -
174 230 }
175 231
176 232 return $this->notifyOnPostCreatedAsync($feed);
177 233 }
@@ -177,8 +233,14 @@
177 233 }
178 234
179 235 public function handleNewCommentEvent(Comment $comment, $feed)
180 236 {
237 + // Check the comment mentioned users or not
238 + if (Arr::get($comment->meta, 'mentioned_user_ids', [])) {
239 + as_schedule_single_action(time(), 'fluent_community/comment_added_async', [$comment->id, 0], 'fluent-community');
240 + return;
241 + }
242 +
181 243 if ($comment->parent_id) {
182 244 $globalCommentStatus = $this->isEnabled('reply_my_com_mail');
183 245 } else {
184 246 $globalCommentStatus = $this->isEnabled('com_my_post_mail');
@@ -183,10 +245,12 @@
183 245 } else {
184 246 $globalCommentStatus = $this->isEnabled('com_my_post_mail');
185 247 }
186 248
249 + $authorId = FeedsHelper::getNotificationAuthorId($feed);
250 +
187 251 $notificationUserIds = [];
188 - if ($comment->user_id != $feed->user_id && NotificationPref::willGetCommentEmail($feed->user_id, $globalCommentStatus)) {
252 + if ($comment->user_id != $authorId && NotificationPref::willGetNotification($authorId, 'comment', 'mail', $globalCommentStatus)) {
189 253 as_schedule_single_action(time(), 'fluent_community/comment_added_async', [$comment->id, 0], 'fluent-community');
190 254 return true;
191 255 }
192 256
@@ -192,9 +256,9 @@
192 256
193 257 if ($comment->parent_id) {
194 258 $notificationUserIds = $comment->getCommentParentUserIds();
195 259 $notificationUserIds = array_filter($notificationUserIds, function ($userId) use ($globalCommentStatus) {
196 - return NotificationPref::willGetCommentReplyEmail($userId, $globalCommentStatus);
260 + return NotificationPref::willGetNotification($userId, 'reply', 'mail', $globalCommentStatus);
197 261 });
198 262 }
199 263
200 264 if (!$notificationUserIds) {
@@ -215,9 +279,9 @@
215 279 return true;
216 280 }
217 281
218 282 $feed = $comment->post;
219 - if ($feed) {
283 + if (!$feed) {
220 284 return;
221 285 }
222 286
223 287 if ($comment->parent_id) {
@@ -227,19 +291,25 @@
227 291 }
228 292
229 293 $notificationUserIds = $comment->getCommentParentUserIds($lastUserId);
230 294 $notificationUserIds = array_filter($notificationUserIds, function ($userId) use ($globalCommentStatus) {
231 - return NotificationPref::willGetCommentReplyEmail($userId, $globalCommentStatus);
295 + return NotificationPref::willGetNotification($userId, 'reply', 'mail', $globalCommentStatus);
232 296 });
233 297
234 298 $notificationUserIds = array_diff($notificationUserIds, [$comment->user_id]);
235 - if ($comment->user_id != $feed->user_id && NotificationPref::willGetCommentEmail($feed->user_id, $globalCommentStatus)) {
299 + $authorId = FeedsHelper::getNotificationAuthorId($feed);
300 + if ($comment->user_id != $authorId && NotificationPref::willGetNotification($authorId, 'comment', 'mail', $globalCommentStatus)) {
236 301 // Add at the first
237 - $notificationUserIds[] = $feed->user_id;
302 + $notificationUserIds[] = $authorId;
238 303 }
239 304
240 - if (!$notificationUserIds) {
241 - return;
305 + // the mentioned user ids
306 + if ($mentionedUserIds = Arr::get($comment->meta, 'mentioned_user_ids', [])) {
307 + foreach ($mentionedUserIds as $mentionedUserId) {
308 + if (NotificationPref::willGetNotification($mentionedUserId, 'mention', 'mail', $this->isEnabled('mention_mail'))) {
309 + $notificationUserIds[] = $mentionedUserId;
310 + }
311 + }
242 312 }
243 313
244 314 if (!$notificationUserIds) {
245 315 return;
@@ -260,9 +330,11 @@
260 330 if ($users->isEmpty()) {
261 331 return; // it's done
262 332 }
263 333
264 - $emailBody = $this->getCommentHtml($comment, true);
334 + $undeliverableEmails = Helper::getUndeliverableEmails($users->pluck('user_email')->toArray());
335 +
336 + $emailBody = $comment->getCommentHtml(true);
265 337 $emailSubject = $comment->getEmailSubject($feed);
266 338
267 339 $feedPermalik = $feed->getPermalink() . '?comment_id=' . $comment->id;
268 340 $usersCount = count($users);
@@ -274,8 +346,12 @@
274 346 if ($user->ID == $comment->user_id) {
275 347 continue;
276 348 }
277 349
350 + if ($undeliverableEmails && in_array(strtolower($user->user_email), $undeliverableEmails)) {
351 + continue;
352 + }
353 +
278 354 $newEmailBody = str_replace([
279 355 '##feed_permalink##',
280 356 '##email_notification_url##'
281 357 ], [
@@ -282,8 +358,26 @@
282 358 ProfileHelper::signUserUrlWithAuthHash($feedPermalik, $user->ID),
283 359 ProfileHelper::getSignedNotificationPrefUrl($user->ID)
284 360 ], $emailBody);
285 361
362 + $notificationBagde = $this->getNotificationBadges($user->ID);
363 + if ($notificationBagde) {
364 + $newEmailBody = str_replace('<!--before_footer_section-->', $notificationBagde, $newEmailBody);
365 + }
366 +
367 + $hooksSections = apply_filters('fluent_community/comment_notification/email_sections', [
368 + 'before_content' => '',
369 + 'after_content' => ''
370 + ], $user, $comment);
371 +
372 + if (!empty($hooksSections['before_content'])) {
373 + $newEmailBody = str_replace('<!--email_content_before-->', $hooksSections['before_content'], $newEmailBody);
374 + }
375 +
376 + if (!empty($hooksSections['after_content'])) {
377 + $newEmailBody = str_replace('<!--email_content_after-->', $hooksSections['after_content'], $newEmailBody);
378 + }
379 +
286 380 $mailer = new Mailer('', $emailSubject, $newEmailBody);
287 381 $mailer->to($user->user_email, $user->display_name);
288 382 $mailer->send();
289 383
@@ -295,9 +389,9 @@
295 389
296 390 if (($index + 1) % $maxSendPerSecond == 0) {
297 391 $timeTaken = microtime(true) - $startTime;
298 392 if ($timeTaken < 1) {
299 - usleep(1000000 - ($timeTaken * 1000000));
393 + usleep((int)(1000000 - ($timeTaken * 1000000)));
300 394 }
301 395 $startTime = microtime(true);
302 396 }
303 397 }
@@ -307,8 +401,12 @@
307 401 }
308 402
309 403 public function emailNotifyUsersForEveryoneTag($feedId, $lastSendUserId = 0)
310 404 {
405 + if (!$this->maxRunTime) {
406 + $this->maxRunTime = Utility::getMaxRunTime();
407 + }
408 +
311 409 // Let's try to send email to all users of this space for this post
312 410 $feed = Feed::find($feedId);
313 411
314 412 if (!$feed || !$feed->space) {
@@ -314,13 +412,9 @@
314 412 if (!$feed || !$feed->space) {
315 413 return true;
316 414 }
317 415
318 - $message = $feed->message;
319 - $pattern = '/(?<!\S)@everyone(?!\S)/';
320 -
321 - // match if the message contains @everyone
322 - if (!preg_match($pattern, $message)) {
416 + if (!$feed->isEnabledForEveryoneTag()) {
323 417 return true;
324 418 }
325 419
326 420 $notification = Notification::where('action', 'space_feed/created')
@@ -330,11 +424,12 @@
330 424 if (!$notification) {
331 425 return true;
332 426 }
333 427
334 - $users = User::whereDoesntHave('notificationSubscriptions', function ($query) {
335 - $query->where('notification_type', 'mention_mail')
336 - ->where('is_read', 0);
428 + $users = User::whereDoesntHave('notificationPreferences', function ($query) {
429 + $query->where('channel', 'mail')
430 + ->where('event_key', 'mention')
431 + ->where('value', 0);
337 432 })
338 433 ->whereHas('space_pivot', function ($query) use ($feed) {
339 434 $query->where('space_id', $feed->space_id)
340 435 ->where('status', 'active');
@@ -352,17 +447,21 @@
352 447 if ($users->isEmpty()) {
353 448 return true; // it's done
354 449 }
355 450
451 + $undeliverableEmails = Helper::getUndeliverableEmails($users->pluck('user_email')->toArray());
452 +
356 453 $author = $feed->user;
454 +
357 455 $emailSubject = \sprintf(
358 - /* translators: %1$s is the user name, %2$s is the space title and %3$3s is the time */
359 - __('%1$s mentioned you and others in a post at %2$s [%3$s]', 'fluent-community'),
360 - $author->display_name,
361 - $feed->space->title,
362 - gmdate('H:i', strtotime($feed->created_at))
456 + /* translators: for admin post to send email all space members: %1$s is the feed title, %2$s is the author name and %3$s space name */
457 + __('%1$s - %2$s [%3$s]', 'fluent-community'),
458 + $feed->getHumanExcerpt(30),
459 + $author->getPublicDisplayName(),
460 + $feed->space->title
363 461 );
364 - $emailBody = $this->getFeedHtml($feed, true);
462 +
463 + $emailBody = $feed->getFeedHtml(true);
365 464 $feedPermalink = $feed->getPermalink();
366 465
367 466 $startTime = microtime(true);
368 467 $maxSendPerSecond = 10; // max 10 emails per second
@@ -372,8 +471,12 @@
372 471 if ($user->ID == $author->ID) {
373 472 continue;
374 473 }
375 474
475 + if ($undeliverableEmails && in_array(strtolower($user->user_email), $undeliverableEmails)) {
476 + continue;
477 + }
478 +
376 479 $newEmailBody = str_replace([
377 480 '##feed_permalink##',
378 481 '##email_notification_url##'
379 482 ], [
@@ -380,13 +483,31 @@
380 483 ProfileHelper::signUserUrlWithAuthHash($feedPermalink, $user->ID),
381 484 ProfileHelper::getSignedNotificationPrefUrl($user->ID)
382 485 ], $emailBody);
383 486
487 + $notificationBagde = $this->getNotificationBadges($user->ID);
488 + if ($notificationBagde) {
489 + $newEmailBody = str_replace('<!--before_footer_section-->', $notificationBagde, $newEmailBody);
490 + }
491 +
492 + $hooksSections = apply_filters('fluent_community/new_feed_everybody_notification/email_sections', [
493 + 'before_content' => '',
494 + 'after_content' => ''
495 + ], $user, $feed);
496 +
497 + if (!empty($hooksSections['before_content'])) {
498 + $newEmailBody = str_replace('<!--email_content_before-->', $hooksSections['before_content'], $newEmailBody);
499 + }
500 +
501 + if (!empty($hooksSections['after_content'])) {
502 + $newEmailBody = str_replace('<!--email_content_after-->', $hooksSections['after_content'], $newEmailBody);
503 + }
504 +
384 505 $mailer = new Mailer('', $emailSubject, $newEmailBody);
385 506 $mailer->to($user->user_email, $user->display_name);
386 507 $mailer->send();
387 508
388 - if (microtime(true) - FLUENT_COMMUNITY_START_TIME > 50) {
509 + if (microtime(true) - FLUENT_COMMUNITY_START_TIME > $this->maxRunTime) {
389 510 // It's been 45 seconds, let's stop and schedule the next one and schedule a new one
390 511 as_schedule_single_action(time(), 'fluent_community/email_notify_users_everyone_tag', [$feedId, $lastSendUserId], 'fluent-community');
391 512 return true;
392 513 }
@@ -393,9 +514,9 @@
393 514
394 515 if (($index + 1) % $maxSendPerSecond == 0) {
395 516 $timeTaken = microtime(true) - $startTime;
396 517 if ($timeTaken < 1) {
397 - usleep(1000000 - ($timeTaken * 1000000));
518 + usleep((int)(1000000 - ($timeTaken * 1000000)));
398 519 }
399 520 $startTime = microtime(true);
400 521 }
401 522 }
@@ -403,81 +524,14 @@
403 524 sleep(1); // sleeping for 1 second
404 525 return $this->emailNotifyUsersForEveryoneTag($feedId, $lastSendUserId);
405 526 }
406 527
407 - public function getCommentHtml($comment, $withPlaceholder = false)
528 + public function maybeSendDailyDigest()
408 529 {
409 - $emailComposer = new \FluentCommunity\App\Services\Libs\EmailComposer();
410 - if ($withPlaceholder) {
411 - $postPermalink = '##feed_permalink##';
412 - } else {
413 - $postPermalink = $comment->post->getPermalink() . '?comment_id=' . $comment->id;
530 + if (!$this->maxRunTime) {
531 + $this->maxRunTime = Utility::getMaxRunTime();
414 532 }
415 533
416 - if ($comment->post->title) {
417 - $postTitle = $comment->post->title;
418 - } else {
419 - $postTitle = $comment->post->getHumanExcerpt(120);
420 - }
421 -
422 - $renderedMessage = $comment->message_rendered;
423 -
424 - // Remove all the URLs with the text but make it underlined
425 - $renderedMessage = preg_replace('/<a href="([^"]+)">([^<]+)<\/a>/', '<span style="text-decoration: underline !important;">$2</span>', $renderedMessage);
426 -
427 - $renderedMessage .= $this->getMediaHtml($comment->meta, $postPermalink);
428 -
429 - $emailComposer->addBlock('boxed_content', $renderedMessage, [
430 - 'user' => $comment->user,
431 - 'permalink' => $postPermalink,
432 - 'post_content' => $postTitle
433 - ]);
434 -
435 - $emailComposer->addBlock('button', __('View the comment', 'fluent-community'), [
436 - 'link' => $postPermalink
437 - ]);
438 -
439 - // $emailComposer->setLogo(\FluentCommunity\Framework\Support\Arr::get($settting, 'logo'));
440 - $emailComposer->setDefaultFooter($withPlaceholder);
441 -
442 - return $emailComposer->getHtml();
443 - }
444 -
445 - public function getFeedHtml($feed, $withPlaceholder = false)
446 - {
447 - $emailComposer = new \FluentCommunity\App\Services\Libs\EmailComposer();
448 -
449 - if ($withPlaceholder) {
450 - $postPermalink = '##feed_permalink##';
451 - } else {
452 - $postPermalink = $feed->getPermalink();
453 - }
454 -
455 - $feedHtml = $feed->message_rendered;
456 - $feedHtml .= $this->getMediaHtml($feed->meta, $postPermalink);
457 -
458 - $emailComposer->addBlock('post_boxed_content', $feedHtml, [
459 - 'user' => $feed->user,
460 - 'title' => $feed->title,
461 - 'permalink' => $postPermalink,
462 - 'space_name' => $feed->space ? $feed->space->title : __('Community', 'fluent-community'),
463 - 'is_single' => true
464 - ]);
465 -
466 - $emailComposer->addBlock('button', __('Join the conversation', 'fluent-community'), [
467 - 'link' => $postPermalink
468 - ]);
469 -
470 - // $emailComposer->setLogo(\FluentCommunity\Framework\Support\Arr::get($settting, 'logo'));
471 -// $emailComposer->addFooterLine('paragraph', sprintf(__('You are getting this email because you are a member of %s', 'fluent-community'), '<a style="text-decoration: underline !important;" href="' . Helper::baseUrl() . '">' . get_bloginfo('name') . '</a>'));
472 -
473 - $emailComposer->setDefaultFooter();
474 -
475 - return $emailComposer->getHtml();
476 - }
477 -
478 - public function maybeSendDailyDigest()
479 - {
480 534 $settings = Utility::getEmailNotificationSettings();
481 535
482 536 $digestEmailDay = Arr::get($settings, 'digest_mail_day');
483 537 if (strtolower(gmdate('D', current_time('timestamp'))) != $digestEmailDay) {
@@ -492,11 +546,12 @@
492 546 $globalEnabled = Arr::get($settings, 'digest_email_status') === 'yes';
493 547 $lastSentUserId = Utility::getOption('last_digest_sent_user_id');
494 548
495 549 if ($globalEnabled) {
496 - $users = User::whereDoesntHave('notification_records', function ($query) {
497 - $query->where('notification_type', 'digest_mail')
498 - ->where('is_read', 0);
550 + $users = User::whereDoesntHave('notificationPreferences', function ($query) {
551 + $query->where('channel', 'mail')
552 + ->where('event_key', 'digest')
553 + ->where('value', 0);
499 554 })
500 555 ->whereHas('xprofile', function ($query) {
501 556 $query->where('status', 'active');
502 557 })
@@ -505,23 +560,22 @@
505 560 })
506 561 ->limit(100)
507 562 ->orderBy('ID', 'ASC')
508 563 ->get();
509 -
510 564 } else {
511 -
512 - $users = User::whereHas('notification_records', function ($query) {
513 - $query->where('notification_type', 'digest_mail')
514 - ->where('is_read', 1);
565 + $users = User::whereHas('notificationPreferences', function ($query) {
566 + $query->where('channel', 'mail')
567 + ->where('event_key', 'digest')
568 + ->where('value', 1);
515 569 })
516 - ->orderBy('ID', 'ASC')
517 570 ->whereHas('xprofile', function ($query) {
518 - return $query->where('status', 'active');
571 + $query->where('status', 'active');
519 572 })
520 573 ->when($lastSentUserId, function ($q) use ($lastSentUserId) {
521 574 $q->where('ID', '>', $lastSentUserId);
522 575 })
523 576 ->limit(100)
577 + ->orderBy('ID', 'ASC')
524 578 ->get();
525 579 }
526 580
527 581 if ($users->isEmpty()) {
@@ -530,23 +584,29 @@
530 584 Utility::updateOption('last_digest_sent_user_id', 0);
531 585 return false;
532 586 }
533 587
588 + $undeliverableEmails = Helper::getUndeliverableEmails($users->pluck('user_email')->toArray());
589 +
534 590 $startAt = microtime(true);
535 591 $maxSendPerSecond = 10;
536 -
537 592 $sentCount = 0;
538 593
539 594 foreach ($users as $user) {
540 - Utility::updateOption('last_digest_sent_user_id', $user->user_id);
595 + Utility::updateOption('last_digest_sent_user_id', $user->ID);
596 +
597 + if ($undeliverableEmails && in_array(strtolower($user->user_email), $undeliverableEmails)) {
598 + continue;
599 + }
600 +
541 601 $emailDigest = new DailyDigest($user);
542 602 if ($emailDigest->send()) {
543 603 $sentCount++;
544 604 }
545 605
546 - if (microtime(true) - FLUENT_COMMUNITY_START_TIME > 50) {
606 + if (microtime(true) - FLUENT_COMMUNITY_START_TIME > $this->maxRunTime) {
547 607 // It's been 45 seconds, let's stop and schedule the next one and schedule a new one
548 - as_schedule_single_action(time(), 'fluent_community_send_daily_digest', null, 'fluent-community');
608 + as_schedule_single_action(time(), 'fluent_community_send_daily_digest', [], 'fluent-community', false);
549 609 return true;
550 610 }
551 611
552 612 if ($sentCount % $maxSendPerSecond === 0) {
@@ -551,9 +611,9 @@
551 611
552 612 if ($sentCount % $maxSendPerSecond === 0) {
553 613 $timeTaken = microtime(true) - $startAt;
554 614 if ($timeTaken < 1) {
555 - usleep(1000000 - ($timeTaken * 1000000));
615 + usleep((int)(1000000 - ($timeTaken * 1000000)));
556 616 }
557 617 $startAt = microtime(true);
558 618 }
559 619 }
@@ -574,14 +634,13 @@
574 634 if (!$xProfile) {
575 635 return;
576 636 }
577 637
578 - $settting = Helper::generalSettings();
579 -
580 638 $emailComposer = new \FluentCommunity\App\Services\Libs\EmailComposer();
581 639
582 640 $emailComposer->addBlock('paragraph', __('Hi Space Leader,', 'fluent-community'));
583 - $emailComposer->addBlock('paragraph', sprintf(__('You have a new join request from %1$s to join at %2$s.', 'fluent-community'), '<b>' . $xProfile->display_name . '</b>', '<b>' . $space->title . '</b>'));
641 + /* translators: %1$s is replaced by the name of the user who requested to join the space, %2$s is replaced by the title of the space */
642 + $emailComposer->addBlock('paragraph', sprintf(__('You have a new join request from %1$s to join %2$s.', 'fluent-community'), '<b>' . $xProfile->display_name . '</b>', '<b>' . $space->title . '</b>'));
584 643 $emailComposer->addBlock('paragraph', __('Please review the request in the portal', 'fluent-community'));
585 644
586 645 $emailComposer->addBlock('button', __('View Pending Join Requests', 'fluent-community'), [
587 646 'link' => Helper::baseUrl('space/' . $space->slug . '/members?view_pending=yes')
@@ -586,15 +645,17 @@
586 645 $emailComposer->addBlock('button', __('View Pending Join Requests', 'fluent-community'), [
587 646 'link' => Helper::baseUrl('space/' . $space->slug . '/members?view_pending=yes')
588 647 ]);
589 648
590 - $emailComposer->setLogo(\FluentCommunity\Framework\Support\Arr::get($settting, 'logo'));
649 + $emailComposer->setDefaultLogo();
591 650
651 + /* translators: %s is replaced by the title of the space */
592 652 $emailComposer->addFooterLine('paragraph', sprintf(__('You are getting this email because you are an admin/moderator at %s', 'fluent-community'), '<a style="text-decoration: underline !important;" href="' . $space->getPermalink() . '">' . $space->title . '</a>'));
593 653
594 654 $emailBody = $emailComposer->getHtml();
595 655
596 - $emailSubject = sprintf(
656 + $emailSubject = \sprintf(
657 + /* translators: %1$s is replaced by the name of the user who requested to join the space, %2$s is replaced by the title of the space */
597 658 __('%1$s requested to join %2$s', 'fluent-community'),
598 659 $xProfile->display_name,
599 660 $space->title
600 661 );
@@ -613,9 +674,9 @@
613 674 $modUserId = $moderatorsUserIds[0];
614 675
615 676 $moderator = get_user_by('ID', $modUserId);
616 677
617 - if (!$moderator || !$moderator->user_email) {
678 + if (!$moderator || !$moderator->user_email || Helper::isUndeliverableEmail($moderator->user_email)) {
618 679 return;
619 680 }
620 681
621 682 $mailer->to($moderator->user_email, $moderator->display_name);
@@ -629,44 +690,57 @@
629 690
630 691 $mailer = new Mailer('', $emailSubject, $emailBody);
631 692
632 693 $users = User::whereIn('ID', $chunk)->get();
694 + $undeliverableEmails = Helper::getUndeliverableEmails($users->pluck('user_email')->toArray());
695 +
696 + $first = null;
633 697 foreach ($users as $user) {
634 698 if (!$user || !$user->user_email) {
635 699 continue;
636 700 }
701 +
702 + if ($undeliverableEmails && in_array(strtolower($user->user_email), $undeliverableEmails)) {
703 + continue;
704 + }
705 + if (!$first) {
706 + $mailer->to($user->user_email, $user->display_name);
707 + $first = $user;
708 + continue;
709 + }
637 710 $mailer->addBCC($user->display_name . ' <' . $user->user_email . '>');
638 711 }
639 712
640 - $mailer->send();
641 - sleep(1); // sleeping for 1 second
713 + if ($first) {
714 + $mailer->send();
715 + sleep(1); // sleeping for 1 second
716 + }
642 717 }
643 718
644 719 return true;
645 720 }
646 721
647 - private function getMediaHtml($meta, $postPermalink)
722 + private function getNotificationBadges($userId)
648 723 {
649 - $mediaImage = Arr::get($meta, 'media_preview.image');
650 - $mediaCount = 0;
651 - if (!$mediaImage) {
652 - $mediaItems = Arr::get($meta, 'media_items', []);
653 - if ($mediaItems) {
654 - $mediaImage = Arr::get($mediaItems[0], 'url');
655 - $mediaCount = count($mediaItems);
724 + $unreadCount = Notification::byStatus('unread', $userId)->count();
725 + $unreadMessages = apply_filters('fluent_messaging/get_unread_message_count', 0, $userId);
726 +
727 + $html = '';
728 + $linkColor = Utility::getThemeColor();
729 + if ($unreadCount) {
730 + $notificationUrl = ProfileHelper::signUserUrlWithAuthHash(Helper::baseUrl('notifications'), $userId);
731 + /* translators: %d is replaced by the number of unread notifications */
732 + $html = '<a style="text-decoration: none; color: ' . esc_attr($linkColor) . ';" href="' . $notificationUrl . '">' . sprintf(__('🔔 %d Unread Notifications', 'fluent-community'), $unreadCount) . '</a>';
733 + if ($unreadMessages) {
734 + $html .= '<span style="margin: 0 10px;"> | </span>';
656 735 }
657 736 }
658 737
659 - $feedHtml = '';
660 -
661 - if ($mediaImage) {
662 - $feedHtml .= '<div class="fcom_media" style="margin-top: 20px;">';
663 - $feedHtml .= '<a href="' . $postPermalink . '"><img src="' . $mediaImage . '" style="max-width: 100%; height: auto; display: block; margin: 0 auto 0px;" /></a>';
664 - if ($mediaCount > 1) {
665 - $feedHtml .= '<p style="text-align: center; font-size: 14px; color: #666; margin-top: 10px;">' . sprintf(_n('+%d more image', '+%d more images', $mediaCount - 1, 'fluent-community'), $mediaCount - 1) . '</p>';
666 - }
667 - $feedHtml .= '</div>';
738 + if ($unreadMessages) {
739 + $chatUrl = ProfileHelper::signUserUrlWithAuthHash(Helper::baseUrl('chat'), $userId);
740 + /* translators: %d is replaced by the number of unread messages */
741 + $html .= '<a style="text-decoration: none; color: ' . esc_attr($linkColor) . ';" href="' . $chatUrl . '">' . sprintf(__('✉️ %d Unread Messages', 'fluent-community'), $unreadMessages) . '</a>';
668 742 }
669 743
670 - return $feedHtml;
744 + return $html;
671 745 }
672 746 }