/** * Callback used to prepare the mention message for mentions, likes, removed likes and buddies * * @param mixed[] $mentions : Mentions retrieved from the database by getUserMentions * @param string $type : the type of the mention */ public function prepareMentionMessage(&$mentions, $type) { global $txt, $scripturl, $context, $modSettings, $user_info; $boards = array(); $removed = false; foreach ($mentions as $key => $row) { // To ensure it is not done twice if ($row['mention_type'] != $type) { continue; } // These things are associated to messages and require permission checks if (in_array($row['mention_type'], array('men', 'like', 'rlike'))) { $boards[$key] = $row['id_board']; } $mentions[$key]['message'] = str_replace(array('{msg_link}', '{msg_url}', '{subject}'), array('<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . ';mentionread;mark=read;' . $context['session_var'] . '=' . $context['session_id'] . ';item=' . $row['id_mention'] . '#msg' . $row['id_msg'] . '">' . $row['subject'] . '</a>', $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . ';mentionread;' . $context['session_var'] . '=' . $context['session_id'] . 'item=' . $row['id_mention'] . '#msg' . $row['id_msg'], $row['subject']), $txt['mention_' . $row['mention_type']]); } // Do the permissions checks and replace inappropriate messages if (!empty($boards)) { require_once SUBSDIR . '/Boards.subs.php'; $accessibleBoards = accessibleBoards($boards); foreach ($boards as $key => $board) { // You can't see the board where this mention is, so we drop it from the results if (!in_array($board, $accessibleBoards)) { $removed = true; unset($mentions[$key]); } } } // If some of these mentions are no longer visable, we need to do some maintenance if ($removed) { if (!empty($modSettings['user_access_mentions'])) { $modSettings['user_access_mentions'] = @unserialize($modSettings['user_access_mentions']); } else { $modSettings['user_access_mentions'] = array(); } $modSettings['user_access_mentions'][$user_info['id']] = 0; updateSettings(array('user_access_mentions' => serialize($modSettings['user_access_mentions']))); scheduleTaskImmediate('user_access_mentions'); } return $removed; }
/** * 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; } }