/** * Callback for createList(), * Returns the mentions of a give type (like/mention) & (unread or all) * * @param int $start start list number * @param int $limit how many to show on a page * @param string $sort which direction are we showing this * @param bool $all : if true load all the mentions or type, otherwise only the unread * @param string $type : the type of mention */ public function list_loadMentions($start, $limit, $sort, $all, $type) { $totalMentions = countUserMentions($all, $type); $mentions = array(); $round = 0; while ($round < 2) { $possible_mentions = getUserMentions($start, $limit, $sort, $all, $type); // With only one type is enough to just call that (if it exists) if (!empty($type) && isset($this->_callbacks[$type])) { $removed = call_user_func_array($this->_callbacks[$type], array(&$possible_mentions, $type)); } else { $removed = false; // @todo find a way to call only what is actually needed foreach ($this->_callbacks as $type => $callback) { $removed = call_user_func_array($callback, array(&$possible_mentions, $type)) || $removed; } } foreach ($possible_mentions as $mention) { if (count($mentions) < $limit) { $mentions[] = $mention; } else { break; } } $round++; // If nothing has been removed OR there are not enough if (!$removed || count($mentions) == $limit || $totalMentions - $start < $limit) { break; } // Let's start a bit further into the list $start += $limit; } if ($round !== 0) { countUserMentions(); } return $mentions; }
/** * Updates the mention count as a result of an action, read, new, delete, etc * * @package Mentions * @param int $status * @param int $member_id */ function updateMentionMenuCount($status, $member_id) { // If its new add to our menu count if ($status === 0) { updateMemberdata($member_id, array('mentions' => '+')); } elseif ($status === 1) { updateMemberdata($member_id, array('mentions' => '-')); } else { countUserMentions(false, '', $member_id); } }
/** * Re-syncs if a user can access a mention, * * - for example if they loose or gain access to a board, this will correct * the viewing of the mention table. Since this can be a large job it is run * as a scheduled immediate task */ public function user_access_mentions() { global $modSettings; $db = database(); $user_access_mentions = @unserialize($modSettings['user_access_mentions']); // This should be set only because of an immediate scheduled task, so higher priority if (!empty($user_access_mentions)) { foreach ($user_access_mentions as $member => $begin) { // Just to stay on the safe side... if (empty($member)) { continue; } require_once SUBSDIR . '/Boards.subs.php'; require_once SUBSDIR . '/Mentions.subs.php'; require_once SUBSDIR . '/Members.subs.php'; $user_see_board = memberQuerySeeBoard($member); $limit = 100; // We need to repeat this twice: once to find the boards the user can access, // once for those he cannot access foreach (array('can', 'cannot') as $can) { // Let's always start from the begin $start = $begin; while (true) { // Find all the mentions that this user can or cannot see $request = $db->query('', ' SELECT mnt.id_mention, m.id_board FROM {db_prefix}log_mentions as mnt LEFT JOIN {db_prefix}messages AS m ON (m.id_msg = mnt.id_msg) LEFT JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board) WHERE mnt.id_member = {int:current_member} AND mnt.mention_type IN ({array_string:mention_types}) AND {raw:user_see_board} LIMIT {int:start}, {int:limit}', array('current_member' => $member, 'mention_types' => array('men', 'like', 'rlike'), 'user_see_board' => ($can == 'can' ? '' : 'NOT ') . $user_see_board, 'start' => $start, 'limit' => $limit)); $mentions = array(); $remove = array(); while ($row = $db->fetch_assoc($request)) { if (empty($row['id_board'])) { $remove[] = $row['id_mention']; } else { $mentions[] = $row['id_mention']; } } $db->free_result($request); if (!empty($remove)) { removeMentions($remove); } // If we found something toggle them and increment the start for the next round if (!empty($mentions)) { toggleMentionsAccessibility($mentions, $can == 'can'); } else { break; } // Next batch $start += $limit; } } // Drop the member unset($user_access_mentions[$member]); // And save everything for the next run updateSettings(array('user_access_mentions' => serialize($user_access_mentions))); // Count helps keep things correct countUserMentions(false, '', $member); // Run this only once for each user, it may be quite heavy, let's split up the load break; } // If there are no more users, scheduleTaskImmediate can be stopped if (empty($user_access_mentions)) { removeScheduleTaskImmediate('user_access_mentions', false); } return true; } else { // Checks 10 users at a time, the scheduled task is set to run once per hour, so 240 users a day // @todo <= I know you like it Spuds! :P It may be necessary to set it to something higher. $limit = 10; $current_check = !empty($modSettings['mentions_member_check']) ? $modSettings['mentions_member_check'] : 0; require_once SUBSDIR . '/Members.subs.php'; require_once SUBSDIR . '/Mentions.subs.php'; // Grab users with mentions $request = $db->query('', ' SELECT COUNT(DISTINCT(id_member)) FROM {db_prefix}log_mentions WHERE id_member > {int:last_id_member} AND mention_type IN ({array_string:mention_types})', array('last_id_member' => $current_check, 'mention_types' => array('men', 'like', 'rlike'))); list($remaining) = $db->fetch_row($request); $db->free_result($request); if ($remaining == 0) { $current_check = 0; } // Grab users with mentions $request = $db->query('', ' SELECT DISTINCT(id_member) as id_member FROM {db_prefix}log_mentions WHERE id_member > {int:last_id_member} AND mention_type IN ({array_string:mention_types}) LIMIT {int:limit}', array('last_id_member' => $current_check, 'mention_types' => array('men', 'like', 'rlike'), 'limit' => $limit)); // Remember where we are updateSettings(array('mentions_member_check' => $current_check + $limit)); while ($row = $db->fetch_assoc($request)) { // Rebuild 'query_see_board', a lot of code duplication... :( $user_see_board = memberQuerySeeBoard($row['id_member']); // Find out if this user cannot see something that was supposed to be able to see $request2 = $db->query('', ' SELECT mnt.id_mention FROM {db_prefix}log_mentions as mnt LEFT JOIN {db_prefix}messages AS m ON (m.id_msg = mnt.id_msg) LEFT JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board) WHERE mnt.id_member = {int:current_member} AND mnt.mention_type IN ({array_string:mention_types}) AND {raw:user_see_board} AND status < 0 LIMIT 1', array('current_member' => $row['id_member'], 'mention_types' => array('men', 'like', 'rlike'), 'user_see_board' => 'NOT ' . $user_see_board)); // One row of results is enough: scheduleTaskImmediate! if ($db->num_rows($request2) == 1) { if (!empty($modSettings['user_access_mentions'])) { $modSettings['user_access_mentions'] = @unserialize($modSettings['user_access_mentions']); } else { $modSettings['user_access_mentions'] = array(); } // But if the member is already on the list, let's skip it if (!isset($modSettings['user_access_mentions'][$row['id_member']])) { $modSettings['user_access_mentions'][$row['id_member']] = 0; updateSettings(array('user_access_mentions' => serialize(array_unique($modSettings['user_access_mentions'])))); scheduleTaskImmediate('user_access_mentions'); } } $db->free_result($request2); } $db->free_result($request); return true; } }