Yoshi2889 /
SMF2.1
| 1 | <?php |
||
| 2 | |||
| 3 | /** |
||
| 4 | * Handle merging and splitting of topics |
||
| 5 | * |
||
| 6 | * Simple Machines Forum (SMF) |
||
| 7 | * |
||
| 8 | * @package SMF |
||
| 9 | * @author Simple Machines https://www.simplemachines.org |
||
| 10 | * @copyright 2020 Simple Machines and individual contributors |
||
| 11 | * @license https://www.simplemachines.org/about/smf/license.php BSD |
||
| 12 | * |
||
| 13 | * @version 2.1 RC2 |
||
| 14 | * |
||
| 15 | * Original module by Mach8 - We'll never forget you. |
||
| 16 | */ |
||
| 17 | |||
| 18 | if (!defined('SMF')) |
||
| 19 | die('No direct access...'); |
||
| 20 | |||
| 21 | /** |
||
| 22 | * splits a topic into two topics. |
||
| 23 | * delegates to the other functions (based on the URL parameter 'sa'). |
||
| 24 | * loads the SplitTopics template. |
||
| 25 | * requires the split_any permission. |
||
| 26 | * is accessed with ?action=splittopics. |
||
| 27 | */ |
||
| 28 | function SplitTopics() |
||
| 29 | { |
||
| 30 | global $topic, $sourcedir; |
||
| 31 | |||
| 32 | // And... which topic were you splitting, again? |
||
| 33 | if (empty($topic)) |
||
| 34 | fatal_lang_error('numbers_one_to_nine', false); |
||
| 35 | |||
| 36 | // Are you allowed to split topics? |
||
| 37 | isAllowedTo('split_any'); |
||
| 38 | |||
| 39 | // Load up the "dependencies" - the template, getMsgMemberID(), and sendNotifications(). |
||
| 40 | if (!isset($_REQUEST['xml'])) |
||
| 41 | loadTemplate('SplitTopics'); |
||
| 42 | require_once($sourcedir . '/Subs-Boards.php'); |
||
| 43 | require_once($sourcedir . '/Subs-Post.php'); |
||
| 44 | |||
| 45 | $subActions = array( |
||
| 46 | 'selectTopics' => 'SplitSelectTopics', |
||
| 47 | 'execute' => 'SplitExecute', |
||
| 48 | 'index' => 'SplitIndex', |
||
| 49 | 'splitSelection' => 'SplitSelectionExecute', |
||
| 50 | ); |
||
| 51 | |||
| 52 | // ?action=splittopics;sa=LETSBREAKIT won't work, sorry. |
||
| 53 | if (empty($_REQUEST['sa']) || !isset($subActions[$_REQUEST['sa']])) |
||
| 54 | SplitIndex(); |
||
| 55 | |||
| 56 | else |
||
| 57 | call_helper($subActions[$_REQUEST['sa']]); |
||
| 58 | } |
||
| 59 | |||
| 60 | /** |
||
| 61 | * screen shown before the actual split. |
||
| 62 | * is accessed with ?action=splittopics;sa=index. |
||
| 63 | * default sub action for ?action=splittopics. |
||
| 64 | * uses 'ask' sub template of the SplitTopics template. |
||
| 65 | * redirects to SplitSelectTopics if the message given turns out to be |
||
| 66 | * the first message of a topic. |
||
| 67 | * shows the user three ways to split the current topic. |
||
| 68 | */ |
||
| 69 | function SplitIndex() |
||
| 70 | { |
||
| 71 | global $txt, $topic, $context, $smcFunc, $modSettings; |
||
| 72 | |||
| 73 | // Validate "at". |
||
| 74 | if (empty($_GET['at'])) |
||
| 75 | fatal_lang_error('numbers_one_to_nine', false); |
||
| 76 | $_GET['at'] = (int) $_GET['at']; |
||
| 77 | |||
| 78 | // Retrieve the subject and stuff of the specific topic/message. |
||
| 79 | $request = $smcFunc['db_query']('', ' |
||
| 80 | SELECT m.subject, t.num_replies, t.unapproved_posts, t.id_first_msg, t.approved |
||
| 81 | FROM {db_prefix}messages AS m |
||
| 82 | INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic}) |
||
| 83 | WHERE m.id_msg = {int:split_at}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : ' |
||
| 84 | AND m.approved = 1') . ' |
||
| 85 | AND m.id_topic = {int:current_topic} |
||
| 86 | LIMIT 1', |
||
| 87 | array( |
||
| 88 | 'current_topic' => $topic, |
||
| 89 | 'split_at' => $_GET['at'], |
||
| 90 | ) |
||
| 91 | ); |
||
| 92 | if ($smcFunc['db_num_rows']($request) == 0) |
||
| 93 | fatal_lang_error('cant_find_messages'); |
||
| 94 | |||
| 95 | list ($_REQUEST['subname'], $num_replies, $unapproved_posts, $id_first_msg, $approved) = $smcFunc['db_fetch_row']($request); |
||
| 96 | $smcFunc['db_free_result']($request); |
||
| 97 | |||
| 98 | // If not approved validate they can see it. |
||
| 99 | if ($modSettings['postmod_active'] && !$approved) |
||
| 100 | isAllowedTo('approve_posts'); |
||
| 101 | |||
| 102 | // If this topic has unapproved posts, we need to count them too... |
||
| 103 | if ($modSettings['postmod_active'] && allowedTo('approve_posts')) |
||
| 104 | $num_replies += $unapproved_posts - ($approved ? 0 : 1); |
||
| 105 | |||
| 106 | // Check if there is more than one message in the topic. (there should be.) |
||
| 107 | if ($num_replies < 1) |
||
| 108 | fatal_lang_error('topic_one_post', false); |
||
| 109 | |||
| 110 | // Check if this is the first message in the topic (if so, the first and second option won't be available) |
||
| 111 | if ($id_first_msg == $_GET['at']) |
||
| 112 | return SplitSelectTopics(); |
||
| 113 | |||
| 114 | // Basic template information.... |
||
| 115 | $context['message'] = array( |
||
| 116 | 'id' => $_GET['at'], |
||
| 117 | 'subject' => $_REQUEST['subname'] |
||
| 118 | ); |
||
| 119 | $context['sub_template'] = 'ask'; |
||
| 120 | $context['page_title'] = $txt['split']; |
||
| 121 | } |
||
| 122 | |||
| 123 | /** |
||
| 124 | * do the actual split. |
||
| 125 | * is accessed with ?action=splittopics;sa=execute. |
||
| 126 | * uses the main SplitTopics template. |
||
| 127 | * supports three ways of splitting: |
||
| 128 | * (1) only one message is split off. |
||
| 129 | * (2) all messages after and including a given message are split off. |
||
| 130 | * (3) select topics to split (redirects to SplitSelectTopics()). |
||
| 131 | * uses splitTopic function to do the actual splitting. |
||
| 132 | */ |
||
| 133 | function SplitExecute() |
||
| 134 | { |
||
| 135 | global $txt, $topic, $context, $smcFunc; |
||
| 136 | |||
| 137 | // Check the session to make sure they meant to do this. |
||
| 138 | checkSession(); |
||
| 139 | |||
| 140 | // Clean up the subject. |
||
| 141 | if (!isset($_POST['subname']) || $_POST['subname'] == '') |
||
| 142 | $_POST['subname'] = $txt['new_topic']; |
||
| 143 | |||
| 144 | // Redirect to the selector if they chose selective. |
||
| 145 | if ($_POST['step2'] == 'selective') |
||
| 146 | redirectexit ('action=splittopics;sa=selectTopics;subname=' . $_POST['subname'] . ';topic=' . $topic . '.0;start2=0'); |
||
| 147 | |||
| 148 | $_POST['at'] = (int) $_POST['at']; |
||
| 149 | $messagesToBeSplit = array(); |
||
| 150 | |||
| 151 | if ($_POST['step2'] == 'afterthis') |
||
| 152 | { |
||
| 153 | // Fetch the message IDs of the topic that are at or after the message. |
||
| 154 | $request = $smcFunc['db_query']('', ' |
||
| 155 | SELECT id_msg |
||
| 156 | FROM {db_prefix}messages |
||
| 157 | WHERE id_topic = {int:current_topic} |
||
| 158 | AND id_msg >= {int:split_at}', |
||
| 159 | array( |
||
| 160 | 'current_topic' => $topic, |
||
| 161 | 'split_at' => $_POST['at'], |
||
| 162 | ) |
||
| 163 | ); |
||
| 164 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 165 | $messagesToBeSplit[] = $row['id_msg']; |
||
| 166 | |||
| 167 | $smcFunc['db_free_result']($request); |
||
| 168 | } |
||
| 169 | // Only the selected message has to be split. That should be easy. |
||
| 170 | elseif ($_POST['step2'] == 'onlythis') |
||
| 171 | $messagesToBeSplit[] = $_POST['at']; |
||
| 172 | // There's another action?! |
||
| 173 | else |
||
| 174 | fatal_lang_error('no_access', false); |
||
| 175 | |||
| 176 | $context['old_topic'] = $topic; |
||
| 177 | $context['new_topic'] = splitTopic($topic, $messagesToBeSplit, $_POST['subname']); |
||
| 178 | $context['page_title'] = $txt['split']; |
||
| 179 | } |
||
| 180 | |||
| 181 | /** |
||
| 182 | * allows the user to select the messages to be split. |
||
| 183 | * is accessed with ?action=splittopics;sa=selectTopics. |
||
| 184 | * uses 'select' sub template of the SplitTopics template or (for |
||
| 185 | * XMLhttp) the 'split' sub template of the Xml template. |
||
| 186 | * supports XMLhttp for adding/removing a message to the selection. |
||
| 187 | * uses a session variable to store the selected topics. |
||
| 188 | * shows two independent page indexes for both the selected and |
||
| 189 | * not-selected messages (;topic=1.x;start2=y). |
||
| 190 | */ |
||
| 191 | function SplitSelectTopics() |
||
| 192 | { |
||
| 193 | global $txt, $scripturl, $topic, $context, $modSettings, $original_msgs, $smcFunc, $options; |
||
| 194 | |||
| 195 | $context['page_title'] = $txt['split'] . ' - ' . $txt['select_split_posts']; |
||
| 196 | |||
| 197 | // Haven't selected anything have we? |
||
| 198 | $_SESSION['split_selection'][$topic] = empty($_SESSION['split_selection'][$topic]) ? array() : $_SESSION['split_selection'][$topic]; |
||
| 199 | |||
| 200 | // This is a special case for split topics from quick-moderation checkboxes |
||
| 201 | if (isset($_REQUEST['subname_enc'])) |
||
| 202 | $_REQUEST['subname'] = urldecode($_REQUEST['subname_enc']); |
||
| 203 | |||
| 204 | $context['not_selected'] = array( |
||
| 205 | 'num_messages' => 0, |
||
| 206 | 'start' => empty($_REQUEST['start']) ? 0 : (int) $_REQUEST['start'], |
||
| 207 | 'messages' => array(), |
||
| 208 | ); |
||
| 209 | |||
| 210 | $context['selected'] = array( |
||
| 211 | 'num_messages' => 0, |
||
| 212 | 'start' => empty($_REQUEST['start2']) ? 0 : (int) $_REQUEST['start2'], |
||
| 213 | 'messages' => array(), |
||
| 214 | ); |
||
| 215 | |||
| 216 | $context['topic'] = array( |
||
| 217 | 'id' => $topic, |
||
| 218 | 'subject' => urlencode($_REQUEST['subname']), |
||
| 219 | ); |
||
| 220 | |||
| 221 | // Some stuff for our favorite template. |
||
| 222 | $context['new_subject'] = $_REQUEST['subname']; |
||
| 223 | |||
| 224 | // Using the "select" sub template. |
||
| 225 | $context['sub_template'] = isset($_REQUEST['xml']) ? 'split' : 'select'; |
||
| 226 | |||
| 227 | // Are we using a custom messages per page? |
||
| 228 | $context['messages_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['messages_per_page']) ? $options['messages_per_page'] : $modSettings['defaultMaxMessages']; |
||
| 229 | |||
| 230 | // Get the message ID's from before the move. |
||
| 231 | if (isset($_REQUEST['xml'])) |
||
| 232 | { |
||
| 233 | $original_msgs = array( |
||
| 234 | 'not_selected' => array(), |
||
| 235 | 'selected' => array(), |
||
| 236 | ); |
||
| 237 | $request = $smcFunc['db_query']('', ' |
||
| 238 | SELECT id_msg |
||
| 239 | FROM {db_prefix}messages |
||
| 240 | WHERE id_topic = {int:current_topic}' . (empty($_SESSION['split_selection'][$topic]) ? '' : ' |
||
| 241 | AND id_msg NOT IN ({array_int:no_split_msgs})') . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : ' |
||
| 242 | AND approved = {int:is_approved}') . ' |
||
| 243 | ' . (empty($options['view_newest_first']) ? '' : 'ORDER BY id_msg DESC') . ' |
||
| 244 | LIMIT {int:start}, {int:messages_per_page}', |
||
| 245 | array( |
||
| 246 | 'current_topic' => $topic, |
||
| 247 | 'no_split_msgs' => empty($_SESSION['split_selection'][$topic]) ? array() : $_SESSION['split_selection'][$topic], |
||
| 248 | 'is_approved' => 1, |
||
| 249 | 'start' => $context['not_selected']['start'], |
||
| 250 | 'messages_per_page' => $context['messages_per_page'], |
||
| 251 | ) |
||
| 252 | ); |
||
| 253 | // You can't split the last message off. |
||
| 254 | if (empty($context['not_selected']['start']) && $smcFunc['db_num_rows']($request) <= 1 && $_REQUEST['move'] == 'down') |
||
| 255 | $_REQUEST['move'] = ''; |
||
| 256 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 257 | $original_msgs['not_selected'][] = $row['id_msg']; |
||
| 258 | $smcFunc['db_free_result']($request); |
||
| 259 | if (!empty($_SESSION['split_selection'][$topic])) |
||
| 260 | { |
||
| 261 | $request = $smcFunc['db_query']('', ' |
||
| 262 | SELECT id_msg |
||
| 263 | FROM {db_prefix}messages |
||
| 264 | WHERE id_topic = {int:current_topic} |
||
| 265 | AND id_msg IN ({array_int:split_msgs})' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : ' |
||
| 266 | AND approved = {int:is_approved}') . ' |
||
| 267 | ' . (empty($options['view_newest_first']) ? '' : 'ORDER BY id_msg DESC') . ' |
||
| 268 | LIMIT {int:start}, {int:messages_per_page}', |
||
| 269 | array( |
||
| 270 | 'current_topic' => $topic, |
||
| 271 | 'split_msgs' => $_SESSION['split_selection'][$topic], |
||
| 272 | 'is_approved' => 1, |
||
| 273 | 'start' => $context['selected']['start'], |
||
| 274 | 'messages_per_page' => $context['messages_per_page'], |
||
| 275 | ) |
||
| 276 | ); |
||
| 277 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 278 | $original_msgs['selected'][] = $row['id_msg']; |
||
| 279 | |||
| 280 | $smcFunc['db_free_result']($request); |
||
| 281 | } |
||
| 282 | } |
||
| 283 | |||
| 284 | // (De)select a message.. |
||
| 285 | if (!empty($_REQUEST['move'])) |
||
| 286 | { |
||
| 287 | $_REQUEST['msg'] = (int) $_REQUEST['msg']; |
||
| 288 | |||
| 289 | if ($_REQUEST['move'] == 'reset') |
||
| 290 | $_SESSION['split_selection'][$topic] = array(); |
||
| 291 | elseif ($_REQUEST['move'] == 'up') |
||
| 292 | $_SESSION['split_selection'][$topic] = array_diff($_SESSION['split_selection'][$topic], array($_REQUEST['msg'])); |
||
| 293 | else |
||
| 294 | $_SESSION['split_selection'][$topic][] = $_REQUEST['msg']; |
||
| 295 | } |
||
| 296 | |||
| 297 | // Make sure the selection is still accurate. |
||
| 298 | if (!empty($_SESSION['split_selection'][$topic])) |
||
| 299 | { |
||
| 300 | $request = $smcFunc['db_query']('', ' |
||
| 301 | SELECT id_msg |
||
| 302 | FROM {db_prefix}messages |
||
| 303 | WHERE id_topic = {int:current_topic} |
||
| 304 | AND id_msg IN ({array_int:split_msgs})' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : ' |
||
| 305 | AND approved = {int:is_approved}'), |
||
| 306 | array( |
||
| 307 | 'current_topic' => $topic, |
||
| 308 | 'split_msgs' => $_SESSION['split_selection'][$topic], |
||
| 309 | 'is_approved' => 1, |
||
| 310 | ) |
||
| 311 | ); |
||
| 312 | $_SESSION['split_selection'][$topic] = array(); |
||
| 313 | |||
| 314 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 315 | $_SESSION['split_selection'][$topic][] = $row['id_msg']; |
||
| 316 | |||
| 317 | $smcFunc['db_free_result']($request); |
||
| 318 | } |
||
| 319 | |||
| 320 | // Get the number of messages (not) selected to be split. |
||
| 321 | $request = $smcFunc['db_query']('', ' |
||
| 322 | SELECT ' . (empty($_SESSION['split_selection'][$topic]) ? '0' : 'm.id_msg IN ({array_int:split_msgs})') . ' AS is_selected, COUNT(*) AS num_messages |
||
| 323 | FROM {db_prefix}messages AS m |
||
| 324 | WHERE m.id_topic = {int:current_topic}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : ' |
||
| 325 | AND approved = {int:is_approved}') . (empty($_SESSION['split_selection'][$topic]) ? '' : ' |
||
| 326 | GROUP BY is_selected'), |
||
| 327 | array( |
||
| 328 | 'current_topic' => $topic, |
||
| 329 | 'split_msgs' => !empty($_SESSION['split_selection'][$topic]) ? $_SESSION['split_selection'][$topic] : array(), |
||
| 330 | 'is_approved' => 1, |
||
| 331 | ) |
||
| 332 | ); |
||
| 333 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 334 | $context[empty($row['is_selected']) || $row['is_selected'] == 'f' ? 'not_selected' : 'selected']['num_messages'] = $row['num_messages']; |
||
| 335 | $smcFunc['db_free_result']($request); |
||
| 336 | |||
| 337 | // Fix an oversized starting page (to make sure both pageindexes are properly set). |
||
| 338 | if ($context['selected']['start'] >= $context['selected']['num_messages']) |
||
| 339 | $context['selected']['start'] = $context['selected']['num_messages'] <= $context['messages_per_page'] ? 0 : ($context['selected']['num_messages'] - (($context['selected']['num_messages'] % $context['messages_per_page']) == 0 ? $context['messages_per_page'] : ($context['selected']['num_messages'] % $context['messages_per_page']))); |
||
| 340 | |||
| 341 | // Build a page list of the not-selected topics... |
||
| 342 | $context['not_selected']['page_index'] = constructPageIndex($scripturl . '?action=splittopics;sa=selectTopics;subname=' . strtr(urlencode($_REQUEST['subname']), array('%' => '%%')) . ';topic=' . $topic . '.%1$d;start2=' . $context['selected']['start'], $context['not_selected']['start'], $context['not_selected']['num_messages'], $context['messages_per_page'], true); |
||
| 343 | // ...and one of the selected topics. |
||
| 344 | $context['selected']['page_index'] = constructPageIndex($scripturl . '?action=splittopics;sa=selectTopics;subname=' . strtr(urlencode($_REQUEST['subname']), array('%' => '%%')) . ';topic=' . $topic . '.' . $context['not_selected']['start'] . ';start2=%1$d', $context['selected']['start'], $context['selected']['num_messages'], $context['messages_per_page'], true); |
||
| 345 | |||
| 346 | // Get the messages and stick them into an array. |
||
| 347 | $request = $smcFunc['db_query']('', ' |
||
| 348 | SELECT m.subject, COALESCE(mem.real_name, m.poster_name) AS real_name, m.poster_time, m.body, m.id_msg, m.smileys_enabled |
||
| 349 | FROM {db_prefix}messages AS m |
||
| 350 | LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member) |
||
| 351 | WHERE m.id_topic = {int:current_topic}' . (empty($_SESSION['split_selection'][$topic]) ? '' : ' |
||
| 352 | AND id_msg NOT IN ({array_int:no_split_msgs})') . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : ' |
||
| 353 | AND approved = {int:is_approved}') . ' |
||
| 354 | ' . (empty($options['view_newest_first']) ? '' : 'ORDER BY m.id_msg DESC') . ' |
||
| 355 | LIMIT {int:start}, {int:messages_per_page}', |
||
| 356 | array( |
||
| 357 | 'current_topic' => $topic, |
||
| 358 | 'no_split_msgs' => !empty($_SESSION['split_selection'][$topic]) ? $_SESSION['split_selection'][$topic] : array(), |
||
| 359 | 'is_approved' => 1, |
||
| 360 | 'start' => $context['not_selected']['start'], |
||
| 361 | 'messages_per_page' => $context['messages_per_page'], |
||
| 362 | ) |
||
| 363 | ); |
||
| 364 | $context['messages'] = array(); |
||
| 365 | for ($counter = 0; $row = $smcFunc['db_fetch_assoc']($request); $counter++) |
||
| 366 | { |
||
| 367 | censorText($row['subject']); |
||
| 368 | censorText($row['body']); |
||
| 369 | |||
| 370 | $row['body'] = parse_bbc($row['body'], $row['smileys_enabled'], $row['id_msg']); |
||
| 371 | |||
| 372 | $context['not_selected']['messages'][$row['id_msg']] = array( |
||
| 373 | 'id' => $row['id_msg'], |
||
| 374 | 'subject' => $row['subject'], |
||
| 375 | 'time' => timeformat($row['poster_time']), |
||
| 376 | 'timestamp' => forum_time(true, $row['poster_time']), |
||
| 377 | 'body' => $row['body'], |
||
| 378 | 'poster' => $row['real_name'], |
||
| 379 | ); |
||
| 380 | } |
||
| 381 | $smcFunc['db_free_result']($request); |
||
| 382 | |||
| 383 | // Now get the selected messages. |
||
| 384 | if (!empty($_SESSION['split_selection'][$topic])) |
||
| 385 | { |
||
| 386 | // Get the messages and stick them into an array. |
||
| 387 | $request = $smcFunc['db_query']('', ' |
||
| 388 | SELECT m.subject, COALESCE(mem.real_name, m.poster_name) AS real_name, m.poster_time, m.body, m.id_msg, m.smileys_enabled |
||
| 389 | FROM {db_prefix}messages AS m |
||
| 390 | LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member) |
||
| 391 | WHERE m.id_topic = {int:current_topic} |
||
| 392 | AND m.id_msg IN ({array_int:split_msgs})' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : ' |
||
| 393 | AND approved = {int:is_approved}') . ' |
||
| 394 | ' . (empty($options['view_newest_first']) ? '' : 'ORDER BY m.id_msg DESC') . ' |
||
| 395 | LIMIT {int:start}, {int:messages_per_page}', |
||
| 396 | array( |
||
| 397 | 'current_topic' => $topic, |
||
| 398 | 'split_msgs' => $_SESSION['split_selection'][$topic], |
||
| 399 | 'is_approved' => 1, |
||
| 400 | 'start' => $context['selected']['start'], |
||
| 401 | 'messages_per_page' => $context['messages_per_page'], |
||
| 402 | ) |
||
| 403 | ); |
||
| 404 | $context['messages'] = array(); |
||
| 405 | for ($counter = 0; $row = $smcFunc['db_fetch_assoc']($request); $counter++) |
||
| 406 | { |
||
| 407 | censorText($row['subject']); |
||
| 408 | censorText($row['body']); |
||
| 409 | |||
| 410 | $row['body'] = parse_bbc($row['body'], $row['smileys_enabled'], $row['id_msg']); |
||
| 411 | |||
| 412 | $context['selected']['messages'][$row['id_msg']] = array( |
||
| 413 | 'id' => $row['id_msg'], |
||
| 414 | 'subject' => $row['subject'], |
||
| 415 | 'time' => timeformat($row['poster_time']), |
||
| 416 | 'timestamp' => forum_time(true, $row['poster_time']), |
||
| 417 | 'body' => $row['body'], |
||
| 418 | 'poster' => $row['real_name'] |
||
| 419 | ); |
||
| 420 | } |
||
| 421 | $smcFunc['db_free_result']($request); |
||
| 422 | } |
||
| 423 | |||
| 424 | // The XMLhttp method only needs the stuff that changed, so let's compare. |
||
| 425 | if (isset($_REQUEST['xml'])) |
||
| 426 | { |
||
| 427 | $changes = array( |
||
| 428 | 'remove' => array( |
||
| 429 | 'not_selected' => array_diff($original_msgs['not_selected'], array_keys($context['not_selected']['messages'])), |
||
| 430 | 'selected' => array_diff($original_msgs['selected'], array_keys($context['selected']['messages'])), |
||
| 431 | ), |
||
| 432 | 'insert' => array( |
||
| 433 | 'not_selected' => array_diff(array_keys($context['not_selected']['messages']), $original_msgs['not_selected']), |
||
| 434 | 'selected' => array_diff(array_keys($context['selected']['messages']), $original_msgs['selected']), |
||
| 435 | ), |
||
| 436 | ); |
||
| 437 | |||
| 438 | $context['changes'] = array(); |
||
| 439 | foreach ($changes as $change_type => $change_array) |
||
| 440 | foreach ($change_array as $section => $msg_array) |
||
| 441 | { |
||
| 442 | if (empty($msg_array)) |
||
| 443 | continue; |
||
| 444 | |||
| 445 | foreach ($msg_array as $id_msg) |
||
| 446 | { |
||
| 447 | $context['changes'][$change_type . $id_msg] = array( |
||
| 448 | 'id' => $id_msg, |
||
| 449 | 'type' => $change_type, |
||
| 450 | 'section' => $section, |
||
| 451 | ); |
||
| 452 | if ($change_type == 'insert') |
||
| 453 | $context['changes']['insert' . $id_msg]['insert_value'] = $context[$section]['messages'][$id_msg]; |
||
| 454 | } |
||
| 455 | } |
||
| 456 | } |
||
| 457 | } |
||
| 458 | |||
| 459 | /** |
||
| 460 | * do the actual split of a selection of topics. |
||
| 461 | * is accessed with ?action=splittopics;sa=splitSelection. |
||
| 462 | * uses the main SplitTopics template. |
||
| 463 | * uses splitTopic function to do the actual splitting. |
||
| 464 | */ |
||
| 465 | function SplitSelectionExecute() |
||
| 466 | { |
||
| 467 | global $txt, $topic, $context; |
||
| 468 | |||
| 469 | // Make sure the session id was passed with post. |
||
| 470 | checkSession(); |
||
| 471 | |||
| 472 | // Default the subject in case it's blank. |
||
| 473 | if (!isset($_POST['subname']) || $_POST['subname'] == '') |
||
| 474 | $_POST['subname'] = $txt['new_topic']; |
||
| 475 | |||
| 476 | // You must've selected some messages! Can't split out none! |
||
| 477 | if (empty($_SESSION['split_selection'][$topic])) |
||
| 478 | fatal_lang_error('no_posts_selected', false); |
||
| 479 | |||
| 480 | $context['old_topic'] = $topic; |
||
| 481 | $context['new_topic'] = splitTopic($topic, $_SESSION['split_selection'][$topic], $_POST['subname']); |
||
| 482 | $context['page_title'] = $txt['split']; |
||
| 483 | } |
||
| 484 | |||
| 485 | /** |
||
| 486 | * general function to split off a topic. |
||
| 487 | * creates a new topic and moves the messages with the IDs in |
||
| 488 | * array messagesToBeSplit to the new topic. |
||
| 489 | * the subject of the newly created topic is set to 'newSubject'. |
||
| 490 | * marks the newly created message as read for the user splitting it. |
||
| 491 | * updates the statistics to reflect a newly created topic. |
||
| 492 | * logs the action in the moderation log. |
||
| 493 | * a notification is sent to all users monitoring this topic. |
||
| 494 | * |
||
| 495 | * @param int $split1_ID_TOPIC The ID of the topic we're splitting |
||
| 496 | * @param array $splitMessages The IDs of the messages being split |
||
| 497 | * @param string $new_subject The subject of the new topic |
||
| 498 | * @return int The ID of the new split topic. |
||
| 499 | */ |
||
| 500 | function splitTopic($split1_ID_TOPIC, $splitMessages, $new_subject) |
||
| 501 | { |
||
| 502 | global $smcFunc, $txt, $sourcedir; |
||
| 503 | |||
| 504 | // Nothing to split? |
||
| 505 | if (empty($splitMessages)) |
||
| 506 | fatal_lang_error('no_posts_selected', false); |
||
| 507 | |||
| 508 | // Get some board info. |
||
| 509 | $request = $smcFunc['db_query']('', ' |
||
| 510 | SELECT id_board, approved |
||
| 511 | FROM {db_prefix}topics |
||
| 512 | WHERE id_topic = {int:id_topic} |
||
| 513 | LIMIT 1', |
||
| 514 | array( |
||
| 515 | 'id_topic' => $split1_ID_TOPIC, |
||
| 516 | ) |
||
| 517 | ); |
||
| 518 | list ($id_board, $split1_approved) = $smcFunc['db_fetch_row']($request); |
||
| 519 | $smcFunc['db_free_result']($request); |
||
| 520 | |||
| 521 | // Find the new first and last not in the list. (old topic) |
||
| 522 | $request = $smcFunc['db_query']('', ' |
||
| 523 | SELECT |
||
| 524 | MIN(m.id_msg) AS myid_first_msg, MAX(m.id_msg) AS myid_last_msg, COUNT(*) AS message_count, m.approved |
||
| 525 | FROM {db_prefix}messages AS m |
||
| 526 | INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:id_topic}) |
||
| 527 | WHERE m.id_msg NOT IN ({array_int:no_msg_list}) |
||
| 528 | AND m.id_topic = {int:id_topic} |
||
| 529 | GROUP BY m.approved |
||
| 530 | ORDER BY m.approved DESC |
||
| 531 | LIMIT 2', |
||
| 532 | array( |
||
| 533 | 'id_topic' => $split1_ID_TOPIC, |
||
| 534 | 'no_msg_list' => $splitMessages, |
||
| 535 | ) |
||
| 536 | ); |
||
| 537 | // You can't select ALL the messages! |
||
| 538 | if ($smcFunc['db_num_rows']($request) == 0) |
||
| 539 | fatal_lang_error('selected_all_posts', false); |
||
| 540 | |||
| 541 | $split1_first_msg = null; |
||
| 542 | $split1_last_msg = null; |
||
| 543 | |||
| 544 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 545 | { |
||
| 546 | // Get the right first and last message dependant on approved state... |
||
| 547 | if (empty($split1_first_msg) || $row['myid_first_msg'] < $split1_first_msg) |
||
| 548 | $split1_first_msg = $row['myid_first_msg']; |
||
| 549 | if (empty($split1_last_msg) || $row['approved']) |
||
| 550 | $split1_last_msg = $row['myid_last_msg']; |
||
| 551 | |||
| 552 | // Get the counts correct... |
||
| 553 | if ($row['approved']) |
||
| 554 | { |
||
| 555 | $split1_replies = $row['message_count'] - 1; |
||
| 556 | $split1_unapprovedposts = 0; |
||
| 557 | } |
||
| 558 | else |
||
| 559 | { |
||
| 560 | if (!isset($split1_replies)) |
||
| 561 | $split1_replies = 0; |
||
| 562 | // If the topic isn't approved then num replies must go up by one... as first post wouldn't be counted. |
||
| 563 | elseif (!$split1_approved) |
||
| 564 | $split1_replies++; |
||
| 565 | |||
| 566 | $split1_unapprovedposts = $row['message_count']; |
||
| 567 | } |
||
| 568 | } |
||
| 569 | $smcFunc['db_free_result']($request); |
||
| 570 | $split1_firstMem = getMsgMemberID($split1_first_msg); |
||
| 571 | $split1_lastMem = getMsgMemberID($split1_last_msg); |
||
| 572 | |||
| 573 | // Find the first and last in the list. (new topic) |
||
| 574 | $request = $smcFunc['db_query']('', ' |
||
| 575 | SELECT MIN(id_msg) AS myid_first_msg, MAX(id_msg) AS myid_last_msg, COUNT(*) AS message_count, approved |
||
| 576 | FROM {db_prefix}messages |
||
| 577 | WHERE id_msg IN ({array_int:msg_list}) |
||
| 578 | AND id_topic = {int:id_topic} |
||
| 579 | GROUP BY id_topic, approved |
||
| 580 | ORDER BY approved DESC |
||
| 581 | LIMIT 2', |
||
| 582 | array( |
||
| 583 | 'msg_list' => $splitMessages, |
||
| 584 | 'id_topic' => $split1_ID_TOPIC, |
||
| 585 | ) |
||
| 586 | ); |
||
| 587 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 588 | { |
||
| 589 | // As before get the right first and last message dependant on approved state... |
||
| 590 | if (empty($split2_first_msg) || $row['myid_first_msg'] < $split2_first_msg) |
||
| 591 | $split2_first_msg = $row['myid_first_msg']; |
||
| 592 | if (empty($split2_last_msg) || $row['approved']) |
||
| 593 | $split2_last_msg = $row['myid_last_msg']; |
||
| 594 | |||
| 595 | // Then do the counts again... |
||
| 596 | if ($row['approved']) |
||
| 597 | { |
||
| 598 | $split2_approved = true; |
||
| 599 | $split2_replies = $row['message_count'] - 1; |
||
| 600 | $split2_unapprovedposts = 0; |
||
| 601 | } |
||
| 602 | else |
||
| 603 | { |
||
| 604 | // Should this one be approved?? |
||
| 605 | if ($split2_first_msg == $row['myid_first_msg']) |
||
| 606 | $split2_approved = false; |
||
| 607 | |||
| 608 | if (!isset($split2_replies)) |
||
| 609 | $split2_replies = 0; |
||
| 610 | // As before, fix number of replies. |
||
| 611 | elseif (!$split2_approved) |
||
| 612 | $split2_replies++; |
||
| 613 | |||
| 614 | $split2_unapprovedposts = $row['message_count']; |
||
| 615 | } |
||
| 616 | } |
||
| 617 | $smcFunc['db_free_result']($request); |
||
| 618 | $split2_firstMem = getMsgMemberID($split2_first_msg); |
||
| 619 | $split2_lastMem = getMsgMemberID($split2_last_msg); |
||
| 620 | |||
| 621 | // No database changes yet, so let's double check to see if everything makes at least a little sense. |
||
| 622 | if ($split1_first_msg <= 0 || $split1_last_msg <= 0 || $split2_first_msg <= 0 || $split2_last_msg <= 0 || $split1_replies < 0 || $split2_replies < 0 || $split1_unapprovedposts < 0 || $split2_unapprovedposts < 0 || !isset($split1_approved) || !isset($split2_approved)) |
||
| 623 | fatal_lang_error('cant_find_messages'); |
||
| 624 | |||
| 625 | // You cannot split off the first message of a topic. |
||
| 626 | if ($split1_first_msg > $split2_first_msg) |
||
| 627 | fatal_lang_error('split_first_post', false); |
||
| 628 | |||
| 629 | // We're off to insert the new topic! Use 0 for now to avoid UNIQUE errors. |
||
| 630 | $split2_ID_TOPIC = $smcFunc['db_insert']('', |
||
| 631 | '{db_prefix}topics', |
||
| 632 | array( |
||
| 633 | 'id_board' => 'int', |
||
| 634 | 'id_member_started' => 'int', |
||
| 635 | 'id_member_updated' => 'int', |
||
| 636 | 'id_first_msg' => 'int', |
||
| 637 | 'id_last_msg' => 'int', |
||
| 638 | 'num_replies' => 'int', |
||
| 639 | 'unapproved_posts' => 'int', |
||
| 640 | 'approved' => 'int', |
||
| 641 | 'is_sticky' => 'int', |
||
| 642 | ), |
||
| 643 | array( |
||
| 644 | (int) $id_board, $split2_firstMem, $split2_lastMem, 0, |
||
| 645 | 0, $split2_replies, $split2_unapprovedposts, (int) $split2_approved, 0, |
||
| 646 | ), |
||
| 647 | array('id_topic'), |
||
| 648 | 1 |
||
| 649 | ); |
||
| 650 | if ($split2_ID_TOPIC <= 0) |
||
| 651 | fatal_lang_error('cant_insert_topic'); |
||
| 652 | |||
| 653 | // Move the messages over to the other topic. |
||
| 654 | $new_subject = strtr($smcFunc['htmltrim']($smcFunc['htmlspecialchars']($new_subject)), array("\r" => '', "\n" => '', "\t" => '')); |
||
| 655 | // Check the subject length. |
||
| 656 | if ($smcFunc['strlen']($new_subject) > 100) |
||
| 657 | $new_subject = $smcFunc['substr']($new_subject, 0, 100); |
||
| 658 | // Valid subject? |
||
| 659 | if ($new_subject != '') |
||
| 660 | { |
||
| 661 | $smcFunc['db_query']('', ' |
||
| 662 | UPDATE {db_prefix}messages |
||
| 663 | SET |
||
| 664 | id_topic = {int:id_topic}, |
||
| 665 | subject = CASE WHEN id_msg = {int:split_first_msg} THEN {string:new_subject} ELSE {string:new_subject_replies} END |
||
| 666 | WHERE id_msg IN ({array_int:split_msgs})', |
||
| 667 | array( |
||
| 668 | 'split_msgs' => $splitMessages, |
||
| 669 | 'id_topic' => $split2_ID_TOPIC, |
||
| 670 | 'new_subject' => $new_subject, |
||
| 671 | 'split_first_msg' => $split2_first_msg, |
||
| 672 | 'new_subject_replies' => $txt['response_prefix'] . $new_subject, |
||
| 673 | ) |
||
| 674 | ); |
||
| 675 | |||
| 676 | // Cache the new topics subject... we can do it now as all the subjects are the same! |
||
| 677 | updateStats('subject', $split2_ID_TOPIC, $new_subject); |
||
| 678 | } |
||
| 679 | |||
| 680 | // Any associated reported posts better follow... |
||
| 681 | $smcFunc['db_query']('', ' |
||
| 682 | UPDATE {db_prefix}log_reported |
||
| 683 | SET id_topic = {int:id_topic} |
||
| 684 | WHERE id_msg IN ({array_int:split_msgs})', |
||
| 685 | array( |
||
| 686 | 'split_msgs' => $splitMessages, |
||
| 687 | 'id_topic' => $split2_ID_TOPIC, |
||
| 688 | ) |
||
| 689 | ); |
||
| 690 | |||
| 691 | // Mess with the old topic's first, last, and number of messages. |
||
| 692 | $smcFunc['db_query']('', ' |
||
| 693 | UPDATE {db_prefix}topics |
||
| 694 | SET |
||
| 695 | num_replies = {int:num_replies}, |
||
| 696 | id_first_msg = {int:id_first_msg}, |
||
| 697 | id_last_msg = {int:id_last_msg}, |
||
| 698 | id_member_started = {int:id_member_started}, |
||
| 699 | id_member_updated = {int:id_member_updated}, |
||
| 700 | unapproved_posts = {int:unapproved_posts} |
||
| 701 | WHERE id_topic = {int:id_topic}', |
||
| 702 | array( |
||
| 703 | 'num_replies' => $split1_replies, |
||
| 704 | 'id_first_msg' => $split1_first_msg, |
||
| 705 | 'id_last_msg' => $split1_last_msg, |
||
| 706 | 'id_member_started' => $split1_firstMem, |
||
| 707 | 'id_member_updated' => $split1_lastMem, |
||
| 708 | 'unapproved_posts' => $split1_unapprovedposts, |
||
| 709 | 'id_topic' => $split1_ID_TOPIC, |
||
| 710 | ) |
||
| 711 | ); |
||
| 712 | |||
| 713 | // Now, put the first/last message back to what they should be. |
||
| 714 | $smcFunc['db_query']('', ' |
||
| 715 | UPDATE {db_prefix}topics |
||
| 716 | SET |
||
| 717 | id_first_msg = {int:id_first_msg}, |
||
| 718 | id_last_msg = {int:id_last_msg} |
||
| 719 | WHERE id_topic = {int:id_topic}', |
||
| 720 | array( |
||
| 721 | 'id_first_msg' => $split2_first_msg, |
||
| 722 | 'id_last_msg' => $split2_last_msg, |
||
| 723 | 'id_topic' => $split2_ID_TOPIC, |
||
| 724 | ) |
||
| 725 | ); |
||
| 726 | |||
| 727 | // If the new topic isn't approved ensure the first message flags this just in case. |
||
| 728 | if (!$split2_approved) |
||
| 729 | $smcFunc['db_query']('', ' |
||
| 730 | UPDATE {db_prefix}messages |
||
| 731 | SET approved = {int:approved} |
||
| 732 | WHERE id_msg = {int:id_msg} |
||
| 733 | AND id_topic = {int:id_topic}', |
||
| 734 | array( |
||
| 735 | 'approved' => 0, |
||
| 736 | 'id_msg' => $split2_first_msg, |
||
| 737 | 'id_topic' => $split2_ID_TOPIC, |
||
| 738 | ) |
||
| 739 | ); |
||
| 740 | |||
| 741 | // The board has more topics now (Or more unapproved ones!). |
||
| 742 | $smcFunc['db_query']('', ' |
||
| 743 | UPDATE {db_prefix}boards |
||
| 744 | SET ' . ($split2_approved ? ' |
||
| 745 | num_topics = num_topics + 1' : ' |
||
| 746 | unapproved_topics = unapproved_topics + 1') . ' |
||
| 747 | WHERE id_board = {int:id_board}', |
||
| 748 | array( |
||
| 749 | 'id_board' => $id_board, |
||
| 750 | ) |
||
| 751 | ); |
||
| 752 | |||
| 753 | // Copy log topic entries. |
||
| 754 | // @todo This should really be chunked. |
||
| 755 | $request = $smcFunc['db_query']('', ' |
||
| 756 | SELECT id_member, id_msg, unwatched |
||
| 757 | FROM {db_prefix}log_topics |
||
| 758 | WHERE id_topic = {int:id_topic}', |
||
| 759 | array( |
||
| 760 | 'id_topic' => (int) $split1_ID_TOPIC, |
||
| 761 | ) |
||
| 762 | ); |
||
| 763 | if ($smcFunc['db_num_rows']($request) > 0) |
||
| 764 | { |
||
| 765 | $replaceEntries = array(); |
||
| 766 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 767 | $replaceEntries[] = array($row['id_member'], $split2_ID_TOPIC, $row['id_msg'], $row['unwatched']); |
||
| 768 | |||
| 769 | $smcFunc['db_insert']('ignore', |
||
| 770 | '{db_prefix}log_topics', |
||
| 771 | array('id_member' => 'int', 'id_topic' => 'int', 'id_msg' => 'int', 'unwatched' => 'int'), |
||
| 772 | $replaceEntries, |
||
| 773 | array('id_member', 'id_topic') |
||
| 774 | ); |
||
| 775 | unset($replaceEntries); |
||
| 776 | } |
||
| 777 | $smcFunc['db_free_result']($request); |
||
| 778 | |||
| 779 | // Housekeeping. |
||
| 780 | updateStats('topic'); |
||
| 781 | updateLastMessages($id_board); |
||
| 782 | |||
| 783 | logAction('split', array('topic' => $split1_ID_TOPIC, 'new_topic' => $split2_ID_TOPIC, 'board' => $id_board)); |
||
| 784 | |||
| 785 | // Notify people that this topic has been split? |
||
| 786 | sendNotifications($split1_ID_TOPIC, 'split'); |
||
| 787 | |||
| 788 | // If there's a search index that needs updating, update it... |
||
| 789 | require_once($sourcedir . '/Search.php'); |
||
| 790 | $searchAPI = findSearchAPI(); |
||
| 791 | if (is_callable(array($searchAPI, 'topicSplit'))) |
||
| 792 | $searchAPI->topicSplit($split2_ID_TOPIC, $splitMessages); |
||
|
0 ignored issues
–
show
|
|||
| 793 | |||
| 794 | // Maybe we want to let an external CMS know about this split |
||
| 795 | $split1 = array( |
||
| 796 | 'num_replies' => $split1_replies, |
||
| 797 | 'id_first_msg' => $split1_first_msg, |
||
| 798 | 'id_last_msg' => $split1_last_msg, |
||
| 799 | 'id_member_started' => $split1_firstMem, |
||
| 800 | 'id_member_updated' => $split1_lastMem, |
||
| 801 | 'unapproved_posts' => $split1_unapprovedposts, |
||
| 802 | 'id_topic' => $split1_ID_TOPIC, |
||
| 803 | ); |
||
| 804 | $split2 = array( |
||
| 805 | 'num_replies' => $split2_replies, |
||
| 806 | 'id_first_msg' => $split2_first_msg, |
||
| 807 | 'id_last_msg' => $split2_last_msg, |
||
| 808 | 'id_member_started' => $split2_firstMem, |
||
| 809 | 'id_member_updated' => $split2_lastMem, |
||
| 810 | 'unapproved_posts' => $split2_unapprovedposts, |
||
| 811 | 'id_topic' => $split2_ID_TOPIC, |
||
| 812 | ); |
||
| 813 | call_integration_hook('integrate_split_topic', array($split1, $split2, $new_subject, $id_board)); |
||
| 814 | |||
| 815 | // Return the ID of the newly created topic. |
||
| 816 | return $split2_ID_TOPIC; |
||
| 817 | } |
||
| 818 | |||
| 819 | /** |
||
| 820 | * merges two or more topics into one topic. |
||
| 821 | * delegates to the other functions (based on the URL parameter sa). |
||
| 822 | * loads the SplitTopics template. |
||
| 823 | * requires the merge_any permission. |
||
| 824 | * is accessed with ?action=mergetopics. |
||
| 825 | */ |
||
| 826 | function MergeTopics() |
||
| 827 | { |
||
| 828 | // Load the template.... |
||
| 829 | loadTemplate('MoveTopic'); |
||
| 830 | |||
| 831 | $subActions = array( |
||
| 832 | 'done' => 'MergeDone', |
||
| 833 | 'execute' => 'MergeExecute', |
||
| 834 | 'index' => 'MergeIndex', |
||
| 835 | 'options' => 'MergeExecute', |
||
| 836 | ); |
||
| 837 | |||
| 838 | // ?action=mergetopics;sa=LETSBREAKIT won't work, sorry. |
||
| 839 | if (empty($_REQUEST['sa']) || !isset($subActions[$_REQUEST['sa']])) |
||
| 840 | MergeIndex(); |
||
| 841 | |||
| 842 | else |
||
| 843 | call_helper($subActions[$_REQUEST['sa']]); |
||
| 844 | } |
||
| 845 | |||
| 846 | /** |
||
| 847 | * allows to pick a topic to merge the current topic with. |
||
| 848 | * is accessed with ?action=mergetopics;sa=index |
||
| 849 | * default sub action for ?action=mergetopics. |
||
| 850 | * uses 'merge' sub template of the MoveTopic template. |
||
| 851 | * allows to set a different target board. |
||
| 852 | */ |
||
| 853 | function MergeIndex() |
||
| 854 | { |
||
| 855 | global $txt, $board, $context, $smcFunc, $sourcedir; |
||
| 856 | global $scripturl, $modSettings; |
||
| 857 | |||
| 858 | if (!isset($_GET['from'])) |
||
| 859 | fatal_lang_error('no_access', false); |
||
| 860 | |||
| 861 | $_GET['from'] = (int) $_GET['from']; |
||
| 862 | |||
| 863 | $_REQUEST['targetboard'] = isset($_REQUEST['targetboard']) ? (int) $_REQUEST['targetboard'] : $board; |
||
| 864 | $context['target_board'] = $_REQUEST['targetboard']; |
||
| 865 | |||
| 866 | // Prepare a handy query bit for approval... |
||
| 867 | if ($modSettings['postmod_active']) |
||
| 868 | { |
||
| 869 | $can_approve_boards = boardsAllowedTo('approve_posts'); |
||
| 870 | $onlyApproved = $can_approve_boards !== array(0) && !in_array($_REQUEST['targetboard'], $can_approve_boards); |
||
| 871 | } |
||
| 872 | |||
| 873 | else |
||
| 874 | $onlyApproved = false; |
||
| 875 | |||
| 876 | // How many topics are on this board? (used for paging.) |
||
| 877 | $request = $smcFunc['db_query']('', ' |
||
| 878 | SELECT COUNT(*) |
||
| 879 | FROM {db_prefix}topics AS t |
||
| 880 | WHERE t.id_board = {int:id_board}' . ($onlyApproved ? ' |
||
| 881 | AND t.approved = {int:is_approved}' : ''), |
||
| 882 | array( |
||
| 883 | 'id_board' => $_REQUEST['targetboard'], |
||
| 884 | 'is_approved' => 1, |
||
| 885 | ) |
||
| 886 | ); |
||
| 887 | |||
| 888 | list ($topiccount) = $smcFunc['db_fetch_row']($request); |
||
| 889 | $smcFunc['db_free_result']($request); |
||
| 890 | |||
| 891 | // Make the page list. |
||
| 892 | $context['page_index'] = constructPageIndex($scripturl . '?action=mergetopics;from=' . $_GET['from'] . ';targetboard=' . $_REQUEST['targetboard'] . ';board=' . $board . '.%1$d', $_REQUEST['start'], $topiccount, $modSettings['defaultMaxTopics'], true); |
||
| 893 | |||
| 894 | // Get the topic's subject. |
||
| 895 | $request = $smcFunc['db_query']('', ' |
||
| 896 | SELECT m.subject |
||
| 897 | FROM {db_prefix}topics AS t |
||
| 898 | INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg) |
||
| 899 | WHERE t.id_topic = {int:id_topic} |
||
| 900 | AND t.id_board = {int:current_board}' . ($onlyApproved ? ' |
||
| 901 | AND t.approved = {int:is_approved}' : '') . ' |
||
| 902 | LIMIT 1', |
||
| 903 | array( |
||
| 904 | 'current_board' => $board, |
||
| 905 | 'id_topic' => $_GET['from'], |
||
| 906 | 'is_approved' => 1, |
||
| 907 | ) |
||
| 908 | ); |
||
| 909 | |||
| 910 | if ($smcFunc['db_num_rows']($request) == 0) |
||
| 911 | fatal_lang_error('no_board'); |
||
| 912 | |||
| 913 | list ($subject) = $smcFunc['db_fetch_row']($request); |
||
| 914 | $smcFunc['db_free_result']($request); |
||
| 915 | |||
| 916 | // Tell the template a few things.. |
||
| 917 | $context['origin_topic'] = $_GET['from']; |
||
| 918 | $context['origin_subject'] = $subject; |
||
| 919 | $context['origin_js_subject'] = addcslashes(addslashes($subject), '/'); |
||
| 920 | $context['page_title'] = $txt['merge']; |
||
| 921 | |||
| 922 | // Check which boards you have merge permissions on. |
||
| 923 | $merge_boards = boardsAllowedTo('merge_any'); |
||
| 924 | |||
| 925 | if (empty($merge_boards)) |
||
| 926 | fatal_lang_error('cannot_merge_any', 'user'); |
||
| 927 | |||
| 928 | // No sense in loading this if you can only merge on this board |
||
| 929 | if (count($merge_boards) > 1 || in_array(0, $merge_boards)) |
||
| 930 | { |
||
| 931 | require_once($sourcedir . '/Subs-MessageIndex.php'); |
||
| 932 | |||
| 933 | // Set up a couple of options for our board list |
||
| 934 | $options = array( |
||
| 935 | 'not_redirection' => true, |
||
| 936 | 'selected_board' => $context['target_board'], |
||
| 937 | ); |
||
| 938 | |||
| 939 | // Only include these boards in the list (0 means you're an admin') |
||
| 940 | if (!in_array(0, $merge_boards)) |
||
| 941 | $options['included_boards'] = $merge_boards; |
||
| 942 | |||
| 943 | $context['merge_categories'] = getBoardList($options); |
||
| 944 | } |
||
| 945 | |||
| 946 | // Get some topics to merge it with. |
||
| 947 | $request = $smcFunc['db_query']('', ' |
||
| 948 | SELECT t.id_topic, m.subject, m.id_member, COALESCE(mem.real_name, m.poster_name) AS poster_name |
||
| 949 | FROM {db_prefix}topics AS t |
||
| 950 | INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg) |
||
| 951 | LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member) |
||
| 952 | WHERE t.id_board = {int:id_board} |
||
| 953 | AND t.id_topic != {int:id_topic} |
||
| 954 | AND t.id_redirect_topic = {int:not_redirect}' . ($onlyApproved ? ' |
||
| 955 | AND t.approved = {int:is_approved}' : '') . ' |
||
| 956 | ORDER BY {raw:sort} |
||
| 957 | LIMIT {int:offset}, {int:limit}', |
||
| 958 | array( |
||
| 959 | 'id_board' => $_REQUEST['targetboard'], |
||
| 960 | 'id_topic' => $_GET['from'], |
||
| 961 | 'sort' => 't.is_sticky DESC, t.id_last_msg DESC', |
||
| 962 | 'offset' => $_REQUEST['start'], |
||
| 963 | 'limit' => $modSettings['defaultMaxTopics'], |
||
| 964 | 'is_approved' => 1, |
||
| 965 | 'not_redirect' => 0, |
||
| 966 | ) |
||
| 967 | ); |
||
| 968 | $context['topics'] = array(); |
||
| 969 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 970 | { |
||
| 971 | censorText($row['subject']); |
||
| 972 | |||
| 973 | $context['topics'][] = array( |
||
| 974 | 'id' => $row['id_topic'], |
||
| 975 | 'poster' => array( |
||
| 976 | 'id' => $row['id_member'], |
||
| 977 | 'name' => $row['poster_name'], |
||
| 978 | 'href' => empty($row['id_member']) ? '' : $scripturl . '?action=profile;u=' . $row['id_member'], |
||
| 979 | 'link' => empty($row['id_member']) ? $row['poster_name'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '" target="_blank" rel="noopener">' . $row['poster_name'] . '</a>' |
||
| 980 | ), |
||
| 981 | 'subject' => $row['subject'], |
||
| 982 | 'js_subject' => addcslashes(addslashes($row['subject']), '/') |
||
| 983 | ); |
||
| 984 | } |
||
| 985 | $smcFunc['db_free_result']($request); |
||
| 986 | |||
| 987 | if (empty($context['topics']) && count($merge_boards) <= 1 && !in_array(0, $merge_boards)) |
||
| 988 | fatal_lang_error('merge_need_more_topics'); |
||
| 989 | |||
| 990 | $context['sub_template'] = 'merge'; |
||
| 991 | } |
||
| 992 | |||
| 993 | /** |
||
| 994 | * set merge options and do the actual merge of two or more topics. |
||
| 995 | * |
||
| 996 | * the merge options screen: |
||
| 997 | * * shows topics to be merged and allows to set some merge options. |
||
| 998 | * * is accessed by ?action=mergetopics;sa=options.and can also internally be called by QuickModeration() (Subs-Boards.php). |
||
| 999 | * * uses 'merge_extra_options' sub template of the MoveTopic template. |
||
| 1000 | * |
||
| 1001 | * the actual merge: |
||
| 1002 | * * is accessed with ?action=mergetopics;sa=execute. |
||
| 1003 | * * updates the statistics to reflect the merge. |
||
| 1004 | * * logs the action in the moderation log. |
||
| 1005 | * * sends a notification is sent to all users monitoring this topic. |
||
| 1006 | * * redirects to ?action=mergetopics;sa=done. |
||
| 1007 | * |
||
| 1008 | * @param array $topics The IDs of the topics to merge |
||
| 1009 | */ |
||
| 1010 | function MergeExecute($topics = array()) |
||
| 1011 | { |
||
| 1012 | global $user_info, $txt, $context, $scripturl, $sourcedir; |
||
| 1013 | global $smcFunc, $language, $modSettings; |
||
| 1014 | |||
| 1015 | // Check the session. |
||
| 1016 | checkSession('request'); |
||
| 1017 | |||
| 1018 | // Handle URLs from MergeIndex. |
||
| 1019 | if (!empty($_GET['from']) && !empty($_GET['to'])) |
||
| 1020 | $topics = array((int) $_GET['from'], (int) $_GET['to']); |
||
| 1021 | |||
| 1022 | // If we came from a form, the topic IDs came by post. |
||
| 1023 | if (!empty($_POST['topics']) && is_array($_POST['topics'])) |
||
| 1024 | $topics = $_POST['topics']; |
||
| 1025 | |||
| 1026 | // There's nothing to merge with just one topic... |
||
| 1027 | if (empty($topics) || !is_array($topics) || count($topics) == 1) |
||
| 1028 | fatal_lang_error('merge_need_more_topics'); |
||
| 1029 | |||
| 1030 | // Make sure every topic is numeric, or some nasty things could be done with the DB. |
||
| 1031 | foreach ($topics as $id => $topic) |
||
| 1032 | $topics[$id] = (int) $topic; |
||
| 1033 | |||
| 1034 | // Joy of all joys, make sure they're not messing about with unapproved topics they can't see :P |
||
| 1035 | if ($modSettings['postmod_active']) |
||
| 1036 | $can_approve_boards = boardsAllowedTo('approve_posts'); |
||
| 1037 | |||
| 1038 | // Get info about the topics and polls that will be merged. |
||
| 1039 | $request = $smcFunc['db_query']('', ' |
||
| 1040 | SELECT |
||
| 1041 | t.id_topic, t.id_board, t.id_poll, t.num_views, t.is_sticky, t.approved, t.num_replies, t.unapproved_posts, t.id_redirect_topic, |
||
| 1042 | m1.subject, m1.poster_time AS time_started, COALESCE(mem1.id_member, 0) AS id_member_started, COALESCE(mem1.real_name, m1.poster_name) AS name_started, |
||
| 1043 | m2.poster_time AS time_updated, COALESCE(mem2.id_member, 0) AS id_member_updated, COALESCE(mem2.real_name, m2.poster_name) AS name_updated |
||
| 1044 | FROM {db_prefix}topics AS t |
||
| 1045 | INNER JOIN {db_prefix}messages AS m1 ON (m1.id_msg = t.id_first_msg) |
||
| 1046 | INNER JOIN {db_prefix}messages AS m2 ON (m2.id_msg = t.id_last_msg) |
||
| 1047 | LEFT JOIN {db_prefix}members AS mem1 ON (mem1.id_member = m1.id_member) |
||
| 1048 | LEFT JOIN {db_prefix}members AS mem2 ON (mem2.id_member = m2.id_member) |
||
| 1049 | WHERE t.id_topic IN ({array_int:topic_list}) |
||
| 1050 | ORDER BY t.id_first_msg |
||
| 1051 | LIMIT {int:limit}', |
||
| 1052 | array( |
||
| 1053 | 'topic_list' => $topics, |
||
| 1054 | 'limit' => count($topics), |
||
| 1055 | ) |
||
| 1056 | ); |
||
| 1057 | if ($smcFunc['db_num_rows']($request) < 2) |
||
| 1058 | fatal_lang_error('no_topic_id'); |
||
| 1059 | |||
| 1060 | $num_views = 0; |
||
| 1061 | $is_sticky = 0; |
||
| 1062 | $boardTotals = array(); |
||
| 1063 | $boards = array(); |
||
| 1064 | $polls = array(); |
||
| 1065 | $firstTopic = 0; |
||
| 1066 | $context['is_approved'] = 1; |
||
| 1067 | $lowestTopicId = 0; |
||
| 1068 | $lowestTopicBoard = 0; |
||
| 1069 | |||
| 1070 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 1071 | { |
||
| 1072 | // Sorry, redirection topics can't be merged |
||
| 1073 | if (!empty($row['id_redirect_topic'])) |
||
| 1074 | fatal_lang_error('cannot_merge_redirect', false); |
||
| 1075 | |||
| 1076 | // Make a note for the board counts... |
||
| 1077 | if (!isset($boardTotals[$row['id_board']])) |
||
| 1078 | $boardTotals[$row['id_board']] = array( |
||
| 1079 | 'posts' => 0, |
||
| 1080 | 'topics' => 0, |
||
| 1081 | 'unapproved_posts' => 0, |
||
| 1082 | 'unapproved_topics' => 0 |
||
| 1083 | ); |
||
| 1084 | |||
| 1085 | // We can't see unapproved topics here? |
||
| 1086 | if ($modSettings['postmod_active'] && !$row['approved'] && $can_approve_boards != array(0) && in_array($row['id_board'], $can_approve_boards)) |
||
| 1087 | { |
||
| 1088 | unset($topics[$row['id_topic']]); // If we can't see it, we should not merge it and not adjust counts! Instead skip it. |
||
| 1089 | continue; |
||
| 1090 | } |
||
| 1091 | elseif (!$row['approved']) |
||
| 1092 | $boardTotals[$row['id_board']]['unapproved_topics']++; |
||
| 1093 | else |
||
| 1094 | $boardTotals[$row['id_board']]['topics']++; |
||
| 1095 | |||
| 1096 | $boardTotals[$row['id_board']]['unapproved_posts'] += $row['unapproved_posts']; |
||
| 1097 | $boardTotals[$row['id_board']]['posts'] += $row['num_replies'] + ($row['approved'] ? 1 : 0); |
||
| 1098 | |||
| 1099 | // In the case of making a redirect, the topic count goes up by one due to the redirect topic. |
||
| 1100 | if (isset($_POST['postRedirect'])) |
||
| 1101 | $boardTotals[$row['id_board']]['topics']--; |
||
| 1102 | |||
| 1103 | $topic_data[$row['id_topic']] = array( |
||
| 1104 | 'id' => $row['id_topic'], |
||
| 1105 | 'board' => $row['id_board'], |
||
| 1106 | 'poll' => $row['id_poll'], |
||
| 1107 | 'num_views' => $row['num_views'], |
||
| 1108 | 'subject' => $row['subject'], |
||
| 1109 | 'started' => array( |
||
| 1110 | 'time' => timeformat($row['time_started']), |
||
| 1111 | 'timestamp' => forum_time(true, $row['time_started']), |
||
| 1112 | 'href' => empty($row['id_member_started']) ? '' : $scripturl . '?action=profile;u=' . $row['id_member_started'], |
||
| 1113 | 'link' => empty($row['id_member_started']) ? $row['name_started'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member_started'] . '">' . $row['name_started'] . '</a>' |
||
| 1114 | ), |
||
| 1115 | 'updated' => array( |
||
| 1116 | 'time' => timeformat($row['time_updated']), |
||
| 1117 | 'timestamp' => forum_time(true, $row['time_updated']), |
||
| 1118 | 'href' => empty($row['id_member_updated']) ? '' : $scripturl . '?action=profile;u=' . $row['id_member_updated'], |
||
| 1119 | 'link' => empty($row['id_member_updated']) ? $row['name_updated'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member_updated'] . '">' . $row['name_updated'] . '</a>' |
||
| 1120 | ), |
||
| 1121 | 'approved' => $row['approved'] |
||
| 1122 | ); |
||
| 1123 | $num_views += $row['num_views']; |
||
| 1124 | $boards[] = $row['id_board']; |
||
| 1125 | |||
| 1126 | // If there's no poll, id_poll == 0... |
||
| 1127 | if ($row['id_poll'] > 0) |
||
| 1128 | $polls[] = $row['id_poll']; |
||
| 1129 | // Store the id_topic with the lowest id_first_msg. |
||
| 1130 | if (empty($firstTopic)) |
||
| 1131 | $firstTopic = $row['id_topic']; |
||
| 1132 | |||
| 1133 | // Lowest topic id gets selected as surviving topic id. We need to store this board so we can adjust the topic count (This one will not have a redirect topic) |
||
| 1134 | if ($row['id_topic'] < $lowestTopicId || empty($lowestTopicId)) |
||
| 1135 | { |
||
| 1136 | $lowestTopicId = $row['id_topic']; |
||
| 1137 | $lowestTopicBoard = $row['id_board']; |
||
| 1138 | } |
||
| 1139 | |||
| 1140 | $is_sticky = max($is_sticky, $row['is_sticky']); |
||
| 1141 | } |
||
| 1142 | $smcFunc['db_free_result']($request); |
||
| 1143 | |||
| 1144 | // If we didn't get any topics then they've been messing with unapproved stuff. |
||
| 1145 | if (empty($topic_data)) |
||
| 1146 | fatal_lang_error('no_topic_id'); |
||
| 1147 | |||
| 1148 | if (isset($_POST['postRedirect']) && !empty($lowestTopicBoard)) |
||
| 1149 | $boardTotals[$lowestTopicBoard]['topics']++; |
||
| 1150 | |||
| 1151 | // Will this be approved? |
||
| 1152 | $context['is_approved'] = $topic_data[$firstTopic]['approved']; |
||
| 1153 | |||
| 1154 | $boards = array_values(array_unique($boards)); |
||
| 1155 | |||
| 1156 | // The parameters of MergeExecute were set, so this must've been an internal call. |
||
| 1157 | if (!empty($topics)) |
||
| 1158 | { |
||
| 1159 | isAllowedTo('merge_any', $boards); |
||
| 1160 | loadTemplate('MoveTopic'); |
||
| 1161 | } |
||
| 1162 | |||
| 1163 | // Get the boards a user is allowed to merge in. |
||
| 1164 | $merge_boards = boardsAllowedTo('merge_any'); |
||
| 1165 | if (empty($merge_boards)) |
||
| 1166 | fatal_lang_error('cannot_merge_any', 'user'); |
||
| 1167 | |||
| 1168 | // Make sure they can see all boards.... |
||
| 1169 | $request = $smcFunc['db_query']('', ' |
||
| 1170 | SELECT b.id_board |
||
| 1171 | FROM {db_prefix}boards AS b |
||
| 1172 | WHERE b.id_board IN ({array_int:boards}) |
||
| 1173 | AND {query_see_board}' . (!in_array(0, $merge_boards) ? ' |
||
| 1174 | AND b.id_board IN ({array_int:merge_boards})' : '') . ' |
||
| 1175 | LIMIT {int:limit}', |
||
| 1176 | array( |
||
| 1177 | 'boards' => $boards, |
||
| 1178 | 'merge_boards' => $merge_boards, |
||
| 1179 | 'limit' => count($boards), |
||
| 1180 | ) |
||
| 1181 | ); |
||
| 1182 | // If the number of boards that's in the output isn't exactly the same as we've put in there, you're in trouble. |
||
| 1183 | if ($smcFunc['db_num_rows']($request) != count($boards)) |
||
| 1184 | fatal_lang_error('no_board'); |
||
| 1185 | $smcFunc['db_free_result']($request); |
||
| 1186 | |||
| 1187 | if (empty($_REQUEST['sa']) || $_REQUEST['sa'] == 'options') |
||
| 1188 | { |
||
| 1189 | if (count($polls) > 1) |
||
| 1190 | { |
||
| 1191 | $request = $smcFunc['db_query']('', ' |
||
| 1192 | SELECT t.id_topic, t.id_poll, m.subject, p.question |
||
| 1193 | FROM {db_prefix}polls AS p |
||
| 1194 | INNER JOIN {db_prefix}topics AS t ON (t.id_poll = p.id_poll) |
||
| 1195 | INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg) |
||
| 1196 | WHERE p.id_poll IN ({array_int:polls}) |
||
| 1197 | LIMIT {int:limit}', |
||
| 1198 | array( |
||
| 1199 | 'polls' => $polls, |
||
| 1200 | 'limit' => count($polls), |
||
| 1201 | ) |
||
| 1202 | ); |
||
| 1203 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 1204 | $context['polls'][] = array( |
||
| 1205 | 'id' => $row['id_poll'], |
||
| 1206 | 'topic' => array( |
||
| 1207 | 'id' => $row['id_topic'], |
||
| 1208 | 'subject' => $row['subject'] |
||
| 1209 | ), |
||
| 1210 | 'question' => $row['question'], |
||
| 1211 | 'selected' => $row['id_topic'] == $firstTopic |
||
| 1212 | ); |
||
| 1213 | $smcFunc['db_free_result']($request); |
||
| 1214 | } |
||
| 1215 | if (count($boards) > 1) |
||
| 1216 | { |
||
| 1217 | $request = $smcFunc['db_query']('', ' |
||
| 1218 | SELECT id_board, name |
||
| 1219 | FROM {db_prefix}boards |
||
| 1220 | WHERE id_board IN ({array_int:boards}) |
||
| 1221 | ORDER BY name |
||
| 1222 | LIMIT {int:limit}', |
||
| 1223 | array( |
||
| 1224 | 'boards' => $boards, |
||
| 1225 | 'limit' => count($boards), |
||
| 1226 | ) |
||
| 1227 | ); |
||
| 1228 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 1229 | $context['boards'][] = array( |
||
| 1230 | 'id' => $row['id_board'], |
||
| 1231 | 'name' => $row['name'], |
||
| 1232 | 'selected' => $row['id_board'] == $topic_data[$firstTopic]['board'] |
||
| 1233 | ); |
||
| 1234 | $smcFunc['db_free_result']($request); |
||
| 1235 | } |
||
| 1236 | |||
| 1237 | $context['topics'] = $topic_data; |
||
| 1238 | foreach ($topic_data as $id => $topic) |
||
| 1239 | $context['topics'][$id]['selected'] = $topic['id'] == $firstTopic; |
||
| 1240 | |||
| 1241 | $context['page_title'] = $txt['merge']; |
||
| 1242 | $context['sub_template'] = 'merge_extra_options'; |
||
| 1243 | return; |
||
| 1244 | } |
||
| 1245 | |||
| 1246 | // Determine target board. |
||
| 1247 | $target_board = count($boards) > 1 ? (int) $_REQUEST['board'] : $boards[0]; |
||
| 1248 | if (!in_array($target_board, $boards)) |
||
| 1249 | fatal_lang_error('no_board'); |
||
| 1250 | |||
| 1251 | // Determine which poll will survive and which polls won't. |
||
| 1252 | $target_poll = count($polls) > 1 ? (int) $_POST['poll'] : (count($polls) == 1 ? $polls[0] : 0); |
||
| 1253 | if ($target_poll > 0 && !in_array($target_poll, $polls)) |
||
| 1254 | fatal_lang_error('no_access', false); |
||
| 1255 | $deleted_polls = empty($target_poll) ? $polls : array_diff($polls, array($target_poll)); |
||
| 1256 | |||
| 1257 | // Determine the subject of the newly merged topic - was a custom subject specified? |
||
| 1258 | if (empty($_POST['subject']) && isset($_POST['custom_subject']) && $_POST['custom_subject'] != '') |
||
| 1259 | { |
||
| 1260 | $target_subject = strtr($smcFunc['htmltrim']($smcFunc['htmlspecialchars']($_POST['custom_subject'])), array("\r" => '', "\n" => '', "\t" => '')); |
||
| 1261 | // Keep checking the length. |
||
| 1262 | if ($smcFunc['strlen']($target_subject) > 100) |
||
| 1263 | $target_subject = $smcFunc['substr']($target_subject, 0, 100); |
||
| 1264 | |||
| 1265 | // Nothing left - odd but pick the first topics subject. |
||
| 1266 | if ($target_subject == '') |
||
| 1267 | $target_subject = $topic_data[$firstTopic]['subject']; |
||
| 1268 | } |
||
| 1269 | // A subject was selected from the list. |
||
| 1270 | elseif (!empty($topic_data[(int) $_POST['subject']]['subject'])) |
||
| 1271 | $target_subject = $topic_data[(int) $_POST['subject']]['subject']; |
||
| 1272 | // Nothing worked? Just take the subject of the first message. |
||
| 1273 | else |
||
| 1274 | $target_subject = $topic_data[$firstTopic]['subject']; |
||
| 1275 | |||
| 1276 | // Get the first and last message and the number of messages.... |
||
| 1277 | $request = $smcFunc['db_query']('', ' |
||
| 1278 | SELECT approved, MIN(id_msg) AS first_msg, MAX(id_msg) AS last_msg, COUNT(*) AS message_count |
||
| 1279 | FROM {db_prefix}messages |
||
| 1280 | WHERE id_topic IN ({array_int:topics}) |
||
| 1281 | GROUP BY approved |
||
| 1282 | ORDER BY approved DESC', |
||
| 1283 | array( |
||
| 1284 | 'topics' => $topics, |
||
| 1285 | ) |
||
| 1286 | ); |
||
| 1287 | $topic_approved = 1; |
||
| 1288 | $first_msg = 0; |
||
| 1289 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 1290 | { |
||
| 1291 | // If this is approved, or is fully unapproved. |
||
| 1292 | if ($row['approved'] || !empty($first_msg)) |
||
| 1293 | { |
||
| 1294 | $first_msg = $row['first_msg']; |
||
| 1295 | $last_msg = $row['last_msg']; |
||
| 1296 | if ($row['approved']) |
||
| 1297 | { |
||
| 1298 | $num_replies = $row['message_count'] - 1; |
||
| 1299 | $num_unapproved = 0; |
||
| 1300 | } |
||
| 1301 | else |
||
| 1302 | { |
||
| 1303 | $topic_approved = 0; |
||
| 1304 | $num_replies = 0; |
||
| 1305 | $num_unapproved = $row['message_count']; |
||
| 1306 | } |
||
| 1307 | } |
||
| 1308 | else |
||
| 1309 | { |
||
| 1310 | // If this has a lower first_msg then the first post is not approved and hence the number of replies was wrong! |
||
| 1311 | if ($first_msg > $row['first_msg']) |
||
| 1312 | { |
||
| 1313 | $first_msg = $row['first_msg']; |
||
| 1314 | $num_replies++; |
||
| 1315 | $topic_approved = 0; |
||
| 1316 | } |
||
| 1317 | $num_unapproved = $row['message_count']; |
||
| 1318 | } |
||
| 1319 | } |
||
| 1320 | $smcFunc['db_free_result']($request); |
||
| 1321 | |||
| 1322 | // Ensure we have a board stat for the target board. |
||
| 1323 | if (!isset($boardTotals[$target_board])) |
||
| 1324 | { |
||
| 1325 | $boardTotals[$target_board] = array( |
||
| 1326 | 'posts' => 0, |
||
| 1327 | 'topics' => 0, |
||
| 1328 | 'unapproved_posts' => 0, |
||
| 1329 | 'unapproved_topics' => 0 |
||
| 1330 | ); |
||
| 1331 | } |
||
| 1332 | |||
| 1333 | // Fix the topic count stuff depending on what the new one counts as. |
||
| 1334 | $boardTotals[$target_board][(!$topic_approved) ? 'unapproved_topics' : 'topics']--; |
||
| 1335 | |||
| 1336 | $boardTotals[$target_board]['unapproved_posts'] -= $num_unapproved; |
||
| 1337 | $boardTotals[$target_board]['posts'] -= $topic_approved ? $num_replies + 1 : $num_replies; |
||
| 1338 | |||
| 1339 | // Get the member ID of the first and last message. |
||
| 1340 | $request = $smcFunc['db_query']('', ' |
||
| 1341 | SELECT id_member |
||
| 1342 | FROM {db_prefix}messages |
||
| 1343 | WHERE id_msg IN ({int:first_msg}, {int:last_msg}) |
||
| 1344 | ORDER BY id_msg |
||
| 1345 | LIMIT 2', |
||
| 1346 | array( |
||
| 1347 | 'first_msg' => $first_msg, |
||
| 1348 | 'last_msg' => $last_msg, |
||
| 1349 | ) |
||
| 1350 | ); |
||
| 1351 | list ($member_started) = $smcFunc['db_fetch_row']($request); |
||
| 1352 | list ($member_updated) = $smcFunc['db_fetch_row']($request); |
||
| 1353 | |||
| 1354 | // First and last message are the same, so only row was returned. |
||
| 1355 | if ($member_updated === null) |
||
| 1356 | $member_updated = $member_started; |
||
| 1357 | |||
| 1358 | $smcFunc['db_free_result']($request); |
||
| 1359 | |||
| 1360 | // Obtain all the message ids we are going to affect. |
||
| 1361 | $affected_msgs = array(); |
||
| 1362 | $request = $smcFunc['db_query']('', ' |
||
| 1363 | SELECT id_msg |
||
| 1364 | FROM {db_prefix}messages |
||
| 1365 | WHERE id_topic IN ({array_int:topic_list})', |
||
| 1366 | array( |
||
| 1367 | 'topic_list' => $topics, |
||
| 1368 | ) |
||
| 1369 | ); |
||
| 1370 | while ($row = $smcFunc['db_fetch_row']($request)) |
||
| 1371 | $affected_msgs[] = $row[0]; |
||
| 1372 | $smcFunc['db_free_result']($request); |
||
| 1373 | |||
| 1374 | // Assign the first topic ID to be the merged topic. |
||
| 1375 | $id_topic = min($topics); |
||
| 1376 | |||
| 1377 | $deleted_topics = array_diff($topics, array($id_topic)); |
||
| 1378 | $updated_topics = array(); |
||
| 1379 | |||
| 1380 | // Create stub topics out of the remaining topics. |
||
| 1381 | // We don't want the search index data though (For non-redirect merges). |
||
| 1382 | if (!isset($_POST['postRedirect'])) |
||
| 1383 | { |
||
| 1384 | $smcFunc['db_query']('', ' |
||
| 1385 | DELETE FROM {db_prefix}log_search_subjects |
||
| 1386 | WHERE id_topic IN ({array_int:deleted_topics})', |
||
| 1387 | array( |
||
| 1388 | 'deleted_topics' => $deleted_topics, |
||
| 1389 | ) |
||
| 1390 | ); |
||
| 1391 | } |
||
| 1392 | |||
| 1393 | require_once($sourcedir . '/Subs-Post.php'); |
||
| 1394 | $posterOptions = array( |
||
| 1395 | 'id' => $user_info['id'], |
||
| 1396 | 'update_post_count' => false, |
||
| 1397 | ); |
||
| 1398 | |||
| 1399 | // We only need to do this if we're posting redirection topics... |
||
| 1400 | if (isset($_POST['postRedirect'])) |
||
| 1401 | { |
||
| 1402 | $_POST['reason'] = $smcFunc['htmlspecialchars']($_POST['reason'], ENT_QUOTES); |
||
| 1403 | preparsecode($_POST['reason']); |
||
| 1404 | |||
| 1405 | // Add a URL onto the message. |
||
| 1406 | $reason = strtr($_POST['reason'], array( |
||
| 1407 | $txt['movetopic_auto_topic'] => '[iurl=' . $scripturl . '?topic=' . $id_topic . '.0]' . $target_subject . '[/iurl]' |
||
| 1408 | )); |
||
| 1409 | |||
| 1410 | // Automatically remove this MERGED redirection topic in the future? |
||
| 1411 | $redirect_expires = !empty($_POST['redirect_expires']) ? ((int) ($_POST['redirect_expires'] * 60) + time()) : 0; |
||
| 1412 | |||
| 1413 | // Redirect to the MERGED topic from topic list? |
||
| 1414 | $redirect_topic = isset($_POST['redirect_topic']) ? $id_topic : 0; |
||
| 1415 | |||
| 1416 | foreach ($deleted_topics as $this_old_topic) |
||
| 1417 | { |
||
| 1418 | $redirect_subject = sprintf($txt['merged_subject'], $topic_data[$this_old_topic]['subject']); |
||
| 1419 | |||
| 1420 | $msgOptions = array( |
||
| 1421 | 'icon' => 'moved', |
||
| 1422 | 'subject' => $redirect_subject, |
||
| 1423 | 'body' => $reason, |
||
| 1424 | 'approved' => 1, |
||
| 1425 | ); |
||
| 1426 | $topicOptions = array( |
||
| 1427 | 'id' => $this_old_topic, |
||
| 1428 | 'is_approved' => true, |
||
| 1429 | 'lock_mode' => 1, |
||
| 1430 | 'board' => $topic_data[$this_old_topic]['board'], |
||
| 1431 | 'mark_as_read' => true, |
||
| 1432 | ); |
||
| 1433 | |||
| 1434 | // So we have to make the post. We need to do *this* here so we don't foul up indexes later |
||
| 1435 | // and we have to fix them up later once everything else has happened. |
||
| 1436 | if (createPost($msgOptions, $topicOptions, $posterOptions)) |
||
| 1437 | { |
||
| 1438 | $updated_topics[$this_old_topic] = $msgOptions['id']; |
||
| 1439 | } |
||
| 1440 | |||
| 1441 | // Update subject search index |
||
| 1442 | updateStats('subject', $this_old_topic, $redirect_subject); |
||
| 1443 | } |
||
| 1444 | } |
||
| 1445 | |||
| 1446 | // Grab the response prefix (like 'Re: ') in the default forum language. |
||
| 1447 | if (!isset($context['response_prefix']) && !($context['response_prefix'] = cache_get_data('response_prefix'))) |
||
| 1448 | { |
||
| 1449 | if ($language === $user_info['language']) |
||
| 1450 | $context['response_prefix'] = $txt['response_prefix']; |
||
| 1451 | else |
||
| 1452 | { |
||
| 1453 | loadLanguage('index', $language, false); |
||
| 1454 | $context['response_prefix'] = $txt['response_prefix']; |
||
| 1455 | loadLanguage('index'); |
||
| 1456 | } |
||
| 1457 | cache_put_data('response_prefix', $context['response_prefix'], 600); |
||
| 1458 | } |
||
| 1459 | |||
| 1460 | // Change the topic IDs of all messages that will be merged. Also adjust subjects if 'enforce subject' was checked. |
||
| 1461 | $smcFunc['db_query']('', ' |
||
| 1462 | UPDATE {db_prefix}messages |
||
| 1463 | SET |
||
| 1464 | id_topic = {int:id_topic}, |
||
| 1465 | id_board = {int:target_board}' . (empty($_POST['enforce_subject']) ? '' : ', |
||
| 1466 | subject = {string:subject}') . ' |
||
| 1467 | WHERE id_topic IN ({array_int:topic_list})' . (!empty($updated_topics) ? ' |
||
| 1468 | AND id_msg NOT IN ({array_int:merge_msg})' : ''), |
||
| 1469 | array( |
||
| 1470 | 'topic_list' => $topics, |
||
| 1471 | 'id_topic' => $id_topic, |
||
| 1472 | 'merge_msg' => $updated_topics, |
||
| 1473 | 'target_board' => $target_board, |
||
| 1474 | 'subject' => $context['response_prefix'] . $target_subject, |
||
| 1475 | ) |
||
| 1476 | ); |
||
| 1477 | |||
| 1478 | // Any reported posts should reflect the new board. |
||
| 1479 | $smcFunc['db_query']('', ' |
||
| 1480 | UPDATE {db_prefix}log_reported |
||
| 1481 | SET |
||
| 1482 | id_topic = {int:id_topic}, |
||
| 1483 | id_board = {int:target_board} |
||
| 1484 | WHERE id_topic IN ({array_int:topics_list})', |
||
| 1485 | array( |
||
| 1486 | 'topics_list' => $topics, |
||
| 1487 | 'id_topic' => $id_topic, |
||
| 1488 | 'target_board' => $target_board, |
||
| 1489 | ) |
||
| 1490 | ); |
||
| 1491 | |||
| 1492 | // Change the subject of the first message... |
||
| 1493 | $smcFunc['db_query']('', ' |
||
| 1494 | UPDATE {db_prefix}messages |
||
| 1495 | SET subject = {string:target_subject} |
||
| 1496 | WHERE id_msg = {int:first_msg}', |
||
| 1497 | array( |
||
| 1498 | 'first_msg' => $first_msg, |
||
| 1499 | 'target_subject' => $target_subject, |
||
| 1500 | ) |
||
| 1501 | ); |
||
| 1502 | |||
| 1503 | // Adjust all calendar events to point to the new topic. |
||
| 1504 | $smcFunc['db_query']('', ' |
||
| 1505 | UPDATE {db_prefix}calendar |
||
| 1506 | SET |
||
| 1507 | id_topic = {int:id_topic}, |
||
| 1508 | id_board = {int:target_board} |
||
| 1509 | WHERE id_topic IN ({array_int:deleted_topics})', |
||
| 1510 | array( |
||
| 1511 | 'deleted_topics' => $deleted_topics, |
||
| 1512 | 'id_topic' => $id_topic, |
||
| 1513 | 'target_board' => $target_board, |
||
| 1514 | ) |
||
| 1515 | ); |
||
| 1516 | |||
| 1517 | // Merge log topic entries. |
||
| 1518 | // The unwatch setting comes from the oldest topic |
||
| 1519 | $request = $smcFunc['db_query']('', ' |
||
| 1520 | SELECT id_member, MIN(id_msg) AS new_id_msg, unwatched |
||
| 1521 | FROM {db_prefix}log_topics |
||
| 1522 | WHERE id_topic IN ({array_int:topics}) |
||
| 1523 | GROUP BY id_member, unwatched', |
||
| 1524 | array( |
||
| 1525 | 'topics' => $topics, |
||
| 1526 | ) |
||
| 1527 | ); |
||
| 1528 | if ($smcFunc['db_num_rows']($request) > 0) |
||
| 1529 | { |
||
| 1530 | $replaceEntries = array(); |
||
| 1531 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 1532 | $replaceEntries[] = array($row['id_member'], $id_topic, $row['new_id_msg'], $row['unwatched']); |
||
| 1533 | |||
| 1534 | $smcFunc['db_insert']('replace', |
||
| 1535 | '{db_prefix}log_topics', |
||
| 1536 | array('id_member' => 'int', 'id_topic' => 'int', 'id_msg' => 'int', 'unwatched' => 'int'), |
||
| 1537 | $replaceEntries, |
||
| 1538 | array('id_member', 'id_topic') |
||
| 1539 | ); |
||
| 1540 | unset($replaceEntries); |
||
| 1541 | |||
| 1542 | // Get rid of the old log entries. |
||
| 1543 | $smcFunc['db_query']('', ' |
||
| 1544 | DELETE FROM {db_prefix}log_topics |
||
| 1545 | WHERE id_topic IN ({array_int:deleted_topics})', |
||
| 1546 | array( |
||
| 1547 | 'deleted_topics' => $deleted_topics, |
||
| 1548 | ) |
||
| 1549 | ); |
||
| 1550 | } |
||
| 1551 | $smcFunc['db_free_result']($request); |
||
| 1552 | |||
| 1553 | // Merge topic notifications. |
||
| 1554 | $notifications = isset($_POST['notifications']) && is_array($_POST['notifications']) ? array_intersect($topics, $_POST['notifications']) : array(); |
||
| 1555 | if (!empty($notifications)) |
||
| 1556 | { |
||
| 1557 | $request = $smcFunc['db_query']('', ' |
||
| 1558 | SELECT id_member, MAX(sent) AS sent |
||
| 1559 | FROM {db_prefix}log_notify |
||
| 1560 | WHERE id_topic IN ({array_int:topics_list}) |
||
| 1561 | GROUP BY id_member', |
||
| 1562 | array( |
||
| 1563 | 'topics_list' => $notifications, |
||
| 1564 | ) |
||
| 1565 | ); |
||
| 1566 | if ($smcFunc['db_num_rows']($request) > 0) |
||
| 1567 | { |
||
| 1568 | $replaceEntries = array(); |
||
| 1569 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 1570 | $replaceEntries[] = array($row['id_member'], $id_topic, 0, $row['sent']); |
||
| 1571 | |||
| 1572 | $smcFunc['db_insert']('replace', |
||
| 1573 | '{db_prefix}log_notify', |
||
| 1574 | array('id_member' => 'int', 'id_topic' => 'int', 'id_board' => 'int', 'sent' => 'int'), |
||
| 1575 | $replaceEntries, |
||
| 1576 | array('id_member', 'id_topic', 'id_board') |
||
| 1577 | ); |
||
| 1578 | unset($replaceEntries); |
||
| 1579 | |||
| 1580 | $smcFunc['db_query']('', ' |
||
| 1581 | DELETE FROM {db_prefix}log_topics |
||
| 1582 | WHERE id_topic IN ({array_int:deleted_topics})', |
||
| 1583 | array( |
||
| 1584 | 'deleted_topics' => $deleted_topics, |
||
| 1585 | ) |
||
| 1586 | ); |
||
| 1587 | } |
||
| 1588 | $smcFunc['db_free_result']($request); |
||
| 1589 | } |
||
| 1590 | |||
| 1591 | // Get rid of the redundant polls. |
||
| 1592 | if (!empty($deleted_polls)) |
||
| 1593 | { |
||
| 1594 | $smcFunc['db_query']('', ' |
||
| 1595 | DELETE FROM {db_prefix}polls |
||
| 1596 | WHERE id_poll IN ({array_int:deleted_polls})', |
||
| 1597 | array( |
||
| 1598 | 'deleted_polls' => $deleted_polls, |
||
| 1599 | ) |
||
| 1600 | ); |
||
| 1601 | $smcFunc['db_query']('', ' |
||
| 1602 | DELETE FROM {db_prefix}poll_choices |
||
| 1603 | WHERE id_poll IN ({array_int:deleted_polls})', |
||
| 1604 | array( |
||
| 1605 | 'deleted_polls' => $deleted_polls, |
||
| 1606 | ) |
||
| 1607 | ); |
||
| 1608 | $smcFunc['db_query']('', ' |
||
| 1609 | DELETE FROM {db_prefix}log_polls |
||
| 1610 | WHERE id_poll IN ({array_int:deleted_polls})', |
||
| 1611 | array( |
||
| 1612 | 'deleted_polls' => $deleted_polls, |
||
| 1613 | ) |
||
| 1614 | ); |
||
| 1615 | } |
||
| 1616 | |||
| 1617 | // Cycle through each board... |
||
| 1618 | foreach ($boardTotals as $id_board => $stats) |
||
| 1619 | { |
||
| 1620 | $smcFunc['db_query']('', ' |
||
| 1621 | UPDATE {db_prefix}boards |
||
| 1622 | SET |
||
| 1623 | num_topics = CASE WHEN {int:topics} > num_topics THEN 0 ELSE num_topics - {int:topics} END, |
||
| 1624 | unapproved_topics = CASE WHEN {int:unapproved_topics} > unapproved_topics THEN 0 ELSE unapproved_topics - {int:unapproved_topics} END, |
||
| 1625 | num_posts = CASE WHEN {int:posts} > num_posts THEN 0 ELSE num_posts - {int:posts} END, |
||
| 1626 | unapproved_posts = CASE WHEN {int:unapproved_posts} > unapproved_posts THEN 0 ELSE unapproved_posts - {int:unapproved_posts} END |
||
| 1627 | WHERE id_board = {int:id_board}', |
||
| 1628 | array( |
||
| 1629 | 'id_board' => $id_board, |
||
| 1630 | 'topics' => $stats['topics'], |
||
| 1631 | 'unapproved_topics' => $stats['unapproved_topics'], |
||
| 1632 | 'posts' => $stats['posts'], |
||
| 1633 | 'unapproved_posts' => $stats['unapproved_posts'], |
||
| 1634 | ) |
||
| 1635 | ); |
||
| 1636 | } |
||
| 1637 | |||
| 1638 | // Determine the board the final topic resides in |
||
| 1639 | $request = $smcFunc['db_query']('', ' |
||
| 1640 | SELECT id_board |
||
| 1641 | FROM {db_prefix}topics |
||
| 1642 | WHERE id_topic = {int:id_topic} |
||
| 1643 | LIMIT 1', |
||
| 1644 | array( |
||
| 1645 | 'id_topic' => $id_topic, |
||
| 1646 | ) |
||
| 1647 | ); |
||
| 1648 | list($id_board) = $smcFunc['db_fetch_row']($request); |
||
| 1649 | $smcFunc['db_free_result']($request); |
||
| 1650 | |||
| 1651 | // Again, only do this if we're redirecting - otherwise delete |
||
| 1652 | if (isset($_POST['postRedirect'])) |
||
| 1653 | { |
||
| 1654 | // Having done all that, now make sure we fix the merge/redirect topics upp before we |
||
| 1655 | // leave here. Specifically: that there are no replies, no unapproved stuff, that the first |
||
| 1656 | // and last posts are the same and so on and so forth. |
||
| 1657 | foreach ($updated_topics as $old_topic => $id_msg) |
||
| 1658 | { |
||
| 1659 | $smcFunc['db_query']('', ' |
||
| 1660 | UPDATE {db_prefix}topics |
||
| 1661 | SET id_first_msg = id_last_msg, |
||
| 1662 | id_member_started = {int:current_user}, |
||
| 1663 | id_member_updated = {int:current_user}, |
||
| 1664 | id_poll = 0, |
||
| 1665 | approved = 1, |
||
| 1666 | num_replies = 0, |
||
| 1667 | unapproved_posts = 0, |
||
| 1668 | id_redirect_topic = {int:redirect_topic}, |
||
| 1669 | redirect_expires = {int:redirect_expires} |
||
| 1670 | WHERE id_topic = {int:old_topic}', |
||
| 1671 | array( |
||
| 1672 | 'current_user' => $user_info['id'], |
||
| 1673 | 'old_topic' => $old_topic, |
||
| 1674 | 'redirect_topic' => $redirect_topic, |
||
| 1675 | 'redirect_expires' => $redirect_expires |
||
| 1676 | ) |
||
| 1677 | ); |
||
| 1678 | } |
||
| 1679 | } |
||
| 1680 | |||
| 1681 | // Ensure we don't accidentally delete the poll we want to keep... |
||
| 1682 | $smcFunc['db_query']('', ' |
||
| 1683 | UPDATE {db_prefix}topics |
||
| 1684 | SET id_poll = 0 |
||
| 1685 | WHERE id_topic IN ({array_int:deleted_topics})', |
||
| 1686 | array( |
||
| 1687 | 'deleted_topics' => $deleted_topics |
||
| 1688 | ) |
||
| 1689 | ); |
||
| 1690 | |||
| 1691 | // Delete any remaining data regarding these topics, this is done before changing the properties of the merged topic (else we get duplicate keys)... |
||
| 1692 | if (!isset($_POST['postRedirect'])) |
||
| 1693 | { |
||
| 1694 | // Remove any remaining info about these topics... |
||
| 1695 | include_once($sourcedir . '/RemoveTopic.php'); |
||
| 1696 | // We do not need to remove the counts of the deleted topics, as we already removed these. |
||
| 1697 | removeTopics($deleted_topics, false, true, false); |
||
| 1698 | } |
||
| 1699 | |||
| 1700 | // Asssign the properties of the newly merged topic. |
||
| 1701 | $smcFunc['db_query']('', ' |
||
| 1702 | UPDATE {db_prefix}topics |
||
| 1703 | SET |
||
| 1704 | id_board = {int:id_board}, |
||
| 1705 | id_member_started = {int:id_member_started}, |
||
| 1706 | id_member_updated = {int:id_member_updated}, |
||
| 1707 | id_first_msg = {int:id_first_msg}, |
||
| 1708 | id_last_msg = {int:id_last_msg}, |
||
| 1709 | id_poll = {int:id_poll}, |
||
| 1710 | num_replies = {int:num_replies}, |
||
| 1711 | unapproved_posts = {int:unapproved_posts}, |
||
| 1712 | num_views = {int:num_views}, |
||
| 1713 | is_sticky = {int:is_sticky}, |
||
| 1714 | approved = {int:approved} |
||
| 1715 | WHERE id_topic = {int:id_topic}', |
||
| 1716 | array( |
||
| 1717 | 'id_board' => $target_board, |
||
| 1718 | 'is_sticky' => $is_sticky, |
||
| 1719 | 'approved' => $topic_approved, |
||
| 1720 | 'id_topic' => $id_topic, |
||
| 1721 | 'id_member_started' => $member_started, |
||
| 1722 | 'id_member_updated' => $member_updated, |
||
| 1723 | 'id_first_msg' => $first_msg, |
||
| 1724 | 'id_last_msg' => $last_msg, |
||
| 1725 | 'id_poll' => $target_poll, |
||
| 1726 | 'num_replies' => $num_replies, |
||
| 1727 | 'unapproved_posts' => $num_unapproved, |
||
| 1728 | 'num_views' => $num_views, |
||
| 1729 | ) |
||
| 1730 | ); |
||
| 1731 | |||
| 1732 | // Update all the statistics. |
||
| 1733 | updateStats('topic'); |
||
| 1734 | updateStats('subject', $id_topic, $target_subject); |
||
| 1735 | updateLastMessages($boards); |
||
| 1736 | |||
| 1737 | logAction('merge', array('topic' => $id_topic, 'board' => $id_board)); |
||
| 1738 | |||
| 1739 | // Notify people that these topics have been merged? |
||
| 1740 | sendNotifications($id_topic, 'merge'); |
||
| 1741 | |||
| 1742 | // If there's a search index that needs updating, update it... |
||
| 1743 | require_once($sourcedir . '/Search.php'); |
||
| 1744 | $searchAPI = findSearchAPI(); |
||
| 1745 | if (is_callable(array($searchAPI, 'topicMerge'))) |
||
| 1746 | $searchAPI->topicMerge($id_topic, $topics, $affected_msgs, empty($_POST['enforce_subject']) ? null : array($context['response_prefix'], $target_subject)); |
||
| 1747 | |||
| 1748 | // Merging is the sort of thing an external CMS might want to know about |
||
| 1749 | $merged_topic = array( |
||
| 1750 | 'id_board' => $target_board, |
||
| 1751 | 'is_sticky' => $is_sticky, |
||
| 1752 | 'approved' => $topic_approved, |
||
| 1753 | 'id_topic' => $id_topic, |
||
| 1754 | 'id_member_started' => $member_started, |
||
| 1755 | 'id_member_updated' => $member_updated, |
||
| 1756 | 'id_first_msg' => $first_msg, |
||
| 1757 | 'id_last_msg' => $last_msg, |
||
| 1758 | 'id_poll' => $target_poll, |
||
| 1759 | 'num_replies' => $num_replies, |
||
| 1760 | 'unapproved_posts' => $num_unapproved, |
||
| 1761 | 'num_views' => $num_views, |
||
| 1762 | 'subject' => $target_subject, |
||
| 1763 | ); |
||
| 1764 | call_integration_hook('integrate_merge_topic', array($merged_topic, $updated_topics, $deleted_topics, $deleted_polls)); |
||
| 1765 | |||
| 1766 | // Send them to the all done page. |
||
| 1767 | redirectexit('action=mergetopics;sa=done;to=' . $id_topic . ';targetboard=' . $target_board); |
||
| 1768 | } |
||
| 1769 | |||
| 1770 | /** |
||
| 1771 | * Shows a 'merge completed' screen. |
||
| 1772 | * is accessed with ?action=mergetopics;sa=done. |
||
| 1773 | * uses 'merge_done' sub template of the SplitTopics template. |
||
| 1774 | */ |
||
| 1775 | function MergeDone() |
||
| 1776 | { |
||
| 1777 | global $txt, $context; |
||
| 1778 | |||
| 1779 | // Make sure the template knows everything... |
||
| 1780 | $context['target_board'] = (int) $_GET['targetboard']; |
||
| 1781 | $context['target_topic'] = (int) $_GET['to']; |
||
| 1782 | |||
| 1783 | $context['page_title'] = $txt['merge']; |
||
| 1784 | $context['sub_template'] = 'merge_done'; |
||
| 1785 | } |
||
| 1786 | |||
| 1787 | ?> |
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.
This is most likely a typographical error or the method has been renamed.