1 | <?php |
||
2 | |||
3 | /** |
||
4 | * Functions to support the sending of notifications (new posts, replys, topics) |
||
5 | * |
||
6 | * @package ElkArte Forum |
||
7 | * @copyright ElkArte Forum contributors |
||
8 | * @license BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file) |
||
9 | * |
||
10 | * @version 2.0 dev |
||
11 | * |
||
12 | */ |
||
13 | |||
14 | use ElkArte\Helper\TokenHash; |
||
15 | use ElkArte\Helper\Util; |
||
16 | use ElkArte\Languages\Loader; |
||
17 | use ElkArte\Notifications\Notifications; |
||
18 | use ElkArte\Notifications\PostNotifications; |
||
19 | use ElkArte\User; |
||
20 | |||
21 | /** |
||
22 | * Sends a notification to members who have elected to receive emails |
||
23 | * |
||
24 | * @param int[]|int $topics - represents the topics the action is happening to. |
||
25 | * @param string $type - can be any of reply, sticky, lock, unlock, remove, |
||
26 | * move, merge, and split. An appropriate message will be sent for each. |
||
27 | * @param int[]|int $exclude = array() - members in exclude array will not be |
||
28 | * processed for the topic with the same key. |
||
29 | * @param int[]|int $members_only = array() - are the only ones that will be sent the notification if they have it on. |
||
30 | * @param array $pbe = array() - array containing user_info if this is being run as a result of an email posting |
||
31 | */ |
||
32 | function sendNotifications($topics, $type, $exclude = [], $members_only = [], $pbe = []) |
||
33 | { |
||
34 | // Simply redirects to PostNotifications class sendNotifications method |
||
35 | 2 | // @todo I could find no use of $exclude in any calls to this function, that is why its missing :/ |
|
36 | (new PostNotifications())->sendNotifications($topics, $type, $members_only, $pbe); |
||
37 | 2 | } |
|
38 | |||
39 | /** |
||
40 | 2 | * Notifies members who have requested notification for new topics posted on a board of said posts. |
|
41 | 2 | * |
|
42 | * @param array $topicData |
||
43 | */ |
||
44 | 2 | function sendBoardNotifications(&$topicData) |
|
45 | { |
||
46 | // Redirects to PostNotifications class sendBoardNotifications method |
||
47 | (new PostNotifications())->sendBoardNotifications($topicData); |
||
48 | } |
||
49 | |||
50 | 2 | /** |
|
51 | * A special function for handling the hell which is sending approval notifications. |
||
52 | 2 | * |
|
53 | * @param array $topicData |
||
54 | */ |
||
55 | function sendApprovalNotifications(&$topicData) |
||
56 | 2 | { |
|
57 | 2 | (new PostNotifications())->sendApprovalNotifications($topicData); |
|
58 | } |
||
59 | |||
60 | /** |
||
61 | * This simple function gets a list of all administrators and emails them |
||
62 | * to let them know a new member has joined. |
||
63 | 2 | * Called by registerMember() function in subs/Members.subs.php. |
|
64 | 2 | * Email is sent to all groups that have the moderate_forum permission. |
|
65 | * The language set by each member is being used (if available). |
||
66 | * |
||
67 | 2 | * @param string $type types supported are 'approval', 'activation', and 'standard'. |
|
68 | 2 | * @param int $memberID |
|
69 | 2 | * @param string|null $member_name = null |
|
70 | * @uses the Login language file. |
||
71 | */ |
||
72 | function sendAdminNotifications($type, $memberID, $member_name = null) |
||
73 | { |
||
74 | global $modSettings, $language; |
||
75 | |||
76 | $db = database(); |
||
77 | |||
78 | // If the setting isn't enabled then just exit. |
||
79 | if (empty($modSettings['notify_new_registration'])) |
||
80 | { |
||
81 | 2 | return; |
|
82 | 2 | } |
|
83 | |||
84 | 2 | // Needed to notify admins, or anyone |
|
85 | require_once(SUBSDIR . '/Mail.subs.php'); |
||
86 | |||
87 | 2 | if ($member_name === null) |
|
88 | { |
||
89 | require_once(SUBSDIR . '/Members.subs.php'); |
||
90 | 2 | ||
91 | // Get the new user's name.... |
||
92 | $member_info = getBasicMemberData($memberID); |
||
93 | 2 | $member_name = $member_info['real_name']; |
|
94 | 2 | } |
|
95 | 2 | ||
96 | 2 | // All membergroups who can approve members. |
|
97 | 2 | $groups = []; |
|
98 | 2 | $db->fetchQuery(' |
|
99 | 2 | SELECT |
|
100 | 2 | id_group |
|
101 | 2 | FROM {db_prefix}permissions |
|
102 | 2 | WHERE permission = {string:moderate_forum} |
|
103 | AND add_deny = {int:add_deny} |
||
104 | 2 | AND id_group != {int:id_group}', |
|
105 | [ |
||
106 | 'add_deny' => 1, |
||
107 | 'id_group' => 0, |
||
108 | 2 | 'moderate_forum' => 'moderate_forum', |
|
109 | ] |
||
110 | 2 | )->fetch_callback( |
|
111 | function ($row) use (&$groups) { |
||
112 | 1 | $groups[] = $row['id_group']; |
|
113 | } |
||
114 | ); |
||
115 | |||
116 | // Add administrators too... |
||
117 | 2 | $groups[] = 1; |
|
118 | $groups = array_unique($groups); |
||
119 | |||
120 | // Get a list of all members who have ability to approve accounts - these are the people who we inform. |
||
121 | $current_language = User::$info->language; |
||
0 ignored issues
–
show
Bug
Best Practice
introduced
by
![]() |
|||
122 | 2 | $db->query('', ' |
|
123 | SELECT |
||
124 | id_member, lngfile, email_address |
||
125 | 2 | FROM {db_prefix}members |
|
126 | WHERE (id_group IN ({array_int:group_list}) OR FIND_IN_SET({raw:group_array_implode}, additional_groups) != 0) |
||
127 | AND notify_types != {int:notify_types} |
||
128 | ORDER BY lngfile', |
||
129 | [ |
||
130 | 'group_list' => $groups, |
||
131 | 2 | 'notify_types' => 4, |
|
132 | 2 | 'group_array_implode' => implode(', additional_groups) != 0 OR FIND_IN_SET(', $groups), |
|
133 | ] |
||
134 | 2 | )->fetch_callback( |
|
135 | function ($row) use ($type, $member_name, $memberID, $language) { |
||
136 | global $scripturl, $modSettings; |
||
137 | 2 | ||
138 | 2 | $replacements = [ |
|
139 | 'USERNAME' => $member_name, |
||
140 | 2 | 'PROFILELINK' => $scripturl . '?action=profile;u=' . $memberID |
|
141 | ]; |
||
142 | 1 | $emailtype = 'admin_notify'; |
|
143 | 2 | ||
144 | // If they need to be approved add more info... |
||
145 | if ($type === 'approval') |
||
146 | { |
||
147 | 2 | $replacements['APPROVALLINK'] = $scripturl . '?action=admin;area=viewmembers;sa=browse;type=approve'; |
|
148 | $emailtype .= '_approval'; |
||
149 | } |
||
150 | 2 | ||
151 | $emaildata = loadEmailTemplate($emailtype, $replacements, empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile']); |
||
152 | |||
153 | // And do the actual sending... |
||
154 | sendmail($row['email_address'], $emaildata['subject'], $emaildata['body'], null, null, false, 0); |
||
155 | } |
||
156 | ); |
||
157 | |||
158 | if (isset($current_language) && $current_language !== User::$info->language) |
||
159 | { |
||
160 | $lang_loader = new Loader(null, $txt, database()); |
||
161 | $lang_loader->load('Login', false); |
||
162 | } |
||
163 | } |
||
164 | |||
165 | /** |
||
166 | * Checks if a user has the correct access to get notifications |
||
167 | * - validates they have proper group access to a board |
||
168 | * - if using the maillist, checks if they should get a reply-able message |
||
169 | * - not muted |
||
170 | * - has postby_email permission on the board |
||
171 | * |
||
172 | * Returns false if they do not have the proper group access to a board |
||
173 | * Sets email_perm to false if they should not get a reply-able message |
||
174 | * |
||
175 | * @param array $row |
||
176 | * @param bool $maillist |
||
177 | * @param bool $email_perm |
||
178 | * |
||
179 | * @return bool |
||
180 | */ |
||
181 | function validateNotificationAccess($row, $maillist, &$email_perm = true) |
||
182 | { |
||
183 | global $modSettings; |
||
184 | |||
185 | static $board_profile = []; |
||
186 | |||
187 | $member_in_groups = array_merge([$row['id_group'], $row['id_post_group']], (empty($row['additional_groups']) ? [] : explode(',', $row['additional_groups']))); |
||
188 | $board_allowed_groups = explode(',', $row['member_groups']); |
||
189 | |||
190 | // Standardize the data |
||
191 | $member_in_groups = array_map('intval', $member_in_groups); |
||
192 | $board_allowed_groups = array_map('intval', $board_allowed_groups); |
||
193 | |||
194 | // No need to check for you ;) |
||
195 | if (!in_array(1, $member_in_groups, true)) |
||
196 | { |
||
197 | $email_perm = true; |
||
198 | |||
199 | return true; |
||
200 | } |
||
201 | |||
202 | // They do have access to this board? |
||
203 | if (count(array_intersect($member_in_groups, $board_allowed_groups)) === 0) |
||
204 | { |
||
205 | $email_perm = false; |
||
206 | |||
207 | return false; |
||
208 | } |
||
209 | |||
210 | // If using maillist, see if they should get a reply-able message |
||
211 | if ($email_perm && $maillist) |
||
212 | { |
||
213 | // Perhaps they don't require or deserve a security key in the message |
||
214 | if (!empty($modSettings['postmod_active']) |
||
215 | && !empty($modSettings['warning_mute']) && $modSettings['warning_mute'] <= $row['warning']) |
||
216 | { |
||
217 | $email_perm = false; |
||
218 | |||
219 | return false; |
||
220 | } |
||
221 | |||
222 | if (!isset($board_profile[$row['id_board']])) |
||
223 | { |
||
224 | require_once(SUBSDIR . '/Members.subs.php'); |
||
225 | $board_profile[$row['id_board']] = groupsAllowedTo('postby_email', $row['id_board']); |
||
226 | } |
||
227 | |||
228 | // In a group that has email posting permissions on this board |
||
229 | if (count(array_intersect($board_profile[$row['id_board']]['allowed'], $member_in_groups)) === 0) |
||
230 | { |
||
231 | $email_perm = false; |
||
232 | |||
233 | return false; |
||
234 | } |
||
235 | |||
236 | // And not specifically denied? |
||
237 | if ($email_perm && !empty($modSettings['permission_enable_deny']) |
||
238 | && count(array_intersect($member_in_groups, $board_profile[$row['id_board']]['denied'])) !== 0) |
||
239 | { |
||
240 | $email_perm = false; |
||
241 | } |
||
242 | } |
||
243 | |||
244 | return $email_perm; |
||
245 | } |
||
246 | |||
247 | /** |
||
248 | * Returns the enabled notifications from the modSettings. |
||
249 | * |
||
250 | * @return array |
||
251 | * @global array $modSettings |
||
252 | * |
||
253 | */ |
||
254 | function getEnabledNotifications() |
||
255 | { |
||
256 | global $modSettings; |
||
257 | |||
258 | if (empty($modSettings['enabled_mentions'])) |
||
259 | { |
||
260 | return []; |
||
261 | } |
||
262 | |||
263 | $enabled = array_filter(array_unique(explode(',', $modSettings['enabled_mentions']))); |
||
264 | sort($enabled); |
||
265 | |||
266 | return $enabled; |
||
267 | } |
||
268 | |||
269 | /** |
||
270 | * Queries the database for notification preferences of a set of members. |
||
271 | * |
||
272 | * |
||
273 | * @param string[]|string $notification_types |
||
274 | * @param int[]|int $members |
||
275 | * |
||
276 | * @return array |
||
277 | */ |
||
278 | function getUsersNotificationsPreferences($notification_types, $members) |
||
279 | { |
||
280 | $db = database(); |
||
281 | |||
282 | $notification_types = (array) $notification_types; |
||
283 | $query_members = (array) $members; |
||
284 | $defaults = []; |
||
285 | foreach (getConfiguredNotificationMethods('*') as $notification => $methods) |
||
286 | { |
||
287 | 2 | $return = []; |
|
288 | foreach ($methods as $k => $level) |
||
289 | { |
||
290 | if ($level == Notifications::DEFAULT_LEVEL) |
||
291 | { |
||
292 | $return[] = $k; |
||
293 | } |
||
294 | } |
||
295 | $defaults[$notification] = $return; |
||
296 | } |
||
297 | |||
298 | $results = []; |
||
299 | $db->fetchQuery(' |
||
300 | SELECT |
||
301 | id_member, notification_type, mention_type |
||
302 | 2 | FROM {db_prefix}notifications_pref |
|
303 | WHERE id_member IN ({array_int:members_to}) |
||
304 | AND mention_type IN ({array_string:mention_types})', |
||
305 | 2 | [ |
|
306 | 2 | 'members_to' => $query_members, |
|
307 | 2 | 'mention_types' => $notification_types, |
|
308 | 2 | ] |
|
309 | 2 | )->fetch_callback( |
|
310 | 2 | function ($row) use (&$results) { |
|
311 | if (!isset($results[$row['id_member']])) |
||
312 | { |
||
313 | 2 | $results[$row['id_member']] = []; |
|
314 | } |
||
315 | |||
316 | $results[$row['id_member']][$row['mention_type']] = json_decode($row['notification_type']); |
||
317 | } |
||
318 | ); |
||
319 | |||
320 | // Set the defaults |
||
321 | foreach ($query_members as $member) |
||
322 | { |
||
323 | foreach ($notification_types as $type) |
||
324 | { |
||
325 | if (empty($results[$member]) && !empty($defaults[$type])) |
||
326 | { |
||
327 | if (!isset($results[$member])) |
||
328 | { |
||
329 | $results[$member] = []; |
||
330 | } |
||
331 | |||
332 | if (!isset($results[$member][$type])) |
||
333 | { |
||
334 | $results[$member][$type] = []; |
||
335 | } |
||
336 | |||
337 | $results[$member][$type] = $defaults[$type]; |
||
338 | } |
||
339 | } |
||
340 | } |
||
341 | |||
342 | return $results; |
||
343 | } |
||
344 | |||
345 | /** |
||
346 | * Saves into the database the notification preferences of a certain member. |
||
347 | * |
||
348 | * @param int $member The member id |
||
349 | * @param array $notification_data The array of notifications ('type' => ['level']) |
||
350 | */ |
||
351 | function saveUserNotificationsPreferences($member, $notification_data) |
||
352 | { |
||
353 | $db = database(); |
||
354 | |||
355 | $inserts = []; |
||
356 | |||
357 | // First drop the existing settings |
||
358 | $db->query('', ' |
||
359 | DELETE FROM {db_prefix}notifications_pref |
||
360 | WHERE id_member = {int:member} |
||
361 | AND mention_type IN ({array_string:mention_types})', |
||
362 | [ |
||
363 | 'member' => $member, |
||
364 | 'mention_types' => array_keys($notification_data), |
||
365 | ] |
||
366 | ); |
||
367 | |||
368 | foreach ($notification_data as $type => $level) |
||
369 | { |
||
370 | // used to skip values that are here only to remove the default |
||
371 | if (empty($level)) |
||
372 | { |
||
373 | continue; |
||
374 | } |
||
375 | |||
376 | // If they have any site notifications enabled, set a flag to request Push.Permissions |
||
377 | if (in_array('notification', $level)) |
||
378 | { |
||
379 | $_SESSION['push_enabled'] = true; |
||
380 | } |
||
381 | |||
382 | $inserts[] = [ |
||
383 | $member, |
||
384 | $type, |
||
385 | json_encode($level), |
||
386 | ]; |
||
387 | } |
||
388 | |||
389 | if (empty($inserts)) |
||
390 | { |
||
391 | return; |
||
392 | } |
||
393 | |||
394 | 2 | $db->insert('', |
|
395 | '{db_prefix}notifications_pref', |
||
396 | 2 | [ |
|
397 | 'id_member' => 'int', |
||
398 | 'mention_type' => 'string-12', |
||
399 | 'notification_type' => 'string', |
||
400 | ], |
||
401 | $inserts, |
||
402 | 2 | ['id_member', 'mention_type'] |
|
403 | ); |
||
404 | } |
||
405 | |||
406 | /** |
||
407 | * From the list of all possible notification methods available, only those |
||
408 | * enabled are returned. |
||
409 | * |
||
410 | * @param string[] $possible_methods The array of notifications ('type' => 'level') |
||
411 | * @param string $type The type of notification (mentionmem, likemsg, etc.) |
||
412 | * |
||
413 | * @return array |
||
414 | */ |
||
415 | function filterNotificationMethods($possible_methods, $type) |
||
416 | { |
||
417 | $unserialized = getConfiguredNotificationMethods($type); |
||
418 | |||
419 | 2 | if (empty($unserialized)) |
|
420 | { |
||
421 | return []; |
||
422 | } |
||
423 | |||
424 | $allowed = []; |
||
425 | foreach ($possible_methods as $class) |
||
426 | { |
||
427 | $class = strtolower($class); |
||
428 | if (!empty($unserialized[$class])) |
||
429 | { |
||
430 | $allowed[] = $class; |
||
431 | } |
||
432 | } |
||
433 | |||
434 | return $allowed; |
||
435 | } |
||
436 | |||
437 | /** |
||
438 | * Returns all the enabled methods of notification for a specific |
||
439 | * type of notification. |
||
440 | 2 | * |
|
441 | * @param string $type The type of notification (mentionmem, likemsg, etc.) |
||
442 | * |
||
443 | * @return array |
||
444 | */ |
||
445 | function getConfiguredNotificationMethods($type = '*') |
||
446 | { |
||
447 | global $modSettings; |
||
448 | |||
449 | $unserialized = Util::unserialize($modSettings['notification_methods']); |
||
450 | |||
451 | if (isset($unserialized[$type])) |
||
452 | { |
||
453 | return $unserialized[$type]; |
||
454 | 2 | } |
|
455 | |||
456 | 2 | if ($type === '*') |
|
457 | { |
||
458 | 2 | return $unserialized; |
|
459 | 2 | } |
|
460 | |||
461 | return []; |
||
462 | 2 | } |
|
463 | |||
464 | 2 | /** |
|
465 | * Creates a hash code using the notification details and our secret key |
||
466 | * |
||
467 | * - If no salt (secret key) has been set, creates a random one and saves it |
||
468 | 2 | * in modSettings for future use |
|
469 | * |
||
470 | * @param string $memID member id |
||
471 | 2 | * @param string $memEmail member email address |
|
472 | 2 | * @param string $memSalt member salt |
|
473 | * @param string $area area to unsubscribe |
||
474 | 2 | * @param string $extra area specific data such as topic id or liked msg |
|
475 | * @return string the token for the unsubscribe link |
||
476 | 2 | */ |
|
477 | function getNotifierToken($memID, $memEmail, $memSalt, $area, $extra) |
||
478 | { |
||
479 | global $modSettings; |
||
480 | |||
481 | // We need a site salt to keep things moving |
||
482 | if (empty($modSettings['unsubscribe_site_salt'])) |
||
483 | { |
||
484 | $tokenizer = new TokenHash(); |
||
485 | 2 | ||
486 | // Extra digits of salt |
||
487 | $unsubscribe_site_salt = $tokenizer->generate_hash(22); |
||
488 | updateSettings(['unsubscribe_site_salt' => $unsubscribe_site_salt]); |
||
489 | 2 | } |
|
490 | 2 | ||
491 | // Generate a code suitable for Blowfish crypt. |
||
492 | $blowfish_salt = '$2a$07$' . $memSalt . $modSettings['unsubscribe_site_salt'] . '$'; |
||
493 | $now = time(); |
||
494 | $hash = crypt($area . $extra . $now . $memEmail . $memSalt, $blowfish_salt); |
||
495 | |||
496 | 2 | // Return just the hash, drop the salt |
|
497 | 2 | return urlencode(implode('_', |
|
498 | [ |
||
499 | $memID, |
||
500 | 2 | substr($hash, 28), |
|
501 | 2 | $area, |
|
502 | $extra, |
||
503 | 2 | $now |
|
504 | ] |
||
505 | 2 | )); |
|
506 | 2 | } |
|
507 | |||
508 | 2 | /** |
|
509 | * Validates a hash code using the notification details and our secret key |
||
510 | 1 | * |
|
511 | 2 | * - If no site salt (secret key) has been set, simply fails |
|
512 | * |
||
513 | * @param string $memEmail member email address |
||
514 | * @param string $memSalt member salt |
||
515 | 2 | * @param string $area data to validate = area + extra + time from link |
|
516 | * @param string $hash the hash from the link |
||
517 | * @return bool |
||
518 | */ |
||
519 | function validateNotifierToken($memEmail, $memSalt, $area, $hash) |
||
520 | { |
||
521 | global $modSettings; |
||
522 | |||
523 | if (empty($modSettings['unsubscribe_site_salt'])) |
||
524 | { |
||
525 | return false; |
||
526 | } |
||
527 | |||
528 | $blowfish_salt = '$2a$07$' . $memSalt . $modSettings['unsubscribe_site_salt']. '$'; |
||
529 | $expected = substr($blowfish_salt, 0, 28) . $hash; |
||
530 | 2 | $check = crypt($area . $memEmail . $memSalt, $blowfish_salt); |
|
531 | 2 | ||
532 | 2 | // Basic safe compare |
|
533 | 2 | return hash_equals($expected, $check); |
|
534 | 2 | } |
|
535 | |||
536 | /** |
||
537 | * Fetches a set of data for a topic that will then be used in creating/building notification emails. |
||
538 | 2 | * |
|
539 | * @param int[] $topics |
||
540 | * @param string $type |
||
541 | * @return array[] A board array and the topic info array. Board array used to search for board subscriptions. |
||
542 | */ |
||
543 | function getTopicInfos($topics, $type) |
||
544 | { |
||
545 | $db = database(); |
||
546 | |||
547 | $topicData = []; |
||
548 | $boards_index = []; |
||
549 | |||
550 | $db->fetchQuery(' |
||
551 | SELECT |
||
552 | mf.subject, ml.body, ml.id_member, t.id_last_msg, t.id_topic, t.id_board, t.id_member_started, |
||
553 | mem.signature, COALESCE(mem.real_name, ml.poster_name) AS poster_name, COUNT(a.id_attach) as num_attach |
||
554 | FROM {db_prefix}topics AS t |
||
555 | INNER JOIN {db_prefix}messages AS mf ON (mf.id_msg = t.id_first_msg) |
||
556 | INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg) |
||
557 | LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = ml.id_member) |
||
558 | LEFT JOIN {db_prefix}attachments AS a ON(a.attachment_type = {int:attachment_type} AND a.id_msg = t.id_last_msg) |
||
559 | WHERE t.id_topic IN ({array_int:topic_list}) |
||
560 | GROUP BY 1, 2, 3, 4, 5, 6, 7, 8, 9', |
||
561 | [ |
||
562 | 'topic_list' => $topics, |
||
563 | 'attachment_type' => 0, |
||
564 | ] |
||
565 | )->fetch_callback( |
||
566 | function ($row) use (&$topicData, &$boards_index, $type) { |
||
567 | // all the boards for these topics, used to find all the members to be notified |
||
568 | $boards_index[] = $row['id_board']; |
||
569 | |||
570 | // And the information we are going to tell them about |
||
571 | $topicData[$row['id_topic']] = [ |
||
572 | 'subject' => $row['subject'], |
||
573 | 'body' => $row['body'], |
||
574 | 'last_id' => (int) $row['id_last_msg'], |
||
575 | 'topic' => (int) $row['id_topic'], |
||
576 | 'board' => (int) $row['id_board'], |
||
577 | 'id_member_started' => (int) $row['id_member_started'], |
||
578 | 'name' => $type === 'reply' ? $row['poster_name'] : User::$info->name, |
||
0 ignored issues
–
show
The property
name does not exist on ElkArte\Helper\ValuesContainer . Since you implemented __get , consider adding a @property annotation.
![]() |
|||
579 | 'exclude' => '', |
||
580 | 'signature' => $row['signature'], |
||
581 | 'attachments' => (int) $row['num_attach'], |
||
582 | ]; |
||
583 | } |
||
584 | ); |
||
585 | |||
586 | return [$boards_index, $topicData]; |
||
587 | } |
||
588 | |||
589 | /** |
||
590 | * Keeps the log_digest up to date for members who want weekly/daily updates |
||
591 | * |
||
592 | * @param array $digest_insert |
||
593 | * @return void |
||
594 | */ |
||
595 | function insertLogDigestQueue($digest_insert) |
||
596 | { |
||
597 | $db = database(); |
||
598 | |||
599 | $db->insert('', |
||
600 | '{db_prefix}log_digest', |
||
601 | [ |
||
602 | 'id_topic' => 'int', 'id_msg' => 'int', 'note_type' => 'string', 'exclude' => 'int', |
||
603 | ], |
||
604 | $digest_insert, |
||
605 | [] |
||
606 | ); |
||
607 | } |
||
608 | |||
609 | /** |
||
610 | * Find the members with *board* notifications on. |
||
611 | * |
||
612 | * What it does: |
||
613 | * Finds board notifications that meet: |
||
614 | * - Member has watch notifications on for the board |
||
615 | 2 | * - The notification type of reply and/or moderation notices |
|
616 | * - Notification regularity of instantly or first unread |
||
617 | 2 | * - Member is activated |
|
618 | * - Member has access to the board where the topic resides |
||
619 | * |
||
620 | 2 | * @param int $user_id the id of the poster as they do not get a notification of their own post |
|
621 | * @param int[] $boards_index list of boards to check |
||
622 | * @param string $type type of activity, like reply or lock |
||
623 | * @param int|int[] $members_only returns data only for a list of members |
||
624 | * @param string $regularity type of notification 'email' or 'onsite' |
||
625 | * @return array |
||
626 | */ |
||
627 | 2 | function fetchBoardNotifications($user_id, $boards_index, $type, $members_only, $regularity = 'email') |
|
628 | 2 | { |
|
629 | 2 | $db = database(); |
|
630 | |||
631 | $boardNotifyData = []; |
||
632 | 2 | ||
633 | $notify_types = $type === 'reply' ? 'mem.notify_types < 4' : 'mem.notify_types < 3'; |
||
634 | $notify_regularity = $regularity === 'email' ? 'mem.notify_regularity < 2' : 'mem.notify_regularity = 4'; |
||
635 | |||
636 | // Find the members (excluding the poster) that have board notification enabled. |
||
637 | $db->fetchQuery(' |
||
638 | SELECT |
||
639 | mem.id_member, mem.email_address, mem.notify_regularity, mem.notify_types, mem.notify_send_body, |
||
640 | mem.lngfile, mem.warning, mem.id_group, mem.additional_groups, mem.id_post_group, mem.password_salt, |
||
641 | b.member_groups, b.name, b.id_profile, |
||
642 | ln.id_board, ln.sent |
||
643 | FROM {db_prefix}log_notify AS ln |
||
644 | INNER JOIN {db_prefix}boards AS b ON (b.id_board = ln.id_board) |
||
645 | INNER JOIN {db_prefix}members AS mem ON (mem.id_member = ln.id_member) |
||
646 | WHERE ln.id_board IN ({array_int:board_list}) |
||
647 | AND {raw:notify_types} |
||
648 | AND {raw:notify_regularity} |
||
649 | AND mem.is_activated = {int:is_activated} |
||
650 | AND ln.id_member != {int:current_member}' . |
||
651 | (empty($members_only) ? '' : ' AND ln.id_member IN ({array_int:members_only})') . ' |
||
652 | ORDER BY mem.lngfile', |
||
653 | [ |
||
654 | 'current_member' => $user_id, |
||
655 | 'board_list' => $boards_index, |
||
656 | 'notify_types' => $notify_types, |
||
657 | 'notify_regularity' => $notify_regularity, |
||
658 | 'is_activated' => 1, |
||
659 | 'members_only' => is_array($members_only) ? $members_only : [$members_only], |
||
660 | ] |
||
661 | )->fetch_callback( |
||
662 | function ($row) use (&$boardNotifyData) { |
||
663 | // The board subscription information for the member |
||
664 | $clean = [ |
||
665 | 'id_member' => (int) $row['id_member'], |
||
666 | 'email_address' => $row['email_address'], |
||
667 | 'notify_regularity' => (int) $row['notify_regularity'], |
||
668 | 'notify_types' => (int) $row['notify_types'], |
||
669 | 'notify_send_body' => (int) $row['notify_send_body'], |
||
670 | 'lngfile' => $row['lngfile'], |
||
671 | 'warning' => $row['warning'], |
||
672 | 'id_group' => (int) $row['id_group'], |
||
673 | 'additional_groups' => $row['additional_groups'], |
||
674 | 'id_post_group' => (int) $row['id_post_group'], |
||
675 | 'password_salt' => $row['password_salt'], |
||
676 | 'member_groups' => $row['member_groups'], |
||
677 | 'board_name' => $row['name'], |
||
678 | 'id_profile_board' => (int) $row['id_profile'], |
||
679 | 'id_board' => (int) $row['id_board'], |
||
680 | 'sent' => (int) $row['sent'], |
||
681 | ]; |
||
682 | |||
683 | if (validateNotificationAccess($clean, false)) |
||
684 | { |
||
685 | $boardNotifyData[] = $clean; |
||
686 | } |
||
687 | } |
||
688 | ); |
||
689 | |||
690 | return $boardNotifyData; |
||
691 | } |
||
692 | |||
693 | /** |
||
694 | * Finds members who have topic notification on for a topic where the type is one that they want to be |
||
695 | * kept in the loop. |
||
696 | * |
||
697 | * What it does: |
||
698 | * Finds notifications that meet: |
||
699 | * - Member has watch notifications on for these topics |
||
700 | * - Member has set notification type of reply and/or moderation notices |
||
701 | * - ALL_MESSAGES = 1; |
||
702 | * - MODERATION_ONLY_IF_STARTED = 2; |
||
703 | * - ONLY_REPLIES = 3; |
||
704 | * - NOTHING_AT_ALL = 4; |
||
705 | * - Member has set notification regularity to 'email' (instantly or first unread) or 'onsite' for onsite |
||
706 | * - NOTHING = 99; |
||
707 | * - EMAIL INSTANTLY = 0; |
||
708 | * - EMAIL FIRST_UNREAD_MSG = 1; |
||
709 | * - DAILY_DIGEST = 2; |
||
710 | * - WEEKLY_DIGEST = 3; |
||
711 | * - ONSITE FIRST_UNREAD_MSG = 4; |
||
712 | * - Member is activated |
||
713 | * - Member has access to the board where the topic resides |
||
714 | * |
||
715 | * @param int $user_id some goon, e.g. the originator of the action who **WILL NOT** get a notification |
||
716 | * @param int[] $topics array of topic id's that have updates |
||
717 | * @param string $type type of notification like reply, lock, sticky |
||
718 | * @param int|int[] $members_only if not empty, only send notices to these members |
||
719 | * @param string $regularity type of notification 'email' or 'onsite' |
||
720 | * @return array |
||
721 | */ |
||
722 | function fetchTopicNotifications($user_id, $topics, $type, $members_only, $regularity = 'email') |
||
723 | { |
||
724 | $db = database(); |
||
725 | |||
726 | $topicNotifyData = []; |
||
727 | |||
728 | $notify_types = $type === 'reply' ? 'mem.notify_types < 4' : 'mem.notify_types < 3'; |
||
729 | $notify_regularity = $regularity === 'email' ? 'mem.notify_regularity < 2' : 'mem.notify_regularity = 4'; |
||
730 | |||
731 | // Find the members with notification on for this topic. |
||
732 | $db->fetchQuery(' |
||
733 | SELECT |
||
734 | mem.id_member, mem.email_address, mem.notify_regularity, mem.notify_types, mem.notify_send_body, mem.notify_from, |
||
735 | mem.lngfile, mem.warning, mem.id_group, mem.additional_groups, mem.id_post_group, mem.password_salt, |
||
736 | t.id_member_started, t.id_last_msg, |
||
737 | b.member_groups, b.name, b.id_profile, b.id_board, |
||
738 | ln.id_topic, ln.sent |
||
739 | FROM {db_prefix}log_notify AS ln |
||
740 | INNER JOIN {db_prefix}members AS mem ON (mem.id_member = ln.id_member) |
||
741 | INNER JOIN {db_prefix}topics AS t ON (t.id_topic = ln.id_topic) |
||
742 | INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) |
||
743 | WHERE ln.id_topic IN ({array_int:topic_list}) |
||
744 | AND {raw:notify_types} |
||
745 | AND {raw:notify_regularity} |
||
746 | AND mem.is_activated = {int:is_activated} |
||
747 | AND ln.id_member != {int:current_member}' . |
||
748 | (empty($members_only) ? '' : ' AND ln.id_member IN ({array_int:members_only})') . ' |
||
749 | ORDER BY mem.lngfile', |
||
750 | [ |
||
751 | 'current_member' => $user_id, |
||
752 | 'topic_list' => $topics, |
||
753 | 'notify_types' => $notify_types, |
||
754 | 'notify_regularity' => $notify_regularity, |
||
755 | 'is_activated' => 1, |
||
756 | 'members_only' => is_array($members_only) ? $members_only : [$members_only], |
||
757 | ] |
||
758 | )->fetch_callback( |
||
759 | function ($row) use (&$topicNotifyData) { |
||
760 | // The topic subscription information for the member |
||
761 | $clean = [ |
||
762 | 'id_member' => (int) $row['id_member'], |
||
763 | 'email_address' => $row['email_address'], |
||
764 | 'notify_regularity' => (int) $row['notify_regularity'], |
||
765 | 'notify_types' => (int) $row['notify_types'], |
||
766 | 'notify_send_body' => (int) $row['notify_send_body'], |
||
767 | 'notify_from' => (int) $row['notify_from'], |
||
768 | 'lngfile' => $row['lngfile'], |
||
769 | 'warning' => $row['warning'], |
||
770 | 'id_group' => (int) $row['id_group'], |
||
771 | 'additional_groups' => $row['additional_groups'], |
||
772 | 'id_post_group' => (int) $row['id_post_group'], |
||
773 | 'password_salt' => $row['password_salt'], |
||
774 | 'id_member_started' => (int) $row['id_member_started'], |
||
775 | 'member_groups' => $row['member_groups'], |
||
776 | 'board_name' => $row['name'], |
||
777 | 'id_profile_board' => (int) $row['id_profile'], |
||
778 | 'id_board' => (int) $row['id_board'], |
||
779 | 'id_topic' => (int) $row['id_topic'], |
||
780 | 'last_id' => (int) $row['id_last_msg'], |
||
781 | 'sent' => (int) $row['sent'], |
||
782 | ]; |
||
783 | |||
784 | if (validateNotificationAccess($clean, false)) |
||
785 | { |
||
786 | $topicNotifyData[$clean['id_topic']] = $clean; |
||
787 | } |
||
788 | } |
||
789 | ); |
||
790 | |||
791 | return $topicNotifyData; |
||
792 | } |
||
793 | |||
794 | /** |
||
795 | * Updates the log_notify table for all members that have received notifications |
||
796 | * |
||
797 | * @param int $user_id |
||
798 | * @param array $data |
||
799 | * @param boolean $board if true updates a boards log notify, else topic |
||
800 | * @return void |
||
801 | */ |
||
802 | function updateLogNotify($user_id, $data, $board = false) |
||
803 | { |
||
804 | $db = database(); |
||
805 | 2 | ||
806 | $db->query('', ' |
||
807 | 2 | UPDATE {db_prefix}log_notify |
|
808 | SET |
||
809 | sent = {int:is_sent} |
||
810 | 2 | WHERE ' . ($board ? 'id_board' : 'id_topic') . ' IN ({array_int:data_list}) |
|
811 | AND id_member != {int:current_member}', |
||
812 | 2 | [ |
|
813 | 'current_member' => $user_id, |
||
814 | 'data_list' => $data, |
||
815 | 'is_sent' => 1, |
||
816 | ] |
||
817 | ); |
||
818 | } |
||
819 | |||
820 | /** |
||
821 | * Finds members who have topic notification on for a topic where the type is one that they want to be |
||
822 | * kept in the loop. |
||
823 | * |
||
824 | * What it does: |
||
825 | * Finds notifications that meet: |
||
826 | * - Members has watch notifications enabled for these topics |
||
827 | * - The notification type is not none/off (all, replies+moderation, moderation only) |
||
828 | * - Notification regularity of instantly or first unread |
||
829 | * - Member is activated |
||
830 | * - Member has access to the board where the topic resides |
||
831 | * |
||
832 | * @param int[] $topics array of topic id's that have updates |
||
833 | * @return array |
||
834 | */ |
||
835 | function fetchApprovalNotifications($topics) |
||
836 | { |
||
837 | $db = database(); |
||
838 | |||
839 | $approvalNotifyData = []; |
||
840 | |||
841 | // Find everyone who needs to know about this. |
||
842 | $db->fetchQuery(' |
||
843 | SELECT |
||
844 | DISTINCT mem.id_member, mem.email_address, mem.notify_regularity, mem.notify_types, mem.notify_send_body, mem.notify_from, |
||
845 | mem.lngfile, mem.warning, mem.id_group, mem.additional_groups, mem.id_post_group, mem.password_salt, |
||
846 | t.id_member_started, |
||
847 | b.member_groups, b.name, b.id_profile, b.id_board, |
||
848 | ln.id_topic, ln.sent |
||
849 | FROM {db_prefix}log_notify AS ln |
||
850 | INNER JOIN {db_prefix}members AS mem ON (mem.id_member = ln.id_member) |
||
851 | INNER JOIN {db_prefix}topics AS t ON (t.id_topic = ln.id_topic) |
||
852 | INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) |
||
853 | WHERE ln.id_topic IN ({array_int:topic_list}) |
||
854 | AND mem.is_activated = {int:is_activated} |
||
855 | AND mem.notify_types < {int:notify_types} |
||
856 | AND mem.notify_regularity < {int:notify_regularity} |
||
857 | ORDER BY mem.lngfile', |
||
858 | [ |
||
859 | 'topic_list' => $topics, |
||
860 | 'is_activated' => 1, |
||
861 | 'notify_types' => 4, |
||
862 | 'notify_regularity' => 2, |
||
863 | ] |
||
864 | )->fetch_callback( |
||
865 | function ($row) use (&$approvalNotifyData) { |
||
866 | $clean = [ |
||
867 | 'id_member' => (int) $row['id_member'], |
||
868 | 'email_address' => $row['email_address'], |
||
869 | 'notify_regularity' => (int) $row['notify_regularity'], |
||
870 | 'notify_types' => (int) $row['notify_types'], |
||
871 | 'notify_send_body' => (int) $row['notify_send_body'], |
||
872 | 'notify_from' => (int) $row['notify_from'], |
||
873 | 'lngfile' => $row['lngfile'], |
||
874 | 'warning' => $row['warning'], |
||
875 | 'id_group' => (int) $row['id_group'], |
||
876 | 'additional_groups' => $row['additional_groups'], |
||
877 | 'id_post_group' => (int) $row['id_post_group'], |
||
878 | 'password_salt' => $row['password_salt'], |
||
879 | 'id_member_started' => (int) $row['id_member_started'], |
||
880 | 'member_groups' => $row['member_groups'], |
||
881 | 'board_name' => $row['name'], |
||
882 | 'id_profile_board' => (int) $row['id_profile'], |
||
883 | 'id_board' => (int) $row['id_board'], |
||
884 | 'id_topic' => (int) $row['id_topic'], |
||
885 | 'sent' => (int) $row['sent'], |
||
886 | ]; |
||
887 | |||
888 | if (validateNotificationAccess($clean, false)) |
||
889 | { |
||
890 | $approvalNotifyData[] = $clean; |
||
891 | } |
||
892 | } |
||
893 | ); |
||
894 | |||
895 | return $approvalNotifyData; |
||
896 | } |
||
897 |