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 +218 -158 1.0.952.11.0 View file →
@@ -12,8 +12,9 @@
12 12 use FluentCommunity\App\Models\XProfile;
13 13 use FluentCommunity\App\Services\Helper;
14 14 use FluentCommunity\App\Services\Libs\DailyDigest;
15 15 use FluentCommunity\App\Services\Libs\Mailer;
16 +use FluentCommunity\App\Services\FeedsHelper;
16 17 use FluentCommunity\App\Services\NotificationPref;
17 18 use FluentCommunity\App\Services\ProfileHelper;
18 19 use FluentCommunity\Framework\Support\Arr;
19 20
@@ -18,14 +19,13 @@
18 19 use FluentCommunity\Framework\Support\Arr;
19 20
20 21 class EmailNotificationHandler
21 22 {
22 -
23 23 private $maxRunTime = 0;
24 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');
@@ -92,20 +108,32 @@
92 108 if (!$space || !$feed->user) {
93 109 return;
94 110 }
95 111
96 - $types = ['np_by_member_mail'];
112 + $events = ['np_by_member'];
97 113 $spaceRole = $feed->user->getSpaceRole($feed->space);
98 114 if (in_array($spaceRole, ['admin', 'moderator'])) {
99 - $types[] = 'np_by_admin_mail';
115 + $events[] = 'np_by_admin';
100 116 }
101 117
102 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 + });
103 126
104 - $users = User::whereHas('notificationSubscriptions', function ($query) use ($types, $space) {
105 - $query->whereIn('notification_type', $types)
106 - ->where('object_id', $space->id)
107 - ->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;
108 136 })
109 137 ->whereHas('space_pivot', function ($query) use ($space) {
110 138 $query->where('space_id', $space->id)
111 139 ->where('status', 'active');
@@ -116,23 +144,26 @@
116 144 ->whereHas('xprofile', function ($query) {
117 145 return $query->where('status', 'active');
118 146 })
119 147 ->orderBy('ID', 'ASC')
120 - ->limit(60)
121 - ->get();
148 + ->limit(60);
122 149
150 + $users = $usersQuery->get();
151 +
123 152 if ($users->isEmpty()) {
124 153 return; // It's done
125 154 }
126 155
156 + $undeliverableEmails = Helper::getUndeliverableEmails($users->pluck('user_email')->toArray());
157 +
127 158 $emailSubject = \sprintf(
128 159 /* translators: %1$s is the author name and %2$s is the post excerpt (max 30 chars) */
129 160 __('New Post By %1$s: %2$s', 'fluent-community'),
130 - $feed->user->getDisplayName(),
161 + $feed->user->getPublicDisplayName(),
131 162 $feed->getHumanExcerpt(30)
132 163 );
133 164
134 - $emailBody = $this->getFeedHtml($feed, true);
165 + $emailBody = $feed->getFeedHtml(true);
135 166
136 167 /*
137 168 * must need to replace these two strings
138 169 * ##feed_permalink##
@@ -148,8 +179,12 @@
148 179 if ($user->ID == $feed->user_id) {
149 180 continue;
150 181 }
151 182
183 + if ($undeliverableEmails && in_array(strtolower($user->user_email), $undeliverableEmails)) {
184 + continue;
185 + }
186 +
152 187 $newEmailBody = str_replace([
153 188 '##feed_permalink##',
154 189 '##email_notification_url##'
155 190 ], [
@@ -156,8 +191,26 @@
156 191 ProfileHelper::signUserUrlWithAuthHash($feedLink, $user->ID),
157 192 ProfileHelper::getSignedNotificationPrefUrl($user->ID)
158 193 ], $emailBody);
159 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 +
160 213 $mailer = new Mailer('', $emailSubject, $newEmailBody);
161 214 $mailer->to($user->user_email, $user->display_name);
162 215 $mailer->send();
163 216
@@ -169,13 +222,12 @@
169 222
170 223 if (($index + 1) % $maxSendPerSecond == 0) {
171 224 $timeTaken = microtime(true) - $startTime;
172 225 if ($timeTaken < 1) {
173 - usleep(1000000 - ($timeTaken * 1000000));
226 + usleep((int)(1000000 - ($timeTaken * 1000000)));
174 227 }
175 228 $startTime = microtime(true);
176 229 }
177 -
178 230 }
179 231
180 232 return $this->notifyOnPostCreatedAsync($feed);
181 233 }
@@ -181,8 +233,14 @@
181 233 }
182 234
183 235 public function handleNewCommentEvent(Comment $comment, $feed)
184 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 +
185 243 if ($comment->parent_id) {
186 244 $globalCommentStatus = $this->isEnabled('reply_my_com_mail');
187 245 } else {
188 246 $globalCommentStatus = $this->isEnabled('com_my_post_mail');
@@ -187,10 +245,12 @@
187 245 } else {
188 246 $globalCommentStatus = $this->isEnabled('com_my_post_mail');
189 247 }
190 248
249 + $authorId = FeedsHelper::getNotificationAuthorId($feed);
250 +
191 251 $notificationUserIds = [];
192 - 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)) {
193 253 as_schedule_single_action(time(), 'fluent_community/comment_added_async', [$comment->id, 0], 'fluent-community');
194 254 return true;
195 255 }
196 256
@@ -196,9 +256,9 @@
196 256
197 257 if ($comment->parent_id) {
198 258 $notificationUserIds = $comment->getCommentParentUserIds();
199 259 $notificationUserIds = array_filter($notificationUserIds, function ($userId) use ($globalCommentStatus) {
200 - return NotificationPref::willGetCommentReplyEmail($userId, $globalCommentStatus);
260 + return NotificationPref::willGetNotification($userId, 'reply', 'mail', $globalCommentStatus);
201 261 });
202 262 }
203 263
204 264 if (!$notificationUserIds) {
@@ -231,19 +291,25 @@
231 291 }
232 292
233 293 $notificationUserIds = $comment->getCommentParentUserIds($lastUserId);
234 294 $notificationUserIds = array_filter($notificationUserIds, function ($userId) use ($globalCommentStatus) {
235 - return NotificationPref::willGetCommentReplyEmail($userId, $globalCommentStatus);
295 + return NotificationPref::willGetNotification($userId, 'reply', 'mail', $globalCommentStatus);
236 296 });
237 297
238 298 $notificationUserIds = array_diff($notificationUserIds, [$comment->user_id]);
239 - 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)) {
240 301 // Add at the first
241 - $notificationUserIds[] = $feed->user_id;
302 + $notificationUserIds[] = $authorId;
242 303 }
243 304
244 - if (!$notificationUserIds) {
245 - 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 + }
246 312 }
247 313
248 314 if (!$notificationUserIds) {
249 315 return;
@@ -264,9 +330,11 @@
264 330 if ($users->isEmpty()) {
265 331 return; // it's done
266 332 }
267 333
268 - $emailBody = $this->getCommentHtml($comment, true);
334 + $undeliverableEmails = Helper::getUndeliverableEmails($users->pluck('user_email')->toArray());
335 +
336 + $emailBody = $comment->getCommentHtml(true);
269 337 $emailSubject = $comment->getEmailSubject($feed);
270 338
271 339 $feedPermalik = $feed->getPermalink() . '?comment_id=' . $comment->id;
272 340 $usersCount = count($users);
@@ -278,8 +346,12 @@
278 346 if ($user->ID == $comment->user_id) {
279 347 continue;
280 348 }
281 349
350 + if ($undeliverableEmails && in_array(strtolower($user->user_email), $undeliverableEmails)) {
351 + continue;
352 + }
353 +
282 354 $newEmailBody = str_replace([
283 355 '##feed_permalink##',
284 356 '##email_notification_url##'
285 357 ], [
@@ -286,8 +358,26 @@
286 358 ProfileHelper::signUserUrlWithAuthHash($feedPermalik, $user->ID),
287 359 ProfileHelper::getSignedNotificationPrefUrl($user->ID)
288 360 ], $emailBody);
289 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 +
290 380 $mailer = new Mailer('', $emailSubject, $newEmailBody);
291 381 $mailer->to($user->user_email, $user->display_name);
292 382 $mailer->send();
293 383
@@ -299,9 +389,9 @@
299 389
300 390 if (($index + 1) % $maxSendPerSecond == 0) {
301 391 $timeTaken = microtime(true) - $startTime;
302 392 if ($timeTaken < 1) {
303 - usleep(1000000 - ($timeTaken * 1000000));
393 + usleep((int)(1000000 - ($timeTaken * 1000000)));
304 394 }
305 395 $startTime = microtime(true);
306 396 }
307 397 }
@@ -311,9 +401,8 @@
311 401 }
312 402
313 403 public function emailNotifyUsersForEveryoneTag($feedId, $lastSendUserId = 0)
314 404 {
315 -
316 405 if (!$this->maxRunTime) {
317 406 $this->maxRunTime = Utility::getMaxRunTime();
318 407 }
319 408
@@ -323,13 +412,9 @@
323 412 if (!$feed || !$feed->space) {
324 413 return true;
325 414 }
326 415
327 - $message = $feed->message;
328 - $pattern = '/(?<!\S)@everyone(?!\S)/';
329 -
330 - // match if the message contains @everyone
331 - if (!preg_match($pattern, $message)) {
416 + if (!$feed->isEnabledForEveryoneTag()) {
332 417 return true;
333 418 }
334 419
335 420 $notification = Notification::where('action', 'space_feed/created')
@@ -339,11 +424,12 @@
339 424 if (!$notification) {
340 425 return true;
341 426 }
342 427
343 - $users = User::whereDoesntHave('notificationSubscriptions', function ($query) {
344 - $query->where('notification_type', 'mention_mail')
345 - ->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);
346 432 })
347 433 ->whereHas('space_pivot', function ($query) use ($feed) {
348 434 $query->where('space_id', $feed->space_id)
349 435 ->where('status', 'active');
@@ -361,17 +447,21 @@
361 447 if ($users->isEmpty()) {
362 448 return true; // it's done
363 449 }
364 450
451 + $undeliverableEmails = Helper::getUndeliverableEmails($users->pluck('user_email')->toArray());
452 +
365 453 $author = $feed->user;
454 +
366 455 $emailSubject = \sprintf(
367 - /* translators: %1$s is the user name, %2$s is the space title and %3$3s is the time */
368 - __('%1$s mentioned you and others in a post at %2$s [%3$s]', 'fluent-community'),
369 - $author->display_name,
370 - $feed->space->title,
371 - 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
372 461 );
373 - $emailBody = $this->getFeedHtml($feed, true);
462 +
463 + $emailBody = $feed->getFeedHtml(true);
374 464 $feedPermalink = $feed->getPermalink();
375 465
376 466 $startTime = microtime(true);
377 467 $maxSendPerSecond = 10; // max 10 emails per second
@@ -381,8 +471,12 @@
381 471 if ($user->ID == $author->ID) {
382 472 continue;
383 473 }
384 474
475 + if ($undeliverableEmails && in_array(strtolower($user->user_email), $undeliverableEmails)) {
476 + continue;
477 + }
478 +
385 479 $newEmailBody = str_replace([
386 480 '##feed_permalink##',
387 481 '##email_notification_url##'
388 482 ], [
@@ -389,8 +483,26 @@
389 483 ProfileHelper::signUserUrlWithAuthHash($feedPermalink, $user->ID),
390 484 ProfileHelper::getSignedNotificationPrefUrl($user->ID)
391 485 ], $emailBody);
392 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 +
393 505 $mailer = new Mailer('', $emailSubject, $newEmailBody);
394 506 $mailer->to($user->user_email, $user->display_name);
395 507 $mailer->send();
396 508
@@ -402,9 +514,9 @@
402 514
403 515 if (($index + 1) % $maxSendPerSecond == 0) {
404 516 $timeTaken = microtime(true) - $startTime;
405 517 if ($timeTaken < 1) {
406 - usleep(1000000 - ($timeTaken * 1000000));
518 + usleep((int)(1000000 - ($timeTaken * 1000000)));
407 519 }
408 520 $startTime = microtime(true);
409 521 }
410 522 }
@@ -412,82 +524,10 @@
412 524 sleep(1); // sleeping for 1 second
413 525 return $this->emailNotifyUsersForEveryoneTag($feedId, $lastSendUserId);
414 526 }
415 527
416 - public function getCommentHtml($comment, $withPlaceholder = false)
417 - {
418 - $emailComposer = new \FluentCommunity\App\Services\Libs\EmailComposer();
419 - if ($withPlaceholder) {
420 - $postPermalink = '##feed_permalink##';
421 - } else {
422 - $postPermalink = $comment->post->getPermalink() . '?comment_id=' . $comment->id;
423 - }
424 -
425 - if ($comment->post->title) {
426 - $postTitle = $comment->post->title;
427 - } else {
428 - $postTitle = $comment->post->getHumanExcerpt(120);
429 - }
430 -
431 - $renderedMessage = $comment->message_rendered;
432 -
433 - // Remove all the URLs with the text but make it underlined
434 - $renderedMessage = preg_replace('/<a href="([^"]+)">([^<]+)<\/a>/', '<span style="text-decoration: underline !important;">$2</span>', $renderedMessage);
435 -
436 - $renderedMessage .= $this->getMediaHtml($comment->meta, $postPermalink);
437 -
438 - $emailComposer->addBlock('boxed_content', $renderedMessage, [
439 - 'user' => $comment->user,
440 - 'permalink' => $postPermalink,
441 - 'post_content' => $postTitle
442 - ]);
443 -
444 - $emailComposer->addBlock('button', __('View the comment', 'fluent-community'), [
445 - 'link' => $postPermalink
446 - ]);
447 -
448 - // $emailComposer->setLogo(\FluentCommunity\Framework\Support\Arr::get($settting, 'logo'));
449 - $emailComposer->setDefaultFooter($withPlaceholder);
450 -
451 - return $emailComposer->getHtml();
452 - }
453 -
454 - public function getFeedHtml($feed, $withPlaceholder = false)
455 - {
456 - $emailComposer = new \FluentCommunity\App\Services\Libs\EmailComposer();
457 -
458 - if ($withPlaceholder) {
459 - $postPermalink = '##feed_permalink##';
460 - } else {
461 - $postPermalink = $feed->getPermalink();
462 - }
463 -
464 - $feedHtml = $feed->message_rendered;
465 - $feedHtml .= $this->getMediaHtml($feed->meta, $postPermalink);
466 -
467 - $emailComposer->addBlock('post_boxed_content', $feedHtml, [
468 - 'user' => $feed->user,
469 - 'title' => $feed->title,
470 - 'permalink' => $postPermalink,
471 - 'space_name' => $feed->space ? $feed->space->title : __('Community', 'fluent-community'),
472 - 'is_single' => true
473 - ]);
474 -
475 - $emailComposer->addBlock('button', __('Join the conversation', 'fluent-community'), [
476 - 'link' => $postPermalink
477 - ]);
478 -
479 - // $emailComposer->setLogo(\FluentCommunity\Framework\Support\Arr::get($settting, 'logo'));
480 -// $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>'));
481 -
482 - $emailComposer->setDefaultFooter();
483 -
484 - return $emailComposer->getHtml();
485 - }
486 -
487 528 public function maybeSendDailyDigest()
488 529 {
489 -
490 530 if (!$this->maxRunTime) {
491 531 $this->maxRunTime = Utility::getMaxRunTime();
492 532 }
493 533
@@ -506,11 +546,12 @@
506 546 $globalEnabled = Arr::get($settings, 'digest_email_status') === 'yes';
507 547 $lastSentUserId = Utility::getOption('last_digest_sent_user_id');
508 548
509 549 if ($globalEnabled) {
510 - $users = User::whereDoesntHave('notification_records', function ($query) {
511 - $query->where('notification_type', 'digest_mail')
512 - ->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);
513 554 })
514 555 ->whereHas('xprofile', function ($query) {
515 556 $query->where('status', 'active');
516 557 })
@@ -519,23 +560,22 @@
519 560 })
520 561 ->limit(100)
521 562 ->orderBy('ID', 'ASC')
522 563 ->get();
523 -
524 564 } else {
525 -
526 - $users = User::whereHas('notification_records', function ($query) {
527 - $query->where('notification_type', 'digest_mail')
528 - ->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);
529 569 })
530 - ->orderBy('ID', 'ASC')
531 570 ->whereHas('xprofile', function ($query) {
532 - return $query->where('status', 'active');
571 + $query->where('status', 'active');
533 572 })
534 573 ->when($lastSentUserId, function ($q) use ($lastSentUserId) {
535 574 $q->where('ID', '>', $lastSentUserId);
536 575 })
537 576 ->limit(100)
577 + ->orderBy('ID', 'ASC')
538 578 ->get();
539 579 }
540 580
541 581 if ($users->isEmpty()) {
@@ -544,15 +584,21 @@
544 584 Utility::updateOption('last_digest_sent_user_id', 0);
545 585 return false;
546 586 }
547 587
588 + $undeliverableEmails = Helper::getUndeliverableEmails($users->pluck('user_email')->toArray());
589 +
548 590 $startAt = microtime(true);
549 591 $maxSendPerSecond = 10;
550 -
551 592 $sentCount = 0;
552 593
553 594 foreach ($users as $user) {
554 - 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 +
555 601 $emailDigest = new DailyDigest($user);
556 602 if ($emailDigest->send()) {
557 603 $sentCount++;
558 604 }
@@ -558,9 +604,9 @@
558 604 }
559 605
560 606 if (microtime(true) - FLUENT_COMMUNITY_START_TIME > $this->maxRunTime) {
561 607 // It's been 45 seconds, let's stop and schedule the next one and schedule a new one
562 - as_schedule_single_action(time(), 'fluent_community_send_daily_digest', [], 'fluent-community', true);
608 + as_schedule_single_action(time(), 'fluent_community_send_daily_digest', [], 'fluent-community', false);
563 609 return true;
564 610 }
565 611
566 612 if ($sentCount % $maxSendPerSecond === 0) {
@@ -565,9 +611,9 @@
565 611
566 612 if ($sentCount % $maxSendPerSecond === 0) {
567 613 $timeTaken = microtime(true) - $startAt;
568 614 if ($timeTaken < 1) {
569 - usleep(1000000 - ($timeTaken * 1000000));
615 + usleep((int)(1000000 - ($timeTaken * 1000000)));
570 616 }
571 617 $startAt = microtime(true);
572 618 }
573 619 }
@@ -588,14 +634,13 @@
588 634 if (!$xProfile) {
589 635 return;
590 636 }
591 637
592 - $settting = Helper::generalSettings();
593 -
594 638 $emailComposer = new \FluentCommunity\App\Services\Libs\EmailComposer();
595 639
596 640 $emailComposer->addBlock('paragraph', __('Hi Space Leader,', 'fluent-community'));
597 - $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>'));
598 643 $emailComposer->addBlock('paragraph', __('Please review the request in the portal', 'fluent-community'));
599 644
600 645 $emailComposer->addBlock('button', __('View Pending Join Requests', 'fluent-community'), [
601 646 'link' => Helper::baseUrl('space/' . $space->slug . '/members?view_pending=yes')
@@ -600,15 +645,17 @@
600 645 $emailComposer->addBlock('button', __('View Pending Join Requests', 'fluent-community'), [
601 646 'link' => Helper::baseUrl('space/' . $space->slug . '/members?view_pending=yes')
602 647 ]);
603 648
604 - $emailComposer->setLogo(\FluentCommunity\Framework\Support\Arr::get($settting, 'logo'));
649 + $emailComposer->setDefaultLogo();
605 650
651 + /* translators: %s is replaced by the title of the space */
606 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>'));
607 653
608 654 $emailBody = $emailComposer->getHtml();
609 655
610 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 */
611 658 __('%1$s requested to join %2$s', 'fluent-community'),
612 659 $xProfile->display_name,
613 660 $space->title
614 661 );
@@ -627,9 +674,9 @@
627 674 $modUserId = $moderatorsUserIds[0];
628 675
629 676 $moderator = get_user_by('ID', $modUserId);
630 677
631 - if (!$moderator || !$moderator->user_email) {
678 + if (!$moderator || !$moderator->user_email || Helper::isUndeliverableEmail($moderator->user_email)) {
632 679 return;
633 680 }
634 681
635 682 $mailer->to($moderator->user_email, $moderator->display_name);
@@ -643,44 +690,57 @@
643 690
644 691 $mailer = new Mailer('', $emailSubject, $emailBody);
645 692
646 693 $users = User::whereIn('ID', $chunk)->get();
694 + $undeliverableEmails = Helper::getUndeliverableEmails($users->pluck('user_email')->toArray());
695 +
696 + $first = null;
647 697 foreach ($users as $user) {
648 698 if (!$user || !$user->user_email) {
649 699 continue;
650 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 + }
651 710 $mailer->addBCC($user->display_name . ' <' . $user->user_email . '>');
652 711 }
653 712
654 - $mailer->send();
655 - sleep(1); // sleeping for 1 second
713 + if ($first) {
714 + $mailer->send();
715 + sleep(1); // sleeping for 1 second
716 + }
656 717 }
657 718
658 719 return true;
659 720 }
660 721
661 - private function getMediaHtml($meta, $postPermalink)
722 + private function getNotificationBadges($userId)
662 723 {
663 - $mediaImage = Arr::get($meta, 'media_preview.image');
664 - $mediaCount = 0;
665 - if (!$mediaImage) {
666 - $mediaItems = Arr::get($meta, 'media_items', []);
667 - if ($mediaItems) {
668 - $mediaImage = Arr::get($mediaItems[0], 'url');
669 - $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>';
670 735 }
671 736 }
672 737
673 - $feedHtml = '';
674 -
675 - if ($mediaImage) {
676 - $feedHtml .= '<div class="fcom_media" style="margin-top: 20px;">';
677 - $feedHtml .= '<a href="' . $postPermalink . '"><img src="' . $mediaImage . '" style="max-width: 100%; height: auto; display: block; margin: 0 auto 0px;" /></a>';
678 - if ($mediaCount > 1) {
679 - $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>';
680 - }
681 - $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>';
682 742 }
683 743
684 - return $feedHtml;
744 + return $html;
685 745 }
686 746 }