From 18e1c780ea01702f3518f26de4c48a10becb35e7 Mon Sep 17 00:00:00 2001 From: Spuds Date: Fri, 12 Apr 2024 19:06:05 -0500 Subject: [PATCH 1/4] ! shift useful method to subs for easy re-use --- .../ElkArte/AdminController/CoreFeatures.php | 3 +- sources/ElkArte/Controller/Mentions.php | 30 +++++++------------ .../Modules/Mentions/AbstractMentions.php | 3 +- sources/subs/Notification.subs.php | 23 ++++++++++++++ 4 files changed, 37 insertions(+), 22 deletions(-) diff --git a/sources/ElkArte/AdminController/CoreFeatures.php b/sources/ElkArte/AdminController/CoreFeatures.php index 83802550c4..caa7fc81be 100644 --- a/sources/ElkArte/AdminController/CoreFeatures.php +++ b/sources/ElkArte/AdminController/CoreFeatures.php @@ -188,11 +188,12 @@ public function settings() global $modSettings; require_once(SUBSDIR . '/Mentions.subs.php'); + require_once(SUBSDIR . 'Notification.subs.php'); // Makes all the like/rlike mentions invisible (or visible) toggleMentionsVisibility('likemsg', !empty($value)); toggleMentionsVisibility('rlikemsg', !empty($value)); - $current = empty($modSettings['enabled_mentions']) ? array() : explode(',', $modSettings['enabled_mentions']); + $current = getEnabledNotifications(); if (!empty($value)) { return array('enabled_mentions' => implode(',', array_unique(array_merge($current, array('likemsg', 'rlikemsg'))))); diff --git a/sources/ElkArte/Controller/Mentions.php b/sources/ElkArte/Controller/Mentions.php index 31c1e134d4..ff34fd49ce 100644 --- a/sources/ElkArte/Controller/Mentions.php +++ b/sources/ElkArte/Controller/Mentions.php @@ -19,6 +19,7 @@ use ElkArte\Helper\DataValidator; use ElkArte\Languages\Txt; use ElkArte\Mentions\Mentioning; +use ElkArte\User; /** * as liking a post, adding a buddy, @ calling a member in a post @@ -82,24 +83,7 @@ public function pre_dispatch() require_once(SUBSDIR . '/Mentions.subs.php'); - $this->_known_mentions = $this->_findMentionTypes(); - } - - /** - * Determines the enabled mention types. - * - * @return string[] - */ - protected function _findMentionTypes() - { - global $modSettings; - - if (empty($modSettings['enabled_mentions'])) - { - return []; - } - - return array_filter(array_unique(explode(',', $modSettings['enabled_mentions']))); + $this->_known_mentions = getMentionTypes(User::$info->id, 'system'); } /** @@ -311,6 +295,8 @@ public function action_list() ], ]; + // Build the available mention tabs + $this->_known_mentions = $this->_all === true ? getMentionTypes(User::$info->id, 'system') : getMentionTypes(User::$info->id); foreach ($this->_known_mentions as $mention) { $list_options['list_menu']['links'][] = [ @@ -338,7 +324,7 @@ public function action_list() } /** - * Builds the link back so you return to the right list of mentions + * Builds the link back, so you return to the right list of mentions */ protected function _buildUrl() { @@ -468,7 +454,11 @@ public function list_loadMentions($start, $limit, $sort, $all, $type) $start += $limit; } - countUserMentions(); + // Trigger an unread count update when needed + if ($all !== false) + { + countUserMentions(); + } return $mentions; } diff --git a/sources/ElkArte/Modules/Mentions/AbstractMentions.php b/sources/ElkArte/Modules/Mentions/AbstractMentions.php index dafe914085..3e92407e88 100644 --- a/sources/ElkArte/Modules/Mentions/AbstractMentions.php +++ b/sources/ElkArte/Modules/Mentions/AbstractMentions.php @@ -37,7 +37,8 @@ protected static function registerHooks($action, EventManager $eventsManager) if (!empty($modSettings['mentions_enabled'])) { - $mentions = explode(',', $modSettings['enabled_mentions']); + require_once(SUBSDIR . 'Notification.subs.php'); + $mentions = getEnabledNotifications(); foreach ($mentions as $mention) { diff --git a/sources/subs/Notification.subs.php b/sources/subs/Notification.subs.php index 1b4f1dd545..ea9d054c34 100644 --- a/sources/subs/Notification.subs.php +++ b/sources/subs/Notification.subs.php @@ -244,9 +244,32 @@ function validateNotificationAccess($row, $maillist, &$email_perm = true) return $email_perm; } +/** + * Returns the enabled notifications from the modSettings. + * + * @return array + * @global array $modSettings + * + */ +function getEnabledNotifications() +{ + global $modSettings; + + if (empty($modSettings['enabled_mentions'])) + { + return []; + } + + $enabled = array_filter(array_unique(explode(',', $modSettings['enabled_mentions']))); + sort($enabled); + + return $enabled; +} + /** * Queries the database for notification preferences of a set of members. * + * * @param string[]|string $notification_types * @param int[]|int $members * From f7011f12d142b3e34c7db6cbcbda50088e824b91 Mon Sep 17 00:00:00 2001 From: Spuds Date: Fri, 12 Apr 2024 19:10:26 -0500 Subject: [PATCH 2/4] ! only show unread mention tabs for areas the user has enabled --- .../MentionType/AbstractEventMessage.php | 2 +- sources/ElkArte/Mentions/Mentioning.php | 2 +- sources/subs/Members.subs.php | 4 +- sources/subs/Mentions.subs.php | 116 +++++++++++++----- sources/subs/Profile.subs.php | 6 +- 5 files changed, 95 insertions(+), 35 deletions(-) diff --git a/sources/ElkArte/Mentions/MentionType/AbstractEventMessage.php b/sources/ElkArte/Mentions/MentionType/AbstractEventMessage.php index 5de0daaf4a..8b07dfec48 100644 --- a/sources/ElkArte/Mentions/MentionType/AbstractEventMessage.php +++ b/sources/ElkArte/Mentions/MentionType/AbstractEventMessage.php @@ -94,7 +94,7 @@ protected function _replaceMsg($row) global $txt, $scripturl, $context; $boardTree = new BoardsTree(database()); - $board = $boardTree->getBoardById((int) $row['id_board']); + $board = !empty($row['id_board']) ? $boardTree->getBoardById((int) $row['id_board']) : []; return str_replace( [ diff --git a/sources/ElkArte/Mentions/Mentioning.php b/sources/ElkArte/Mentions/Mentioning.php index 674ee43151..fd607fbc6a 100644 --- a/sources/ElkArte/Mentions/Mentioning.php +++ b/sources/ElkArte/Mentions/Mentioning.php @@ -271,7 +271,7 @@ protected function _getAccessible($mention_ids, $action) 'mark' => 'trim', ]; $validation = [ - 'id_mention' => 'validate_ownmention', + 'id_mention' => 'validate_own_mention', 'mark' => 'contains[read,unread,delete,readall]', ]; diff --git a/sources/subs/Members.subs.php b/sources/subs/Members.subs.php index 7fa6dcb321..77435a154d 100644 --- a/sources/subs/Members.subs.php +++ b/sources/subs/Members.subs.php @@ -629,8 +629,8 @@ function registerMember(&$regOptions, $ErrorContext = 'register') 'password_salt' => $tokenizer->generate_hash(10), 'posts' => 0, 'date_registered' => !empty($regOptions['time']) ? $regOptions['time'] : time(), - 'member_ip' => $regOptions['interface'] == 'admin' ? '127.0.0.1' : $regOptions['ip'], - 'member_ip2' => $regOptions['interface'] == 'admin' ? '127.0.0.1' : $regOptions['ip2'], + 'member_ip' => $regOptions['interface'] === 'admin' ? '127.0.0.1' : $regOptions['ip'], + 'member_ip2' => $regOptions['interface'] === 'admin' ? '127.0.0.1' : $regOptions['ip2'], 'validation_code' => substr(hash('sha256', $validation_code), 0, 10), 'real_name' => !empty($regOptions['real_name']) ? $regOptions['real_name'] : $regOptions['username'], 'pm_email_notify' => 1, diff --git a/sources/subs/Mentions.subs.php b/sources/subs/Mentions.subs.php index bf19b471eb..b84af9815a 100644 --- a/sources/subs/Mentions.subs.php +++ b/sources/subs/Mentions.subs.php @@ -11,19 +11,17 @@ * */ +use ElkArte\MembersList; use ElkArte\User; /** - * Count the mentions of the current user - * callback for createList in action_list of \ElkArte\Controller\Mentions + * Counts the number of mentions for a user. * - * @param bool $all : if true counts all the mentions, otherwise only the unread - * @param string[]|string $type : the type of the mention can be a string or an array of strings. - * @param int|null $id_member : the id of the member the counts are for, defaults to user_info['id'] - * - * @return mixed - * @package Mentions + * @param bool $all Specifies whether to count all mentions or only unread. + * @param string $type Specifies the type of mention to count. Empty string to count all types. + * @param int|null $id_member Specifies the ID of the member. If null, the current user's ID will be used. * + * @return int|array The total count of mentions if $type is empty, otherwise an array with counts for each type. */ function countUserMentions($all = false, $type = '', $id_member = null) { @@ -32,38 +30,45 @@ function countUserMentions($all = false, $type = '', $id_member = null) $db = database(); $id_member = $id_member === null ? User::$info->id : (int) $id_member; - if (isset($counts[$id_member . $type])) + if (isset($counts[$id_member][$type])) { - return $counts[$id_member . $type]; + return $counts[$id_member][$type]; } - $request = $db->query('', ' + $allTypes = getMentionTypes($id_member, $all === true ? 'system' : 'user'); + foreach ($allTypes as $thisType) + { + $counts[$id_member][$thisType] = 0; + } + $counts[$id_member]['total'] = 0; + + $db->fetchQuery(' SELECT - COUNT(*) + mention_type, COUNT(*) as cnt FROM {db_prefix}log_mentions as mtn WHERE mtn.id_member = {int:current_user} AND mtn.is_accessible = {int:is_accessible} - AND mtn.status IN ({array_int:status})' . (empty($type) ? '' : (is_array($type) ? ' - AND mtn.mention_type IN ({array_string:current_type})' : ' - AND mtn.mention_type = {string:current_type}')), - array( + AND mtn.status IN ({array_int:status}) + AND mtn.mention_type IN ({array_string:all_type})', + [ 'current_user' => $id_member, - 'current_type' => $type, - 'status' => $all ? array(0, 1) : array(0), + 'status' => $all ? [0, 1] : [0], 'is_accessible' => 1, - ) - ); - list ($counts[$id_member . $type]) = $request->fetch_row(); - $request->free_result(); + 'all_type' => $allTypes, + ] + )->fetch_callback(function ($row) use (&$counts, $id_member) { + $counts[$id_member][$row['mention_type']] = (int) $row['cnt']; + $counts[$id_member]['total'] += $row['cnt']; + }); // Counts as maintenance! :P - if ($all === false && empty($type)) + if ($all === false) { require_once(SUBSDIR . '/Members.subs.php'); - updateMemberData($id_member, array('mentions' => $counts[$id_member])); + updateMemberData($id_member, ['mentions' => $counts[$id_member]['total']]); } - return $counts[$id_member . $type]; + return empty($type) ? $counts[$id_member]['total'] : $counts[$id_member][$type] ?? 0; } /** @@ -262,17 +267,17 @@ function toggleMentionsAccessibility($mentions, $access) /** * To validate access to read/unread/delete mentions * - * - Called from the validation class + * - Called from the validation class via Mentioning.php * * @param string $field - * @param mixed[] $input + * @param array $input * @param string|null $validation_parameters * * @return array|void * @package Mentions * */ -function validate_ownmention($field, $input, $validation_parameters = null) +function validate_own_mention($field, $input, $validation_parameters = null) { if (!isset($input[$field])) { @@ -427,3 +432,58 @@ function getNewMentions($id_member, $timestamp) return $result['c']; } + +/** + * Get the available mention types for a user. + * + * @param int|null $user The user ID. If null, User::$info->id will be used. + * @param string $type The type of mentions. user will return only those that the user has enabled and set + * as notification. If not user, returns the system level enabled mentions. + * + * By default, will filter out notification types with a method set to none, e.g. the user had disable that + * type of mention. Use type=all to return everything, or type=notification to return only those + * that they want on-site notifications. + * + * @return array The available mention types. + */ +function getMentionTypes($user, $type = 'user') +{ + require_once(SUBSDIR . '/Notification.subs.php'); + + $user = $user ?? User::$info->id; + + $enabled = getEnabledNotifications(); + + if ($type !== 'user') + { + sort($enabled); + return $enabled; + } + + $userAllEnabled = getUsersNotificationsPreferences($enabled, $user); + + // Drop ones they do not have enabled (primarily used to drop watchedtopic / watched board) + foreach ($enabled as $key => $notificationType) + { + if (!isset($notificationType, $userAllEnabled[User::$info->id][$notificationType])) + { + unset($enabled[$key]); + } + } + + // Filter the remaining as requested + foreach ($userAllEnabled[User::$info->id] as $notificationType => $allowedMethods) + { + if (!in_array('notification', $allowedMethods, true)) + { + $key = array_search($notificationType, $enabled, true); + if ($key !== false) + { + unset($enabled[$key]); + } + } + } + + sort($enabled); + return $enabled; +} diff --git a/sources/subs/Profile.subs.php b/sources/subs/Profile.subs.php index 010719236d..c7d474b5bc 100644 --- a/sources/subs/Profile.subs.php +++ b/sources/subs/Profile.subs.php @@ -2414,15 +2414,15 @@ function getMemberNotificationsProfile($member_id) if (empty($modSettings['enabled_mentions'])) { - return array(); + return []; } require_once(SUBSDIR . '/Notification.subs.php'); $notifiers = Notifications::instance()->getNotifiers(); - $enabled_mentions = explode(',', $modSettings['enabled_mentions']); + $enabled_mentions = getEnabledNotifications(); $user_preferences = getUsersNotificationsPreferences($enabled_mentions, $member_id); - $mention_types = array(); + $mention_types = []; $defaults = getConfiguredNotificationMethods('*'); foreach ($enabled_mentions as $type) From 7b10ec7b837dd6636e8e64742f3c2c7a2ab2d3d1 Mon Sep 17 00:00:00 2001 From: Spuds Date: Fri, 12 Apr 2024 19:24:15 -0500 Subject: [PATCH 3/4] ! tests! --- sources/subs/Mentions.subs.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sources/subs/Mentions.subs.php b/sources/subs/Mentions.subs.php index b84af9815a..96270585cf 100644 --- a/sources/subs/Mentions.subs.php +++ b/sources/subs/Mentions.subs.php @@ -11,7 +11,6 @@ * */ -use ElkArte\MembersList; use ElkArte\User; /** @@ -44,17 +43,18 @@ function countUserMentions($all = false, $type = '', $id_member = null) $db->fetchQuery(' SELECT - mention_type, COUNT(*) as cnt + mention_type, COUNT(*) AS cnt FROM {db_prefix}log_mentions as mtn WHERE mtn.id_member = {int:current_user} AND mtn.is_accessible = {int:is_accessible} AND mtn.status IN ({array_int:status}) - AND mtn.mention_type IN ({array_string:all_type})', + AND mtn.mention_type IN ({array_string:all_type}) + GROUP BY mtn.mention_type', [ 'current_user' => $id_member, 'status' => $all ? [0, 1] : [0], 'is_accessible' => 1, - 'all_type' => $allTypes, + 'all_type' => empty($allTypes) ? [$type] : $allTypes, ] )->fetch_callback(function ($row) use (&$counts, $id_member) { $counts[$id_member][$row['mention_type']] = (int) $row['cnt']; @@ -465,14 +465,14 @@ function getMentionTypes($user, $type = 'user') // Drop ones they do not have enabled (primarily used to drop watchedtopic / watched board) foreach ($enabled as $key => $notificationType) { - if (!isset($notificationType, $userAllEnabled[User::$info->id][$notificationType])) + if (!isset($userAllEnabled[$user][$notificationType])) { unset($enabled[$key]); } } // Filter the remaining as requested - foreach ($userAllEnabled[User::$info->id] as $notificationType => $allowedMethods) + foreach ($userAllEnabled[$user] as $notificationType => $allowedMethods) { if (!in_array('notification', $allowedMethods, true)) { From a8e8242f849a46dc1367ae43ab5e92b88f1fe1b5 Mon Sep 17 00:00:00 2001 From: Spuds Date: Sat, 13 Apr 2024 08:10:21 -0500 Subject: [PATCH 4/4] ! typo --- sources/ElkArte/Modules/Mentions/AbstractMentions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/ElkArte/Modules/Mentions/AbstractMentions.php b/sources/ElkArte/Modules/Mentions/AbstractMentions.php index 3e92407e88..94cfbd41b2 100644 --- a/sources/ElkArte/Modules/Mentions/AbstractMentions.php +++ b/sources/ElkArte/Modules/Mentions/AbstractMentions.php @@ -37,7 +37,7 @@ protected static function registerHooks($action, EventManager $eventsManager) if (!empty($modSettings['mentions_enabled'])) { - require_once(SUBSDIR . 'Notification.subs.php'); + require_once(SUBSDIR . '/Notification.subs.php'); $mentions = getEnabledNotifications(); foreach ($mentions as $mention)