/** * Marks the selected topics as read. * Accessed by action=markasread;sa=unreadreplies */ public function action_markreplies() { global $user_info, $modSettings; // Make sure all the topics are integers! $topics = array_map('intval', explode('-', $_REQUEST['topics'])); require_once SUBSDIR . '/Topic.subs.php'; $logged_topics = getLoggedTopics($user_info['id'], $topics); $markRead = array(); foreach ($topics as $id_topic) { $markRead[] = array($user_info['id'], (int) $id_topic, $modSettings['maxMsgID'], (int) (!empty($logged_topics[$id_topic]))); } markTopicsRead($markRead, true); if (isset($_SESSION['topicseen_cache'])) { $_SESSION['topicseen_cache'] = array(); } return 'action=unreadreplies'; }
/** * Set off/on unread reply subscription for a topic * * @param int $id_member * @param int $topic * @param bool $on = false */ function setTopicWatch($id_member, $topic, $on = false) { global $user_info; $db = database(); // find the current entry if it exists that is $was_set = getLoggedTopics($user_info['id'], array($topic)); // Set topic unwatched on/off for this topic. $db->insert(empty($was_set[$topic]) ? 'ignore' : 'replace', '{db_prefix}log_topics', array('id_member' => 'int', 'id_topic' => 'int', 'id_msg' => 'int', 'unwatched' => 'int'), array($id_member, $topic, !empty($was_set[$topic]['id_msg']) ? $was_set[$topic]['id_msg'] : 0, $on ? 1 : 0), array('id_member', 'id_topic')); }
/** * Allows for moderation from the message index. * @todo refactor this... */ public function action_quickmod() { global $board, $user_info, $modSettings, $context; $db = database(); // Check the session = get or post. checkSession('request'); // Lets go straight to the restore area. if (isset($_REQUEST['qaction']) && $_REQUEST['qaction'] == 'restore' && !empty($_REQUEST['topics'])) { redirectexit('action=restoretopic;topics=' . implode(',', $_REQUEST['topics']) . ';' . $context['session_var'] . '=' . $context['session_id']); } if (isset($_SESSION['topicseen_cache'])) { $_SESSION['topicseen_cache'] = array(); } // This is going to be needed to send off the notifications and for updateLastMessages(). require_once SUBSDIR . '/Post.subs.php'; require_once SUBSDIR . '/Notification.subs.php'; // Process process process data. require_once SUBSDIR . '/Topic.subs.php'; // Remember the last board they moved things to. if (isset($_REQUEST['move_to'])) { $_SESSION['move_to_topic'] = array('move_to' => $_REQUEST['move_to'], 'redirect_topic' => !empty($_REQUEST['redirect_topic']) ? (int) $_REQUEST['redirect_topic'] : 0, 'redirect_expires' => !empty($_REQUEST['redirect_expires']) ? (int) $_REQUEST['redirect_expires'] : 0); } // Only a few possible actions. $possibleActions = array(); if (!empty($board)) { $boards_can = array('make_sticky' => allowedTo('make_sticky') ? array($board) : array(), 'move_any' => allowedTo('move_any') ? array($board) : array(), 'move_own' => allowedTo('move_own') ? array($board) : array(), 'remove_any' => allowedTo('remove_any') ? array($board) : array(), 'remove_own' => allowedTo('remove_own') ? array($board) : array(), 'lock_any' => allowedTo('lock_any') ? array($board) : array(), 'lock_own' => allowedTo('lock_own') ? array($board) : array(), 'merge_any' => allowedTo('merge_any') ? array($board) : array(), 'approve_posts' => allowedTo('approve_posts') ? array($board) : array()); $redirect_url = 'board=' . $board . '.' . $_REQUEST['start']; } else { $boards_can = boardsAllowedTo(array('make_sticky', 'move_any', 'move_own', 'remove_any', 'remove_own', 'lock_any', 'lock_own', 'merge_any', 'approve_posts'), true, false); $redirect_url = isset($_POST['redirect_url']) ? $_POST['redirect_url'] : (isset($_SESSION['old_url']) ? $_SESSION['old_url'] : ''); } if (!$user_info['is_guest']) { $possibleActions[] = 'markread'; } if (!empty($boards_can['make_sticky']) && !empty($modSettings['enableStickyTopics'])) { $possibleActions[] = 'sticky'; } if (!empty($boards_can['move_any']) || !empty($boards_can['move_own'])) { $possibleActions[] = 'move'; } if (!empty($boards_can['remove_any']) || !empty($boards_can['remove_own'])) { $possibleActions[] = 'remove'; } if (!empty($boards_can['lock_any']) || !empty($boards_can['lock_own'])) { $possibleActions[] = 'lock'; } if (!empty($boards_can['merge_any'])) { $possibleActions[] = 'merge'; } if (!empty($boards_can['approve_posts'])) { $possibleActions[] = 'approve'; } // Two methods: $_REQUEST['actions'] (id_topic => action), and $_REQUEST['topics'] and $_REQUEST['qaction']. // (if action is 'move', $_REQUEST['move_to'] or $_REQUEST['move_tos'][$topic] is used.) if (!empty($_REQUEST['topics'])) { // If the action isn't valid, just quit now. if (empty($_REQUEST['qaction']) || !in_array($_REQUEST['qaction'], $possibleActions)) { redirectexit($redirect_url); } // Merge requires all topics as one parameter and can be done at once. if ($_REQUEST['qaction'] == 'merge') { // Merge requires at least two topics. if (empty($_REQUEST['topics']) || count($_REQUEST['topics']) < 2) { redirectexit($redirect_url); } require_once CONTROLLERDIR . '/MergeTopics.controller.php'; $controller = new MergeTopics_Controller(); return $controller->action_mergeExecute($_REQUEST['topics']); } // Just convert to the other method, to make it easier. foreach ($_REQUEST['topics'] as $topic) { $_REQUEST['actions'][(int) $topic] = $_REQUEST['qaction']; } } // Weird... how'd you get here? if (empty($_REQUEST['actions'])) { redirectexit($redirect_url); } // Validate each action. $temp = array(); foreach ($_REQUEST['actions'] as $topic => $action) { if (in_array($action, $possibleActions)) { $temp[(int) $topic] = $action; } } $_REQUEST['actions'] = $temp; if (!empty($_REQUEST['actions'])) { // Find all topics... $topics_info = topicsDetails(array_keys($_REQUEST['actions'])); foreach ($topics_info as $row) { if (!empty($board)) { if ($row['id_board'] != $board || $modSettings['postmod_active'] && !$row['approved'] && !allowedTo('approve_posts')) { unset($_REQUEST['actions'][$row['id_topic']]); } } else { // Don't allow them to act on unapproved posts they can't see... if ($modSettings['postmod_active'] && !$row['approved'] && !in_array(0, $boards_can['approve_posts']) && !in_array($row['id_board'], $boards_can['approve_posts'])) { unset($_REQUEST['actions'][$row['id_topic']]); } elseif ($_REQUEST['actions'][$row['id_topic']] == 'sticky' && !in_array(0, $boards_can['make_sticky']) && !in_array($row['id_board'], $boards_can['make_sticky'])) { unset($_REQUEST['actions'][$row['id_topic']]); } elseif ($_REQUEST['actions'][$row['id_topic']] == 'move' && !in_array(0, $boards_can['move_any']) && !in_array($row['id_board'], $boards_can['move_any']) && ($row['id_member_started'] != $user_info['id'] || !in_array(0, $boards_can['move_own']) && !in_array($row['id_board'], $boards_can['move_own']))) { unset($_REQUEST['actions'][$row['id_topic']]); } elseif ($_REQUEST['actions'][$row['id_topic']] == 'remove' && !in_array(0, $boards_can['remove_any']) && !in_array($row['id_board'], $boards_can['remove_any']) && ($row['id_member_started'] != $user_info['id'] || !in_array(0, $boards_can['remove_own']) && !in_array($row['id_board'], $boards_can['remove_own']))) { unset($_REQUEST['actions'][$row['id_topic']]); } elseif ($_REQUEST['actions'][$row['id_topic']] == 'lock' && !in_array(0, $boards_can['lock_any']) && !in_array($row['id_board'], $boards_can['lock_any']) && ($row['id_member_started'] != $user_info['id'] || $row['locked'] == 1 || !in_array(0, $boards_can['lock_own']) && !in_array($row['id_board'], $boards_can['lock_own']))) { unset($_REQUEST['actions'][$row['id_topic']]); } elseif ($_REQUEST['actions'][$row['id_topic']] == 'approve' && (!$row['unapproved_posts'] || !in_array(0, $boards_can['approve_posts']) && !in_array($row['id_board'], $boards_can['approve_posts']))) { unset($_REQUEST['actions'][$row['id_topic']]); } } } } $stickyCache = array(); $moveCache = array(0 => array(), 1 => array()); $removeCache = array(); $lockCache = array(); $markCache = array(); $approveCache = array(); // Separate the actions. foreach ($_REQUEST['actions'] as $topic => $action) { $topic = (int) $topic; if ($action == 'markread') { $markCache[] = $topic; } elseif ($action == 'sticky') { $stickyCache[] = $topic; } elseif ($action == 'move') { moveTopicConcurrence(); // $moveCache[0] is the topic, $moveCache[1] is the board to move to. $moveCache[1][$topic] = (int) (isset($_REQUEST['move_tos'][$topic]) ? $_REQUEST['move_tos'][$topic] : $_REQUEST['move_to']); if (empty($moveCache[1][$topic])) { continue; } $moveCache[0][] = $topic; } elseif ($action == 'remove') { $removeCache[] = $topic; } elseif ($action == 'lock') { $lockCache[] = $topic; } elseif ($action == 'approve') { $approveCache[] = $topic; } } if (empty($board)) { $affectedBoards = array(); } else { $affectedBoards = array($board => array(0, 0)); } // Do all the stickies... if (!empty($stickyCache)) { toggleTopicSticky($stickyCache); // Get the board IDs and Sticky status $request = $db->query('', ' SELECT id_topic, id_board, is_sticky FROM {db_prefix}topics WHERE id_topic IN ({array_int:sticky_topic_ids}) LIMIT ' . count($stickyCache), array('sticky_topic_ids' => $stickyCache)); $stickyCacheBoards = array(); $stickyCacheStatus = array(); while ($row = $db->fetch_assoc($request)) { $stickyCacheBoards[$row['id_topic']] = $row['id_board']; $stickyCacheStatus[$row['id_topic']] = empty($row['is_sticky']); } $db->free_result($request); } // Move sucka! (this is, by the by, probably the most complicated part....) if (!empty($moveCache[0])) { // I know - I just KNOW you're trying to beat the system. Too bad for you... we CHECK :P. $request = $db->query('', ' SELECT t.id_topic, t.id_board, b.count_posts FROM {db_prefix}topics AS t LEFT JOIN {db_prefix}boards AS b ON (t.id_board = b.id_board) WHERE t.id_topic IN ({array_int:move_topic_ids})' . (!empty($board) && !allowedTo('move_any') ? ' AND t.id_member_started = {int:current_member}' : '') . ' LIMIT ' . count($moveCache[0]), array('current_member' => $user_info['id'], 'move_topic_ids' => $moveCache[0])); $moveTos = array(); $moveCache2 = array(); $countPosts = array(); while ($row = $db->fetch_assoc($request)) { $to = $moveCache[1][$row['id_topic']]; if (empty($to)) { continue; } // Does this topic's board count the posts or not? $countPosts[$row['id_topic']] = empty($row['count_posts']); if (!isset($moveTos[$to])) { $moveTos[$to] = array(); } $moveTos[$to][] = $row['id_topic']; // For reporting... $moveCache2[] = array($row['id_topic'], $row['id_board'], $to); } $db->free_result($request); $moveCache = $moveCache2; // Do the actual moves... foreach ($moveTos as $to => $topics) { moveTopics($topics, $to); } // Does the post counts need to be updated? if (!empty($moveTos)) { require_once SUBSDIR . '/Boards.subs.php'; $topicRecounts = array(); $boards_info = fetchBoardsInfo(array('boards' => array_keys($moveTos)), array('selects' => 'posts')); foreach ($boards_info as $row) { $cp = empty($row['count_posts']); // Go through all the topics that are being moved to this board. foreach ($moveTos[$row['id_board']] as $topic) { // If both boards have the same value for post counting then no adjustment needs to be made. if ($countPosts[$topic] != $cp) { // If the board being moved to does count the posts then the other one doesn't so add to their post count. $topicRecounts[$topic] = $cp ? 1 : -1; } } } if (!empty($topicRecounts)) { // Get all the members who have posted in the moved topics. $posters = topicsPosters(array_keys($topicRecounts)); foreach ($posters as $id_member => $topics) { $post_adj = 0; foreach ($topics as $id_topic) { $post_adj += $topicRecounts[$id_topic]; } // And now update that member's post counts if (!empty($post_adj)) { updateMemberData($id_member, array('posts' => 'posts + ' . $post_adj)); } } } } } // Now delete the topics... if (!empty($removeCache)) { // They can only delete their own topics. (we wouldn't be here if they couldn't do that..) $result = $db->query('', ' SELECT id_topic, id_board FROM {db_prefix}topics WHERE id_topic IN ({array_int:removed_topic_ids})' . (!empty($board) && !allowedTo('remove_any') ? ' AND id_member_started = {int:current_member}' : '') . ' LIMIT ' . count($removeCache), array('current_member' => $user_info['id'], 'removed_topic_ids' => $removeCache)); $removeCache = array(); $removeCacheBoards = array(); while ($row = $db->fetch_assoc($result)) { $removeCache[] = $row['id_topic']; $removeCacheBoards[$row['id_topic']] = $row['id_board']; } $db->free_result($result); // Maybe *none* were their own topics. if (!empty($removeCache)) { // Gotta send the notifications *first*! foreach ($removeCache as $topic) { // Only log the topic ID if it's not in the recycle board. logAction('remove', array(empty($modSettings['recycle_enable']) || $modSettings['recycle_board'] != $removeCacheBoards[$topic] ? 'topic' : 'old_topic_id' => $topic, 'board' => $removeCacheBoards[$topic])); sendNotifications($topic, 'remove'); } removeTopics($removeCache); } } // Approve the topics... if (!empty($approveCache)) { // We need unapproved topic ids and their authors! $request = $db->query('', ' SELECT id_topic, id_member_started FROM {db_prefix}topics WHERE id_topic IN ({array_int:approve_topic_ids}) AND approved = {int:not_approved} LIMIT ' . count($approveCache), array('approve_topic_ids' => $approveCache, 'not_approved' => 0)); $approveCache = array(); $approveCacheMembers = array(); while ($row = $db->fetch_assoc($request)) { $approveCache[] = $row['id_topic']; $approveCacheMembers[$row['id_topic']] = $row['id_member_started']; } $db->free_result($request); // Any topics to approve? if (!empty($approveCache)) { // Handle the approval part... approveTopics($approveCache); // Time for some logging! foreach ($approveCache as $topic) { logAction('approve_topic', array('topic' => $topic, 'member' => $approveCacheMembers[$topic])); } } } // And (almost) lastly, lock the topics... if (!empty($lockCache)) { $lockStatus = array(); // Gotta make sure they CAN lock/unlock these topics... if (!empty($board) && !allowedTo('lock_any')) { // Make sure they started the topic AND it isn't already locked by someone with higher priv's. $result = $db->query('', ' SELECT id_topic, locked, id_board FROM {db_prefix}topics WHERE id_topic IN ({array_int:locked_topic_ids}) AND id_member_started = {int:current_member} AND locked IN (2, 0) LIMIT ' . count($lockCache), array('current_member' => $user_info['id'], 'locked_topic_ids' => $lockCache)); $lockCache = array(); $lockCacheBoards = array(); while ($row = $db->fetch_assoc($result)) { $lockCache[] = $row['id_topic']; $lockCacheBoards[$row['id_topic']] = $row['id_board']; $lockStatus[$row['id_topic']] = empty($row['locked']); } $db->free_result($result); } else { $result = $db->query('', ' SELECT id_topic, locked, id_board FROM {db_prefix}topics WHERE id_topic IN ({array_int:locked_topic_ids}) LIMIT ' . count($lockCache), array('locked_topic_ids' => $lockCache)); $lockCacheBoards = array(); while ($row = $db->fetch_assoc($result)) { $lockStatus[$row['id_topic']] = empty($row['locked']); $lockCacheBoards[$row['id_topic']] = $row['id_board']; } $db->free_result($result); } // It could just be that *none* were their own topics... if (!empty($lockCache)) { // Alternate the locked value. $db->query('', ' UPDATE {db_prefix}topics SET locked = CASE WHEN locked = {int:is_locked} THEN ' . (allowedTo('lock_any') ? '1' : '2') . ' ELSE 0 END WHERE id_topic IN ({array_int:locked_topic_ids})', array('locked_topic_ids' => $lockCache, 'is_locked' => 0)); } } if (!empty($markCache)) { $logged_topics = getLoggedTopics($user_info['id'], $markCache); $markArray = array(); foreach ($markCache as $topic) { $markArray[] = array($user_info['id'], $topic, $modSettings['maxMsgID'], (int) (!empty($logged_topics[$topic]))); } markTopicsRead($markArray, true); } foreach ($moveCache as $topic) { // Didn't actually move anything! if (!isset($topic[0])) { break; } logAction('move', array('topic' => $topic[0], 'board_from' => $topic[1], 'board_to' => $topic[2])); sendNotifications($topic[0], 'move'); } foreach ($lockCache as $topic) { logAction($lockStatus[$topic] ? 'lock' : 'unlock', array('topic' => $topic, 'board' => $lockCacheBoards[$topic])); sendNotifications($topic, $lockStatus[$topic] ? 'lock' : 'unlock'); } foreach ($stickyCache as $topic) { logAction($stickyCacheStatus[$topic] ? 'unsticky' : 'sticky', array('topic' => $topic, 'board' => $stickyCacheBoards[$topic])); sendNotifications($topic, 'sticky'); } updateStats('topic'); updateStats('message'); updateSettings(array('calendar_updated' => time())); if (!empty($affectedBoards)) { updateLastMessages(array_keys($affectedBoards)); } redirectexit($redirect_url); }