Verzeichnisstruktur phpBB-3.3.15
- Veröffentlicht
- 28.08.2024
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
mcp_main.php
0001 <?php
0002 /**
0003 *
0004 * This file is part of the phpBB Forum Software package.
0005 *
0006 * @copyright (c) phpBB Limited <https://www.phpbb.com>
0007 * @license GNU General Public License, version 2 (GPL-2.0)
0008 *
0009 * For full copyright and license information, please see
0010 * the docs/CREDITS.txt file.
0011 *
0012 */
0013
0014 /**
0015 * @ignore
0016 */
0017 if (!defined('IN_PHPBB'))
0018 {
0019 exit;
0020 }
0021
0022 /**
0023 * mcp_main
0024 * Handling mcp actions
0025 */
0026 class mcp_main
0027 {
0028 var $p_master;
0029 var $u_action;
0030
0031 function __construct($p_master)
0032 {
0033 $this->p_master = $p_master;
0034 }
0035
0036 function main($id, $mode)
0037 {
0038 global $auth, $user, $action;
0039 global $phpbb_root_path, $phpEx, $request;
0040 global $phpbb_dispatcher;
0041
0042 $quickmod = ($mode == 'quickmod') ? true : false;
0043
0044 /**
0045 * Event to perform additional actions before an MCP action is executed.
0046 *
0047 * @event core.mcp_main_before
0048 * @var string action The action that is about to be performed
0049 * @var string mode The mode in which the MCP is accessed, e.g. front, forum_view, topic_view, post_details, quickmod
0050 * @var boolean quickmod Whether or not the action is performed via QuickMod
0051 * @since 3.2.8-RC1
0052 */
0053 $vars = [
0054 'action',
0055 'mode',
0056 'quickmod',
0057 ];
0058 extract($phpbb_dispatcher->trigger_event('core.mcp_main_before', compact($vars)));
0059
0060 switch ($action)
0061 {
0062 case 'lock':
0063 case 'unlock':
0064 $topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0));
0065
0066 if (!count($topic_ids))
0067 {
0068 trigger_error('NO_TOPIC_SELECTED');
0069 }
0070
0071 lock_unlock($action, $topic_ids);
0072 break;
0073
0074 case 'lock_post':
0075 case 'unlock_post':
0076
0077 $post_ids = (!$quickmod) ? $request->variable('post_id_list', array(0)) : array($request->variable('p', 0));
0078
0079 if (!count($post_ids))
0080 {
0081 trigger_error('NO_POST_SELECTED');
0082 }
0083
0084 lock_unlock($action, $post_ids);
0085 break;
0086
0087 case 'make_announce':
0088 case 'make_sticky':
0089 case 'make_global':
0090 case 'make_normal':
0091
0092 $topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0));
0093
0094 if (!count($topic_ids))
0095 {
0096 trigger_error('NO_TOPIC_SELECTED');
0097 }
0098
0099 change_topic_type($action, $topic_ids);
0100 break;
0101
0102 case 'move':
0103 $user->add_lang('viewtopic');
0104
0105 $topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0));
0106
0107 if (!count($topic_ids))
0108 {
0109 trigger_error('NO_TOPIC_SELECTED');
0110 }
0111
0112 mcp_move_topic($topic_ids);
0113 break;
0114
0115 case 'fork':
0116 $user->add_lang('viewtopic');
0117
0118 $topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0));
0119
0120 if (!count($topic_ids))
0121 {
0122 trigger_error('NO_TOPIC_SELECTED');
0123 }
0124
0125 mcp_fork_topic($topic_ids);
0126 break;
0127
0128 case 'delete_topic':
0129 $user->add_lang('viewtopic');
0130
0131 // f parameter is not reliable for permission usage, however we just use it to decide
0132 // which permission we will check later on. So if it is manipulated, we will still catch it later on.
0133 $forum_id = $request->variable('f', 0);
0134 $topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0));
0135 $soft_delete = (($request->is_set_post('confirm') && !$request->is_set_post('delete_permanent')) || !$auth->acl_get('m_delete', $forum_id)) ? true : false;
0136
0137 if (!count($topic_ids))
0138 {
0139 trigger_error('NO_TOPIC_SELECTED');
0140 }
0141
0142 mcp_delete_topic($topic_ids, $soft_delete, $request->variable('delete_reason', '', true));
0143 break;
0144
0145 case 'delete_post':
0146 $user->add_lang('posting');
0147
0148 // f parameter is not reliable for permission usage, however we just use it to decide
0149 // which permission we will check later on. So if it is manipulated, we will still catch it later on.
0150 $forum_id = $request->variable('f', 0);
0151 $post_ids = (!$quickmod) ? $request->variable('post_id_list', array(0)) : array($request->variable('p', 0));
0152 $soft_delete = (($request->is_set_post('confirm') && !$request->is_set_post('delete_permanent')) || !$auth->acl_get('m_delete', $forum_id)) ? true : false;
0153
0154 if (!count($post_ids))
0155 {
0156 trigger_error('NO_POST_SELECTED');
0157 }
0158
0159 mcp_delete_post($post_ids, $soft_delete, $request->variable('delete_reason', '', true));
0160 break;
0161
0162 case 'restore_topic':
0163 $user->add_lang('posting');
0164
0165 $topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0));
0166
0167 if (!count($topic_ids))
0168 {
0169 trigger_error('NO_TOPIC_SELECTED');
0170 }
0171
0172 mcp_restore_topic($topic_ids);
0173 break;
0174
0175 default:
0176 /**
0177 * This event allows you to handle custom quickmod options
0178 *
0179 * @event core.modify_quickmod_actions
0180 * @var string action Topic quick moderation action name
0181 * @var bool quickmod Flag indicating whether MCP is in quick moderation mode
0182 * @since 3.1.0-a4
0183 * @changed 3.1.0-RC4 Added variables: action, quickmod
0184 */
0185 $vars = array('action', 'quickmod');
0186 extract($phpbb_dispatcher->trigger_event('core.modify_quickmod_actions', compact($vars)));
0187 break;
0188 }
0189
0190 switch ($mode)
0191 {
0192 case 'front':
0193 if (!function_exists('mcp_front_view'))
0194 {
0195 include($phpbb_root_path . 'includes/mcp/mcp_front.' . $phpEx);
0196 }
0197
0198 $user->add_lang('acp/common');
0199
0200 mcp_front_view($id, $mode, $action);
0201
0202 $this->tpl_name = 'mcp_front';
0203 $this->page_title = 'MCP_MAIN';
0204 break;
0205
0206 case 'forum_view':
0207 if (!function_exists('mcp_forum_view'))
0208 {
0209 include($phpbb_root_path . 'includes/mcp/mcp_forum.' . $phpEx);
0210 }
0211
0212 $user->add_lang('viewforum');
0213
0214 $forum_id = $request->variable('f', 0);
0215
0216 $forum_info = phpbb_get_forum_data($forum_id, 'm_', true);
0217
0218 if (!count($forum_info))
0219 {
0220 $this->main('main', 'front');
0221 return;
0222 }
0223
0224 $forum_info = $forum_info[$forum_id];
0225
0226 mcp_forum_view($id, $mode, $action, $forum_info);
0227
0228 $this->tpl_name = 'mcp_forum';
0229 $this->page_title = 'MCP_MAIN_FORUM_VIEW';
0230 break;
0231
0232 case 'topic_view':
0233 if (!function_exists('mcp_topic_view'))
0234 {
0235 include($phpbb_root_path . 'includes/mcp/mcp_topic.' . $phpEx);
0236 }
0237
0238 mcp_topic_view($id, $mode, $action);
0239
0240 $this->tpl_name = 'mcp_topic';
0241 $this->page_title = 'MCP_MAIN_TOPIC_VIEW';
0242 break;
0243
0244 case 'post_details':
0245 if (!function_exists('mcp_post_details'))
0246 {
0247 include($phpbb_root_path . 'includes/mcp/mcp_post.' . $phpEx);
0248 }
0249
0250 mcp_post_details($id, $mode, $action);
0251
0252 $this->tpl_name = ($action == 'whois') ? 'mcp_whois' : 'mcp_post';
0253 $this->page_title = 'MCP_MAIN_POST_DETAILS';
0254 break;
0255
0256 default:
0257 if ($quickmod)
0258 {
0259 switch ($action)
0260 {
0261 case 'lock':
0262 case 'unlock':
0263 case 'make_announce':
0264 case 'make_sticky':
0265 case 'make_global':
0266 case 'make_normal':
0267 case 'make_onindex':
0268 case 'move':
0269 case 'fork':
0270 case 'delete_topic':
0271 trigger_error('TOPIC_NOT_EXIST');
0272 break;
0273
0274 case 'lock_post':
0275 case 'unlock_post':
0276 case 'delete_post':
0277 trigger_error('POST_NOT_EXIST');
0278 break;
0279 }
0280 }
0281
0282 trigger_error('NO_MODE', E_USER_ERROR);
0283 break;
0284 }
0285 }
0286 }
0287
0288 /**
0289 * Lock/Unlock Topic/Post
0290 */
0291 function lock_unlock($action, $ids)
0292 {
0293 global $user, $db, $request, $phpbb_log, $phpbb_dispatcher;
0294
0295 if ($action == 'lock' || $action == 'unlock')
0296 {
0297 $table = TOPICS_TABLE;
0298 $sql_id = 'topic_id';
0299 $set_id = 'topic_status';
0300 $l_prefix = 'TOPIC';
0301 }
0302 else
0303 {
0304 $table = POSTS_TABLE;
0305 $sql_id = 'post_id';
0306 $set_id = 'post_edit_locked';
0307 $l_prefix = 'POST';
0308 }
0309
0310 $orig_ids = $ids;
0311
0312 if (!phpbb_check_ids($ids, $table, $sql_id, array('m_lock')))
0313 {
0314 // Make sure that for f_user_lock only the lock action is triggered.
0315 if ($action != 'lock')
0316 {
0317 return;
0318 }
0319
0320 $ids = $orig_ids;
0321
0322 if (!phpbb_check_ids($ids, $table, $sql_id, array('f_user_lock')))
0323 {
0324 return;
0325 }
0326 }
0327 unset($orig_ids);
0328
0329 $redirect = $request->variable('redirect', build_url(array('action', 'quickmod')));
0330 $redirect = reapply_sid($redirect);
0331
0332 $s_hidden_fields = build_hidden_fields(array(
0333 $sql_id . '_list' => $ids,
0334 'action' => $action,
0335 'redirect' => $redirect)
0336 );
0337
0338 if (confirm_box(true))
0339 {
0340 $sql = "UPDATE $table
0341 SET $set_id = " . (($action == 'lock' || $action == 'lock_post') ? ITEM_LOCKED : ITEM_UNLOCKED) . '
0342 WHERE ' . $db->sql_in_set($sql_id, $ids);
0343 $db->sql_query($sql);
0344
0345 $data = ($action == 'lock' || $action == 'unlock') ? phpbb_get_topic_data($ids) : phpbb_get_post_data($ids);
0346
0347 foreach ($data as $id => $row)
0348 {
0349 $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_' . strtoupper($action), false, array(
0350 'forum_id' => $row['forum_id'],
0351 'topic_id' => $row['topic_id'],
0352 'post_id' => isset($row['post_id']) ? $row['post_id'] : 0,
0353 $row['topic_title']
0354 ));
0355 }
0356
0357 /**
0358 * Perform additional actions after locking/unlocking posts/topics
0359 *
0360 * @event core.mcp_lock_unlock_after
0361 * @var string action Variable containing the action we perform on the posts/topics ('lock', 'unlock', 'lock_post' or 'unlock_post')
0362 * @var array ids Array containing the post/topic IDs that have been locked/unlocked
0363 * @var array data Array containing posts/topics data
0364 * @since 3.1.7-RC1
0365 */
0366 $vars = array(
0367 'action',
0368 'ids',
0369 'data',
0370 );
0371 extract($phpbb_dispatcher->trigger_event('core.mcp_lock_unlock_after', compact($vars)));
0372
0373 $success_msg = $l_prefix . ((count($ids) == 1) ? '' : 'S') . '_' . (($action == 'lock' || $action == 'lock_post') ? 'LOCKED' : 'UNLOCKED') . '_SUCCESS';
0374
0375 meta_refresh(2, $redirect);
0376 $message = $user->lang[$success_msg];
0377
0378 if (!$request->is_ajax())
0379 {
0380 $message .= '<br /><br />' . $user->lang('RETURN_PAGE', '<a href="' . $redirect . '">', '</a>');
0381 }
0382 trigger_error($message);
0383 }
0384 else
0385 {
0386 confirm_box(false, strtoupper($action) . '_' . $l_prefix . ((count($ids) == 1) ? '' : 'S'), $s_hidden_fields);
0387 }
0388
0389 redirect($redirect);
0390 }
0391
0392 /**
0393 * Change Topic Type
0394 */
0395 function change_topic_type($action, $topic_ids)
0396 {
0397 global $user, $db, $request, $phpbb_log, $phpbb_dispatcher;
0398
0399 switch ($action)
0400 {
0401 case 'make_announce':
0402 $new_topic_type = POST_ANNOUNCE;
0403 $check_acl = 'f_announce';
0404 $l_new_type = (count($topic_ids) == 1) ? 'MCP_MAKE_ANNOUNCEMENT' : 'MCP_MAKE_ANNOUNCEMENTS';
0405 break;
0406
0407 case 'make_global':
0408 $new_topic_type = POST_GLOBAL;
0409 $check_acl = 'f_announce_global';
0410 $l_new_type = (count($topic_ids) == 1) ? 'MCP_MAKE_GLOBAL' : 'MCP_MAKE_GLOBALS';
0411 break;
0412
0413 case 'make_sticky':
0414 $new_topic_type = POST_STICKY;
0415 $check_acl = 'f_sticky';
0416 $l_new_type = (count($topic_ids) == 1) ? 'MCP_MAKE_STICKY' : 'MCP_MAKE_STICKIES';
0417 break;
0418
0419 default:
0420 $new_topic_type = POST_NORMAL;
0421 $check_acl = false;
0422 $l_new_type = (count($topic_ids) == 1) ? 'MCP_MAKE_NORMAL' : 'MCP_MAKE_NORMALS';
0423 break;
0424 }
0425
0426 $forum_id = phpbb_check_ids($topic_ids, TOPICS_TABLE, 'topic_id', $check_acl, true);
0427
0428 if ($forum_id === false)
0429 {
0430 return;
0431 }
0432
0433 $redirect = $request->variable('redirect', build_url(array('action', 'quickmod')));
0434 $redirect = reapply_sid($redirect);
0435
0436 $s_hidden_fields = array(
0437 'topic_id_list' => $topic_ids,
0438 'f' => $forum_id,
0439 'action' => $action,
0440 'redirect' => $redirect,
0441 );
0442
0443 if (confirm_box(true))
0444 {
0445
0446 /**
0447 * Perform additional actions before changing topic(s) type
0448 *
0449 * @event core.mcp_change_topic_type_before
0450 * @var int new_topic_type The candidated topic type.
0451 * @var int forum_id The forum ID for the topic ID(s).
0452 * @var array topic_ids Array containing the topic ID(s) that will be changed
0453 * @since 3.2.6-RC1
0454 */
0455 $vars = array(
0456 'new_topic_type',
0457 'forum_id',
0458 'topic_ids',
0459 );
0460 extract($phpbb_dispatcher->trigger_event('core.mcp_change_topic_type_before', compact($vars)));
0461
0462 $db->sql_transaction('begin');
0463
0464 $sql = 'UPDATE ' . TOPICS_TABLE . "
0465 SET topic_type = $new_topic_type
0466 WHERE " . $db->sql_in_set('topic_id', $topic_ids);
0467 $db->sql_query($sql);
0468
0469 if (($new_topic_type == POST_GLOBAL) && count($topic_ids))
0470 {
0471 // Delete topic shadows for global announcements
0472 $sql = 'DELETE FROM ' . TOPICS_TABLE . '
0473 WHERE ' . $db->sql_in_set('topic_moved_id', $topic_ids);
0474 $db->sql_query($sql);
0475 }
0476
0477 $db->sql_transaction('commit');
0478
0479 $success_msg = (count($topic_ids) == 1) ? 'TOPIC_TYPE_CHANGED' : 'TOPICS_TYPE_CHANGED';
0480
0481 if (count($topic_ids))
0482 {
0483 $data = phpbb_get_topic_data($topic_ids);
0484
0485 foreach ($data as $topic_id => $row)
0486 {
0487 $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_TOPIC_TYPE_CHANGED', false, array(
0488 'forum_id' => $forum_id,
0489 'topic_id' => $topic_id,
0490 $row['topic_title']
0491 ));
0492 }
0493 }
0494
0495 /**
0496 * Perform additional actions after changing topic types
0497 *
0498 * @event core.mcp_change_topic_type_after
0499 * @var int new_topic_type The newly changed topic type.
0500 * @var int forum_id The forum ID where the newly changed topic type belongs to.
0501 * @var array topic_ids Array containing the topic IDs that have been changed
0502 * @since 3.2.6-RC1
0503 */
0504 $vars = array(
0505 'new_topic_type',
0506 'forum_id',
0507 'topic_ids',
0508 );
0509 extract($phpbb_dispatcher->trigger_event('core.mcp_change_topic_type_after', compact($vars)));
0510
0511 meta_refresh(2, $redirect);
0512 $message = $user->lang[$success_msg];
0513
0514 if (!$request->is_ajax())
0515 {
0516 $message .= '<br /><br />' . $user->lang('RETURN_PAGE', '<a href="' . $redirect . '">', '</a>');
0517 }
0518 trigger_error($message);
0519 }
0520 else
0521 {
0522 confirm_box(false, $l_new_type, build_hidden_fields($s_hidden_fields));
0523 }
0524
0525 redirect($redirect);
0526 }
0527
0528 /**
0529 * Move Topic
0530 */
0531 function mcp_move_topic($topic_ids)
0532 {
0533 global $auth, $user, $db, $template, $phpbb_log, $request, $phpbb_dispatcher;
0534 global $phpEx, $phpbb_root_path;
0535
0536 // Here we limit the operation to one forum only
0537 $forum_id = phpbb_check_ids($topic_ids, TOPICS_TABLE, 'topic_id', array('m_move'), true);
0538
0539 if ($forum_id === false)
0540 {
0541 return;
0542 }
0543
0544 $to_forum_id = $request->variable('to_forum_id', 0);
0545 $redirect = $request->variable('redirect', build_url(array('action', 'quickmod')));
0546 $additional_msg = $success_msg = '';
0547
0548 $s_hidden_fields = build_hidden_fields(array(
0549 'topic_id_list' => $topic_ids,
0550 'f' => $forum_id,
0551 'action' => 'move',
0552 'redirect' => $redirect)
0553 );
0554
0555 if ($to_forum_id)
0556 {
0557 $forum_data = phpbb_get_forum_data($to_forum_id, 'f_post');
0558
0559 if (!count($forum_data))
0560 {
0561 $additional_msg = $user->lang['FORUM_NOT_EXIST'];
0562 }
0563 else
0564 {
0565 $forum_data = $forum_data[$to_forum_id];
0566
0567 if ($forum_data['forum_type'] != FORUM_POST)
0568 {
0569 $additional_msg = $user->lang['FORUM_NOT_POSTABLE'];
0570 }
0571 else if (!$auth->acl_get('f_post', $to_forum_id) || (!$auth->acl_get('m_approve', $to_forum_id) && !$auth->acl_get('f_noapprove', $to_forum_id)))
0572 {
0573 $additional_msg = $user->lang['USER_CANNOT_POST'];
0574 }
0575 else if ($forum_id == $to_forum_id)
0576 {
0577 $additional_msg = $user->lang['CANNOT_MOVE_SAME_FORUM'];
0578 }
0579 }
0580 }
0581 else if (isset($_POST['confirm']))
0582 {
0583 $additional_msg = $user->lang['FORUM_NOT_EXIST'];
0584 }
0585
0586 if (!$to_forum_id || $additional_msg)
0587 {
0588 $request->overwrite('confirm', null, \phpbb\request\request_interface::POST);
0589 $request->overwrite('confirm_key', null);
0590 }
0591
0592 if (confirm_box(true))
0593 {
0594 $topic_data = phpbb_get_topic_data($topic_ids);
0595 $leave_shadow = (isset($_POST['move_leave_shadow'])) ? true : false;
0596
0597 $forum_sync_data = array();
0598
0599 $forum_sync_data[$forum_id] = current($topic_data);
0600 $forum_sync_data[$to_forum_id] = $forum_data;
0601
0602 $topics_moved = $topics_moved_unapproved = $topics_moved_softdeleted = 0;
0603 $posts_moved = $posts_moved_unapproved = $posts_moved_softdeleted = 0;
0604
0605 foreach ($topic_data as $topic_id => $topic_info)
0606 {
0607 if ($topic_info['topic_visibility'] == ITEM_APPROVED)
0608 {
0609 $topics_moved++;
0610 }
0611 else if ($topic_info['topic_visibility'] == ITEM_UNAPPROVED || $topic_info['topic_visibility'] == ITEM_REAPPROVE)
0612 {
0613 $topics_moved_unapproved++;
0614 }
0615 else if ($topic_info['topic_visibility'] == ITEM_DELETED)
0616 {
0617 $topics_moved_softdeleted++;
0618 }
0619
0620 $posts_moved += $topic_info['topic_posts_approved'];
0621 $posts_moved_unapproved += $topic_info['topic_posts_unapproved'];
0622 $posts_moved_softdeleted += $topic_info['topic_posts_softdeleted'];
0623 }
0624
0625 $db->sql_transaction('begin');
0626
0627 // Move topics, but do not resync yet
0628 move_topics($topic_ids, $to_forum_id, false);
0629
0630 if ($request->is_set_post('move_lock_topics') && $auth->acl_get('m_lock', $to_forum_id))
0631 {
0632 $sql = 'UPDATE ' . TOPICS_TABLE . '
0633 SET topic_status = ' . ITEM_LOCKED . '
0634 WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
0635 $db->sql_query($sql);
0636 }
0637
0638 $shadow_topics = 0;
0639 $forum_ids = array($to_forum_id);
0640 foreach ($topic_data as $topic_id => $row)
0641 {
0642 // Get the list of forums to resync
0643 $forum_ids[] = $row['forum_id'];
0644
0645 // We add the $to_forum_id twice, because 'forum_id' is updated
0646 // when the topic is moved again later.
0647 $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_MOVE', false, array(
0648 'forum_id' => (int) $to_forum_id,
0649 'topic_id' => (int) $topic_id,
0650 $row['forum_name'],
0651 $forum_data['forum_name'],
0652 (int) $row['forum_id'],
0653 (int) $forum_data['forum_id'],
0654 ));
0655
0656 // Leave a redirection if required and only if the topic is visible to users
0657 if ($leave_shadow && $row['topic_visibility'] == ITEM_APPROVED && $row['topic_type'] != POST_GLOBAL)
0658 {
0659 $shadow = array(
0660 'forum_id' => (int) $row['forum_id'],
0661 'icon_id' => (int) $row['icon_id'],
0662 'topic_attachment' => (int) $row['topic_attachment'],
0663 'topic_visibility' => ITEM_APPROVED, // a shadow topic is always approved
0664 'topic_reported' => 0, // a shadow topic is never reported
0665 'topic_title' => (string) $row['topic_title'],
0666 'topic_poster' => (int) $row['topic_poster'],
0667 'topic_time' => (int) $row['topic_time'],
0668 'topic_time_limit' => (int) $row['topic_time_limit'],
0669 'topic_views' => (int) $row['topic_views'],
0670 'topic_posts_approved' => (int) $row['topic_posts_approved'],
0671 'topic_posts_unapproved'=> (int) $row['topic_posts_unapproved'],
0672 'topic_posts_softdeleted'=> (int) $row['topic_posts_softdeleted'],
0673 'topic_status' => ITEM_MOVED,
0674 'topic_type' => POST_NORMAL,
0675 'topic_first_post_id' => (int) $row['topic_first_post_id'],
0676 'topic_first_poster_colour'=>(string) $row['topic_first_poster_colour'],
0677 'topic_first_poster_name'=> (string) $row['topic_first_poster_name'],
0678 'topic_last_post_id' => (int) $row['topic_last_post_id'],
0679 'topic_last_poster_id' => (int) $row['topic_last_poster_id'],
0680 'topic_last_poster_colour'=>(string) $row['topic_last_poster_colour'],
0681 'topic_last_poster_name'=> (string) $row['topic_last_poster_name'],
0682 'topic_last_post_subject'=> (string) $row['topic_last_post_subject'],
0683 'topic_last_post_time' => (int) $row['topic_last_post_time'],
0684 'topic_last_view_time' => (int) $row['topic_last_view_time'],
0685 'topic_moved_id' => (int) $row['topic_id'],
0686 'topic_bumped' => (int) $row['topic_bumped'],
0687 'topic_bumper' => (int) $row['topic_bumper'],
0688 'poll_title' => (string) $row['poll_title'],
0689 'poll_start' => (int) $row['poll_start'],
0690 'poll_length' => (int) $row['poll_length'],
0691 'poll_max_options' => (int) $row['poll_max_options'],
0692 'poll_last_vote' => (int) $row['poll_last_vote']
0693 );
0694
0695 /**
0696 * Perform actions before shadow topic is created.
0697 *
0698 * @event core.mcp_main_modify_shadow_sql
0699 * @var array shadow SQL array to be used by $db->sql_build_array
0700 * @var array row Topic data
0701 * @since 3.1.11-RC1
0702 * @changed 3.1.11-RC1 Added variable: row
0703 */
0704 $vars = array(
0705 'shadow',
0706 'row',
0707 );
0708 extract($phpbb_dispatcher->trigger_event('core.mcp_main_modify_shadow_sql', compact($vars)));
0709
0710 $db->sql_query('INSERT INTO ' . TOPICS_TABLE . $db->sql_build_array('INSERT', $shadow));
0711
0712 // Shadow topics only count on new "topics" and not posts... a shadow topic alone has 0 posts
0713 $shadow_topics++;
0714 }
0715 }
0716 unset($topic_data);
0717
0718 $sync_sql = array();
0719 if ($posts_moved)
0720 {
0721 $sync_sql[$to_forum_id][] = 'forum_posts_approved = forum_posts_approved + ' . (int) $posts_moved;
0722 $sync_sql[$forum_id][] = 'forum_posts_approved = forum_posts_approved - ' . (int) $posts_moved;
0723 }
0724 if ($posts_moved_unapproved)
0725 {
0726 $sync_sql[$to_forum_id][] = 'forum_posts_unapproved = forum_posts_unapproved + ' . (int) $posts_moved_unapproved;
0727 $sync_sql[$forum_id][] = 'forum_posts_unapproved = forum_posts_unapproved - ' . (int) $posts_moved_unapproved;
0728 }
0729 if ($posts_moved_softdeleted)
0730 {
0731 $sync_sql[$to_forum_id][] = 'forum_posts_softdeleted = forum_posts_softdeleted + ' . (int) $posts_moved_softdeleted;
0732 $sync_sql[$forum_id][] = 'forum_posts_softdeleted = forum_posts_softdeleted - ' . (int) $posts_moved_softdeleted;
0733 }
0734
0735 if ($topics_moved)
0736 {
0737 $sync_sql[$to_forum_id][] = 'forum_topics_approved = forum_topics_approved + ' . (int) $topics_moved;
0738 if ($topics_moved - $shadow_topics > 0)
0739 {
0740 $sync_sql[$forum_id][] = 'forum_topics_approved = forum_topics_approved - ' . (int) ($topics_moved - $shadow_topics);
0741 }
0742 }
0743 if ($topics_moved_unapproved)
0744 {
0745 $sync_sql[$to_forum_id][] = 'forum_topics_unapproved = forum_topics_unapproved + ' . (int) $topics_moved_unapproved;
0746 $sync_sql[$forum_id][] = 'forum_topics_unapproved = forum_topics_unapproved - ' . (int) $topics_moved_unapproved;
0747 }
0748 if ($topics_moved_softdeleted)
0749 {
0750 $sync_sql[$to_forum_id][] = 'forum_topics_softdeleted = forum_topics_softdeleted + ' . (int) $topics_moved_softdeleted;
0751 $sync_sql[$forum_id][] = 'forum_topics_softdeleted = forum_topics_softdeleted - ' . (int) $topics_moved_softdeleted;
0752 }
0753
0754 $success_msg = (count($topic_ids) == 1) ? 'TOPIC_MOVED_SUCCESS' : 'TOPICS_MOVED_SUCCESS';
0755
0756 foreach ($sync_sql as $forum_id_key => $array)
0757 {
0758 $sql = 'UPDATE ' . FORUMS_TABLE . '
0759 SET ' . implode(', ', $array) . '
0760 WHERE forum_id = ' . $forum_id_key;
0761 $db->sql_query($sql);
0762 }
0763
0764 $db->sql_transaction('commit');
0765
0766 sync('forum', 'forum_id', array($forum_id, $to_forum_id));
0767 }
0768 else
0769 {
0770 $template->assign_vars(array(
0771 'S_FORUM_SELECT' => make_forum_select($to_forum_id, $forum_id, false, true, true, true),
0772 'S_CAN_LEAVE_SHADOW' => true,
0773 'S_CAN_LOCK_TOPIC' => ($auth->acl_get('m_lock', $to_forum_id)) ? true : false,
0774 'ADDITIONAL_MSG' => $additional_msg)
0775 );
0776
0777 confirm_box(false, 'MOVE_TOPIC' . ((count($topic_ids) == 1) ? '' : 'S'), $s_hidden_fields, 'mcp_move.html');
0778 }
0779
0780 $redirect = $request->variable('redirect', "index.$phpEx");
0781 $redirect = reapply_sid($redirect);
0782
0783 if (!$success_msg)
0784 {
0785 redirect($redirect);
0786 }
0787 else
0788 {
0789 meta_refresh(3, $redirect);
0790
0791 $message = $user->lang[$success_msg];
0792 $message .= '<br /><br />' . sprintf($user->lang['RETURN_PAGE'], '<a href="' . $redirect . '">', '</a>');
0793 $message .= '<br /><br />' . sprintf($user->lang['RETURN_FORUM'], '<a href="' . append_sid("{$phpbb_root_path}viewforum.$phpEx", "f=$forum_id") . '">', '</a>');
0794 $message .= '<br /><br />' . sprintf($user->lang['RETURN_NEW_FORUM'], '<a href="' . append_sid("{$phpbb_root_path}viewforum.$phpEx", "f=$to_forum_id") . '">', '</a>');
0795
0796 trigger_error($message);
0797 }
0798 }
0799
0800 /**
0801 * Restore Topics
0802 */
0803 function mcp_restore_topic($topic_ids)
0804 {
0805 global $user, $phpEx, $phpbb_root_path, $request, $phpbb_container, $phpbb_log;
0806
0807 if (!phpbb_check_ids($topic_ids, TOPICS_TABLE, 'topic_id', array('m_approve')))
0808 {
0809 return;
0810 }
0811
0812 $redirect = $request->variable('redirect', build_url(array('action', 'quickmod')));
0813 $forum_id = $request->variable('f', 0);
0814
0815 $s_hidden_fields = build_hidden_fields(array(
0816 'topic_id_list' => $topic_ids,
0817 'f' => $forum_id,
0818 'action' => 'restore_topic',
0819 'redirect' => $redirect,
0820 ));
0821 $success_msg = '';
0822
0823 if (confirm_box(true))
0824 {
0825 $success_msg = (count($topic_ids) == 1) ? 'TOPIC_RESTORED_SUCCESS' : 'TOPICS_RESTORED_SUCCESS';
0826
0827 $data = phpbb_get_topic_data($topic_ids);
0828
0829 /* @var $phpbb_content_visibility \phpbb\content_visibility */
0830 $phpbb_content_visibility = $phpbb_container->get('content.visibility');
0831 foreach ($data as $topic_id => $row)
0832 {
0833 $return = $phpbb_content_visibility->set_topic_visibility(ITEM_APPROVED, $topic_id, $row['forum_id'], $user->data['user_id'], time(), '');
0834 if (!empty($return))
0835 {
0836 $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_RESTORE_TOPIC', false, array(
0837 'forum_id' => $row['forum_id'],
0838 'topic_id' => $topic_id,
0839 $row['topic_title'],
0840 $row['topic_first_poster_name']
0841 ));
0842 }
0843 }
0844 }
0845 else
0846 {
0847 confirm_box(false, (count($topic_ids) == 1) ? 'RESTORE_TOPIC' : 'RESTORE_TOPICS', $s_hidden_fields);
0848 }
0849
0850 $topic_id = $request->variable('t', 0);
0851 if (!$request->is_set('quickmod', \phpbb\request\request_interface::REQUEST))
0852 {
0853 $redirect = $request->variable('redirect', "index.$phpEx");
0854 $redirect = reapply_sid($redirect);
0855 $redirect_message = 'PAGE';
0856 }
0857 else if ($topic_id)
0858 {
0859 $redirect = append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=' . $topic_id);
0860 $redirect_message = 'TOPIC';
0861 }
0862 else
0863 {
0864 $redirect = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id);
0865 $redirect_message = 'FORUM';
0866 }
0867
0868 if (!$success_msg)
0869 {
0870 redirect($redirect);
0871 }
0872 else
0873 {
0874 meta_refresh(3, $redirect);
0875 trigger_error($user->lang[$success_msg] . '<br /><br />' . sprintf($user->lang['RETURN_' . $redirect_message], '<a href="' . $redirect . '">', '</a>'));
0876 }
0877 }
0878
0879 /**
0880 * Delete Topics
0881 */
0882 function mcp_delete_topic($topic_ids, $is_soft = false, $soft_delete_reason = '', $action = 'delete_topic')
0883 {
0884 global $auth, $user, $db, $phpEx, $phpbb_root_path, $request, $phpbb_container, $phpbb_log, $phpbb_dispatcher;
0885
0886 $forum_id = $request->variable('f', 0);
0887 $check_permission = ($is_soft) ? ['m_softdelete'] : ['m_delete'];
0888 /**
0889 * This event allows you to modify the current user's checked permissions when deleting a topic
0890 *
0891 * @event core.mcp_delete_topic_modify_permissions
0892 * @var array topic_ids The array of topic IDs to be deleted
0893 * @var int forum_id The current forum ID
0894 * @var bool is_soft Boolean designating whether we're soft deleting or not
0895 * @var string soft_delete_reason The reason we're soft deleting
0896 * @var string action The current delete action
0897 * @var array check_permission The array with a permission to check for, can be set to false to not check them
0898 * @since 3.3.3-RC1
0899 */
0900 $vars = array(
0901 'topic_ids',
0902 'forum_id',
0903 'is_soft',
0904 'soft_delete_reason',
0905 'action',
0906 'check_permission',
0907 );
0908 extract($phpbb_dispatcher->trigger_event('core.mcp_delete_topic_modify_permissions', compact($vars)));
0909
0910 if (!phpbb_check_ids($topic_ids, TOPICS_TABLE, 'topic_id', $check_permission))
0911 {
0912 return;
0913 }
0914
0915 $redirect = $request->variable('redirect', build_url(array('action', 'quickmod')));
0916
0917 $s_hidden_fields = array(
0918 'topic_id_list' => $topic_ids,
0919 'f' => $forum_id,
0920 'action' => $action,
0921 'redirect' => $redirect,
0922 );
0923 $success_msg = '';
0924
0925 if (confirm_box(true))
0926 {
0927 $success_msg = (count($topic_ids) == 1) ? 'TOPIC_DELETED_SUCCESS' : 'TOPICS_DELETED_SUCCESS';
0928
0929 $data = phpbb_get_topic_data($topic_ids);
0930
0931 foreach ($data as $topic_id => $row)
0932 {
0933 if ($row['topic_moved_id'])
0934 {
0935 $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_DELETE_SHADOW_TOPIC', false, array(
0936 'forum_id' => $row['forum_id'],
0937 'topic_id' => $topic_id,
0938 $row['topic_title']
0939 ));
0940 }
0941 else
0942 {
0943 // Only soft delete non-shadow topics
0944 if ($is_soft)
0945 {
0946 /* @var $phpbb_content_visibility \phpbb\content_visibility */
0947 $phpbb_content_visibility = $phpbb_container->get('content.visibility');
0948 $return = $phpbb_content_visibility->set_topic_visibility(ITEM_DELETED, $topic_id, $row['forum_id'], $user->data['user_id'], time(), $soft_delete_reason);
0949 if (!empty($return))
0950 {
0951 $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_SOFTDELETE_TOPIC', false, array(
0952 'forum_id' => $row['forum_id'],
0953 'topic_id' => $topic_id,
0954 $row['topic_title'],
0955 $row['topic_first_poster_name'],
0956 $soft_delete_reason
0957 ));
0958 }
0959 }
0960 else
0961 {
0962 $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_DELETE_TOPIC', false, array(
0963 'forum_id' => $row['forum_id'],
0964 'topic_id' => $topic_id,
0965 $row['topic_title'],
0966 $row['topic_first_poster_name'],
0967 $soft_delete_reason
0968 ));
0969 }
0970 }
0971 }
0972
0973 if (!$is_soft)
0974 {
0975 delete_topics('topic_id', $topic_ids);
0976 }
0977 }
0978 else
0979 {
0980 global $template;
0981
0982 $user->add_lang('posting');
0983
0984 // If there are only shadow topics, we neither need a reason nor softdelete
0985 $sql = 'SELECT topic_id
0986 FROM ' . TOPICS_TABLE . '
0987 WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . '
0988 AND topic_moved_id = 0';
0989 $result = $db->sql_query_limit($sql, 1);
0990 $only_shadow = !$db->sql_fetchfield('topic_id');
0991 $db->sql_freeresult($result);
0992
0993 $only_softdeleted = false;
0994 if (!$only_shadow && $auth->acl_get('m_delete', $forum_id) && $auth->acl_get('m_softdelete', $forum_id))
0995 {
0996 // If there are only soft deleted topics, we display a message why the option is not available
0997 $sql = 'SELECT topic_id
0998 FROM ' . TOPICS_TABLE . '
0999 WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . '
1000 AND topic_visibility <> ' . ITEM_DELETED;
1001 $result = $db->sql_query_limit($sql, 1);
1002 $only_softdeleted = !$db->sql_fetchfield('topic_id');
1003 $db->sql_freeresult($result);
1004 }
1005
1006 $template->assign_vars(array(
1007 'S_SHADOW_TOPICS' => $only_shadow,
1008 'S_SOFTDELETED' => $only_softdeleted,
1009 'S_TOPIC_MODE' => true,
1010 'S_ALLOWED_DELETE' => $auth->acl_get('m_delete', $forum_id),
1011 'S_ALLOWED_SOFTDELETE' => $auth->acl_get('m_softdelete', $forum_id),
1012 'DELETE_TOPIC_PERMANENTLY_EXPLAIN' => $user->lang('DELETE_TOPIC_PERMANENTLY', count($topic_ids)),
1013 ));
1014
1015 $count = count($topic_ids);
1016 $l_confirm = $count === 1 ? 'DELETE_TOPIC' : 'DELETE_TOPICS';
1017 if ($only_softdeleted)
1018 {
1019 $l_confirm = array($l_confirm . '_PERMANENTLY', $count);
1020 $s_hidden_fields['delete_permanent'] = '1';
1021 }
1022 else if ($only_shadow || !$auth->acl_get('m_softdelete', $forum_id))
1023 {
1024 $s_hidden_fields['delete_permanent'] = '1';
1025 }
1026
1027 /**
1028 * This event allows you to modify the hidden form fields when deleting topics
1029 *
1030 * @event core.mcp_delete_topic_modify_hidden_fields
1031 * @var string l_confirm The confirmation text language variable (DELETE_TOPIC(S), DELETE_TOPIC(S)_PERMANENTLY)
1032 * @var array s_hidden_fields The array holding the hidden form fields
1033 * @var array topic_ids The array of topic IDs to be deleted
1034 * @var int forum_id The current forum ID
1035 * @var bool only_softdeleted If the topic_ids are all soft deleted, this is true
1036 * @var bool only_shadow If the topic_ids are all shadow topics, this is true
1037 * @since 3.3.3-RC1
1038 */
1039 $vars = array(
1040 'l_confirm',
1041 's_hidden_fields',
1042 'topic_ids',
1043 'forum_id',
1044 'only_softdeleted',
1045 'only_shadow',
1046 );
1047 extract($phpbb_dispatcher->trigger_event('core.mcp_delete_topic_modify_hidden_fields', compact($vars)));
1048
1049 confirm_box(false, $l_confirm, build_hidden_fields($s_hidden_fields), 'confirm_delete_body.html');
1050 }
1051
1052 $topic_id = $request->variable('t', 0);
1053 if (!$request->is_set('quickmod', \phpbb\request\request_interface::REQUEST))
1054 {
1055 $redirect = $request->variable('redirect', "index.$phpEx");
1056 $redirect = reapply_sid($redirect);
1057 $redirect_message = 'PAGE';
1058 }
1059 else if ($is_soft && $topic_id)
1060 {
1061 $redirect = append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=' . $topic_id);
1062 $redirect_message = 'TOPIC';
1063 }
1064 else
1065 {
1066 $redirect = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id);
1067 $redirect_message = 'FORUM';
1068 }
1069
1070 if (!$success_msg)
1071 {
1072 redirect($redirect);
1073 }
1074 else
1075 {
1076 meta_refresh(3, $redirect);
1077 trigger_error($user->lang[$success_msg] . '<br /><br />' . sprintf($user->lang['RETURN_' . $redirect_message], '<a href="' . $redirect . '">', '</a>'));
1078 }
1079 }
1080
1081 /**
1082 * Delete Posts
1083 */
1084 function mcp_delete_post($post_ids, $is_soft = false, $soft_delete_reason = '', $action = 'delete_post')
1085 {
1086 global $auth, $user, $db, $phpEx, $phpbb_root_path, $request, $phpbb_container, $phpbb_log;
1087
1088 $check_permission = ($is_soft) ? 'm_softdelete' : 'm_delete';
1089 if (!phpbb_check_ids($post_ids, POSTS_TABLE, 'post_id', array($check_permission)))
1090 {
1091 return;
1092 }
1093
1094 $redirect = $request->variable('redirect', build_url(array('action', 'quickmod')));
1095 $forum_id = $request->variable('f', 0);
1096 $topic_id = 0;
1097
1098 $s_hidden_fields = array(
1099 'post_id_list' => $post_ids,
1100 'f' => $forum_id,
1101 'action' => $action,
1102 'redirect' => $redirect,
1103 );
1104 $success_msg = '';
1105
1106 if (confirm_box(true) && $is_soft)
1107 {
1108 $post_info = phpbb_get_post_data($post_ids);
1109
1110 $topic_info = $approve_log = array();
1111
1112 // Group the posts by topic_id
1113 foreach ($post_info as $post_id => $post_data)
1114 {
1115 if ($post_data['post_visibility'] != ITEM_APPROVED)
1116 {
1117 continue;
1118 }
1119 $topic_id = (int) $post_data['topic_id'];
1120
1121 $topic_info[$topic_id]['posts'][] = (int) $post_id;
1122 $topic_info[$topic_id]['forum_id'] = (int) $post_data['forum_id'];
1123
1124 if ($post_id == $post_data['topic_first_post_id'])
1125 {
1126 $topic_info[$topic_id]['first_post'] = true;
1127 }
1128
1129 if ($post_id == $post_data['topic_last_post_id'])
1130 {
1131 $topic_info[$topic_id]['last_post'] = true;
1132 }
1133
1134 $approve_log[] = array(
1135 'forum_id' => $post_data['forum_id'],
1136 'topic_id' => $post_data['topic_id'],
1137 'post_id' => $post_id,
1138 'post_subject' => $post_data['post_subject'],
1139 'poster_id' => $post_data['poster_id'],
1140 'post_username' => $post_data['post_username'],
1141 'username' => $post_data['username'],
1142 );
1143 }
1144
1145 /* @var $phpbb_content_visibility \phpbb\content_visibility */
1146 $phpbb_content_visibility = $phpbb_container->get('content.visibility');
1147 foreach ($topic_info as $topic_id => $topic_data)
1148 {
1149 $phpbb_content_visibility->set_post_visibility(ITEM_DELETED, $topic_data['posts'], $topic_id, $topic_data['forum_id'], $user->data['user_id'], time(), $soft_delete_reason, isset($topic_data['first_post']), isset($topic_data['last_post']));
1150 }
1151 $affected_topics = count($topic_info);
1152 // None of the topics is really deleted, so a redirect won't hurt much.
1153 $deleted_topics = 0;
1154
1155 $success_msg = (count($post_info) == 1) ? $user->lang['POST_DELETED_SUCCESS'] : $user->lang['POSTS_DELETED_SUCCESS'];
1156
1157 foreach ($approve_log as $row)
1158 {
1159 $post_username = ($row['poster_id'] == ANONYMOUS && !empty($row['post_username'])) ? $row['post_username'] : $row['username'];
1160 $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_SOFTDELETE_POST', false, array(
1161 'forum_id' => $row['forum_id'],
1162 'topic_id' => $row['topic_id'],
1163 'post_id' => $row['post_id'],
1164 $row['post_subject'],
1165 $post_username,
1166 $soft_delete_reason
1167 ));
1168 }
1169
1170 // Return links
1171 $return_link = array();
1172 if ($affected_topics == 1 && $topic_id)
1173 {
1174 $return_link[] = sprintf($user->lang['RETURN_TOPIC'], '<a href="' . append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id") . '">', '</a>');
1175 }
1176 $return_link[] = sprintf($user->lang['RETURN_FORUM'], '<a href="' . append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id) . '">', '</a>');
1177
1178 }
1179 else if (confirm_box(true))
1180 {
1181 if (!function_exists('delete_posts'))
1182 {
1183 include($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
1184 }
1185
1186 // Count the number of topics that are affected
1187 // I did not use COUNT(DISTINCT ...) because I remember having problems
1188 // with it on older versions of MySQL -- Ashe
1189
1190 $sql = 'SELECT DISTINCT topic_id
1191 FROM ' . POSTS_TABLE . '
1192 WHERE ' . $db->sql_in_set('post_id', $post_ids);
1193 $result = $db->sql_query($sql);
1194
1195 $topic_id_list = array();
1196 while ($row = $db->sql_fetchrow($result))
1197 {
1198 $topic_id_list[] = $topic_id = $row['topic_id'];
1199 }
1200 $affected_topics = count($topic_id_list);
1201 $db->sql_freeresult($result);
1202
1203 $post_data = phpbb_get_post_data($post_ids);
1204
1205 foreach ($post_data as $id => $row)
1206 {
1207 $post_username = ($row['poster_id'] == ANONYMOUS && !empty($row['post_username'])) ? $row['post_username'] : $row['username'];
1208 $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_DELETE_POST', false, array(
1209 'forum_id' => $row['forum_id'],
1210 'topic_id' => $row['topic_id'],
1211 'post_id' => $row['post_id'],
1212 $row['post_subject'],
1213 $post_username,
1214 $soft_delete_reason
1215 ));
1216 }
1217
1218 // Now delete the posts, topics and forums are automatically resync'ed
1219 delete_posts('post_id', $post_ids);
1220
1221 $sql = 'SELECT COUNT(topic_id) AS topics_left
1222 FROM ' . TOPICS_TABLE . '
1223 WHERE ' . $db->sql_in_set('topic_id', $topic_id_list);
1224 $result = $db->sql_query_limit($sql, 1);
1225
1226 $deleted_topics = ($row = $db->sql_fetchrow($result)) ? ($affected_topics - $row['topics_left']) : $affected_topics;
1227 $db->sql_freeresult($result);
1228
1229 // Return links
1230 $return_link = array();
1231 if ($affected_topics == 1 && !$deleted_topics && $topic_id)
1232 {
1233 $return_link[] = sprintf($user->lang['RETURN_TOPIC'], '<a href="' . append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id") . '">', '</a>');
1234 }
1235 $return_link[] = sprintf($user->lang['RETURN_FORUM'], '<a href="' . append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id) . '">', '</a>');
1236
1237 if (count($post_ids) == 1)
1238 {
1239 if ($deleted_topics)
1240 {
1241 // We deleted the only post of a topic, which in turn has
1242 // been removed from the database
1243 $success_msg = $user->lang['TOPIC_DELETED_SUCCESS'];
1244 }
1245 else
1246 {
1247 // Remove any post id anchor
1248 if (($anchor_pos = strrpos($redirect, '#p')) !== false)
1249 {
1250 $redirect = substr($redirect, 0, $anchor_pos);
1251 }
1252
1253 $success_msg = $user->lang['POST_DELETED_SUCCESS'];
1254 }
1255 }
1256 else
1257 {
1258 if ($deleted_topics)
1259 {
1260 // Some of topics disappeared
1261 $success_msg = $user->lang['POSTS_DELETED_SUCCESS'] . '<br /><br />' . $user->lang['EMPTY_TOPICS_REMOVED_WARNING'];
1262 }
1263 else
1264 {
1265 $success_msg = $user->lang['POSTS_DELETED_SUCCESS'];
1266 }
1267 }
1268 }
1269 else
1270 {
1271 global $template;
1272
1273 $user->add_lang('posting');
1274
1275 $only_softdeleted = false;
1276 if ($auth->acl_get('m_delete', $forum_id) && $auth->acl_get('m_softdelete', $forum_id))
1277 {
1278 // If there are only soft deleted posts, we display a message why the option is not available
1279 $sql = 'SELECT post_id
1280 FROM ' . POSTS_TABLE . '
1281 WHERE ' . $db->sql_in_set('post_id', $post_ids) . '
1282 AND post_visibility <> ' . ITEM_DELETED;
1283 $result = $db->sql_query_limit($sql, 1);
1284 $only_softdeleted = !$db->sql_fetchfield('post_id');
1285 $db->sql_freeresult($result);
1286 }
1287
1288 $template->assign_vars(array(
1289 'S_SOFTDELETED' => $only_softdeleted,
1290 'S_ALLOWED_DELETE' => $auth->acl_get('m_delete', $forum_id),
1291 'S_ALLOWED_SOFTDELETE' => $auth->acl_get('m_softdelete', $forum_id),
1292 'DELETE_POST_PERMANENTLY_EXPLAIN' => $user->lang('DELETE_POST_PERMANENTLY', count($post_ids)),
1293 ));
1294
1295 $count = count($post_ids);
1296 $l_confirm = $count === 1 ? 'DELETE_POST' : 'DELETE_POSTS';
1297 if ($only_softdeleted)
1298 {
1299 $l_confirm = array($l_confirm . '_PERMANENTLY', $count);
1300 $s_hidden_fields['delete_permanent'] = '1';
1301 }
1302 else if (!$auth->acl_get('m_softdelete', $forum_id))
1303 {
1304 $s_hidden_fields['delete_permanent'] = '1';
1305 }
1306
1307 confirm_box(false, $l_confirm, build_hidden_fields($s_hidden_fields), 'confirm_delete_body.html');
1308 }
1309
1310 $redirect = reapply_sid($redirect);
1311
1312 if (!$success_msg)
1313 {
1314 redirect($redirect);
1315 }
1316 else
1317 {
1318 if ($affected_topics != 1 || $deleted_topics || !$topic_id)
1319 {
1320 $redirect = append_sid("{$phpbb_root_path}mcp.$phpEx", "f=$forum_id&i=main&mode=forum_view", false);
1321 }
1322
1323 meta_refresh(3, $redirect);
1324 trigger_error($success_msg . '<br /><br />' . sprintf($user->lang['RETURN_PAGE'], '<a href="' . $redirect . '">', '</a>') . '<br /><br />' . implode('<br /><br />', $return_link));
1325 }
1326 }
1327
1328 /**
1329 * Fork Topic
1330 */
1331 function mcp_fork_topic($topic_ids)
1332 {
1333 global $auth, $user, $db, $template, $config;
1334 global $phpEx, $phpbb_root_path, $phpbb_log, $request, $phpbb_dispatcher;
1335
1336 if (!phpbb_check_ids($topic_ids, TOPICS_TABLE, 'topic_id', array('m_')))
1337 {
1338 return;
1339 }
1340
1341 $to_forum_id = $request->variable('to_forum_id', 0);
1342 $forum_id = $request->variable('f', 0);
1343 $redirect = $request->variable('redirect', build_url(array('action', 'quickmod')));
1344 $additional_msg = $success_msg = '';
1345 $counter = array();
1346
1347 $s_hidden_fields = build_hidden_fields(array(
1348 'topic_id_list' => $topic_ids,
1349 'f' => $forum_id,
1350 'action' => 'fork',
1351 'redirect' => $redirect)
1352 );
1353
1354 if ($to_forum_id)
1355 {
1356 $forum_data = phpbb_get_forum_data($to_forum_id, 'f_post');
1357
1358 if (!count($topic_ids))
1359 {
1360 $additional_msg = $user->lang['NO_TOPIC_SELECTED'];
1361 }
1362 else if (!count($forum_data))
1363 {
1364 $additional_msg = $user->lang['FORUM_NOT_EXIST'];
1365 }
1366 else
1367 {
1368 $forum_data = $forum_data[$to_forum_id];
1369
1370 if ($forum_data['forum_type'] != FORUM_POST)
1371 {
1372 $additional_msg = $user->lang['FORUM_NOT_POSTABLE'];
1373 }
1374 else if (!$auth->acl_get('f_post', $to_forum_id))
1375 {
1376 $additional_msg = $user->lang['USER_CANNOT_POST'];
1377 }
1378 }
1379 }
1380 else if (isset($_POST['confirm']))
1381 {
1382 $additional_msg = $user->lang['FORUM_NOT_EXIST'];
1383 }
1384
1385 if ($additional_msg)
1386 {
1387 $request->overwrite('confirm', null, \phpbb\request\request_interface::POST);
1388 $request->overwrite('confirm_key', null);
1389 }
1390
1391 if (confirm_box(true))
1392 {
1393 $topic_data = phpbb_get_topic_data($topic_ids, 'f_post');
1394
1395 $total_topics = $total_topics_unapproved = $total_topics_softdeleted = 0;
1396 $total_posts = $total_posts_unapproved = $total_posts_softdeleted = 0;
1397 $new_topic_id_list = array();
1398
1399 foreach ($topic_data as $topic_id => $topic_row)
1400 {
1401 if (!isset($search_type) && $topic_row['enable_indexing'])
1402 {
1403 // Select the search method and do some additional checks to ensure it can actually be utilised
1404 $search_type = $config['search_type'];
1405
1406 if (!class_exists($search_type))
1407 {
1408 trigger_error('NO_SUCH_SEARCH_MODULE');
1409 }
1410
1411 $error = false;
1412 $search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher);
1413 $search_mode = 'post';
1414
1415 if ($error)
1416 {
1417 trigger_error($error);
1418 }
1419 }
1420 else if (!isset($search_type) && !$topic_row['enable_indexing'])
1421 {
1422 $search_type = false;
1423 }
1424
1425 $sql_ary = array(
1426 'forum_id' => (int) $to_forum_id,
1427 'icon_id' => (int) $topic_row['icon_id'],
1428 'topic_attachment' => (int) $topic_row['topic_attachment'],
1429 'topic_visibility' => (int) $topic_row['topic_visibility'],
1430 'topic_reported' => 0,
1431 'topic_title' => (string) $topic_row['topic_title'],
1432 'topic_poster' => (int) $topic_row['topic_poster'],
1433 'topic_time' => (int) $topic_row['topic_time'],
1434 'topic_posts_approved' => (int) $topic_row['topic_posts_approved'],
1435 'topic_posts_unapproved' => (int) $topic_row['topic_posts_unapproved'],
1436 'topic_posts_softdeleted' => (int) $topic_row['topic_posts_softdeleted'],
1437 'topic_status' => (int) $topic_row['topic_status'],
1438 'topic_type' => (int) $topic_row['topic_type'],
1439 'topic_first_poster_name' => (string) $topic_row['topic_first_poster_name'],
1440 'topic_last_poster_id' => (int) $topic_row['topic_last_poster_id'],
1441 'topic_last_poster_name' => (string) $topic_row['topic_last_poster_name'],
1442 'topic_last_post_time' => (int) $topic_row['topic_last_post_time'],
1443 'topic_last_view_time' => (int) $topic_row['topic_last_view_time'],
1444 'topic_bumped' => (int) $topic_row['topic_bumped'],
1445 'topic_bumper' => (int) $topic_row['topic_bumper'],
1446 'poll_title' => (string) $topic_row['poll_title'],
1447 'poll_start' => (int) $topic_row['poll_start'],
1448 'poll_length' => (int) $topic_row['poll_length'],
1449 'poll_max_options' => (int) $topic_row['poll_max_options'],
1450 'poll_vote_change' => (int) $topic_row['poll_vote_change'],
1451 );
1452
1453 /**
1454 * Perform actions before forked topic is created.
1455 *
1456 * @event core.mcp_main_modify_fork_sql
1457 * @var array sql_ary SQL array to be used by $db->sql_build_array
1458 * @var array topic_row Topic data
1459 * @since 3.1.11-RC1
1460 * @changed 3.1.11-RC1 Added variable: topic_row
1461 */
1462 $vars = array(
1463 'sql_ary',
1464 'topic_row',
1465 );
1466 extract($phpbb_dispatcher->trigger_event('core.mcp_main_modify_fork_sql', compact($vars)));
1467
1468 $db->sql_query('INSERT INTO ' . TOPICS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
1469 $new_topic_id = $db->sql_nextid();
1470 $new_topic_id_list[$topic_id] = $new_topic_id;
1471
1472 switch ($topic_row['topic_visibility'])
1473 {
1474 case ITEM_APPROVED:
1475 $total_topics++;
1476 break;
1477 case ITEM_UNAPPROVED:
1478 case ITEM_REAPPROVE:
1479 $total_topics_unapproved++;
1480 break;
1481 case ITEM_DELETED:
1482 $total_topics_softdeleted++;
1483 break;
1484 }
1485
1486 if ($topic_row['poll_start'])
1487 {
1488 $sql = 'SELECT *
1489 FROM ' . POLL_OPTIONS_TABLE . "
1490 WHERE topic_id = $topic_id";
1491 $result = $db->sql_query($sql);
1492
1493 while ($row = $db->sql_fetchrow($result))
1494 {
1495 $sql_ary = array(
1496 'poll_option_id' => (int) $row['poll_option_id'],
1497 'topic_id' => (int) $new_topic_id,
1498 'poll_option_text' => (string) $row['poll_option_text'],
1499 'poll_option_total' => 0
1500 );
1501
1502 $db->sql_query('INSERT INTO ' . POLL_OPTIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
1503 }
1504 $db->sql_freeresult($result);
1505 }
1506
1507 $sql = 'SELECT *
1508 FROM ' . POSTS_TABLE . "
1509 WHERE topic_id = $topic_id
1510 ORDER BY post_time ASC, post_id ASC";
1511 $result = $db->sql_query($sql);
1512
1513 $post_rows = array();
1514 while ($row = $db->sql_fetchrow($result))
1515 {
1516 $post_rows[] = $row;
1517 }
1518 $db->sql_freeresult($result);
1519
1520 if (!count($post_rows))
1521 {
1522 continue;
1523 }
1524
1525 foreach ($post_rows as $row)
1526 {
1527 $sql_ary = array(
1528 'topic_id' => (int) $new_topic_id,
1529 'forum_id' => (int) $to_forum_id,
1530 'poster_id' => (int) $row['poster_id'],
1531 'icon_id' => (int) $row['icon_id'],
1532 'poster_ip' => (string) $row['poster_ip'],
1533 'post_time' => (int) $row['post_time'],
1534 'post_visibility' => (int) $row['post_visibility'],
1535 'post_reported' => 0,
1536 'enable_bbcode' => (int) $row['enable_bbcode'],
1537 'enable_smilies' => (int) $row['enable_smilies'],
1538 'enable_magic_url' => (int) $row['enable_magic_url'],
1539 'enable_sig' => (int) $row['enable_sig'],
1540 'post_username' => (string) $row['post_username'],
1541 'post_subject' => (string) $row['post_subject'],
1542 'post_text' => (string) $row['post_text'],
1543 'post_edit_reason' => (string) $row['post_edit_reason'],
1544 'post_edit_user' => (int) $row['post_edit_user'],
1545 'post_checksum' => (string) $row['post_checksum'],
1546 'post_attachment' => (int) $row['post_attachment'],
1547 'bbcode_bitfield' => $row['bbcode_bitfield'],
1548 'bbcode_uid' => (string) $row['bbcode_uid'],
1549 'post_edit_time' => (int) $row['post_edit_time'],
1550 'post_edit_count' => (int) $row['post_edit_count'],
1551 'post_edit_locked' => (int) $row['post_edit_locked'],
1552 'post_postcount' => $row['post_postcount'],
1553 );
1554 // Adjust post count only if the post can be incremented to the user counter
1555 if ($row['post_postcount'])
1556 {
1557 if (isset($counter[$row['poster_id']]))
1558 {
1559 ++$counter[$row['poster_id']];
1560 }
1561 else
1562 {
1563 $counter[$row['poster_id']] = 1;
1564 }
1565 }
1566
1567 /**
1568 * Modify the forked post's sql array before it's inserted into the database.
1569 *
1570 * @event core.mcp_main_modify_fork_post_sql
1571 * @var int new_topic_id The newly created topic ID
1572 * @var int to_forum_id The forum ID where the forked topic has been moved to
1573 * @var array sql_ary SQL Array with the post's data
1574 * @var array row Post data
1575 * @var array counter Array with post counts
1576 * @since 3.3.5-RC1
1577 */
1578 $vars = [
1579 'new_topic_id',
1580 'to_forum_id',
1581 'sql_ary',
1582 'row',
1583 'counter',
1584 ];
1585 extract($phpbb_dispatcher->trigger_event('core.mcp_main_modify_fork_post_sql', compact($vars)));
1586 $db->sql_query('INSERT INTO ' . POSTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
1587 $new_post_id = $db->sql_nextid();
1588
1589 /**
1590 * Perform actions after forked topic is created.
1591 *
1592 * @event core.mcp_main_fork_sql_after
1593 * @var int new_topic_id The newly created topic ID
1594 * @var int to_forum_id The forum ID where the forked topic has been moved to
1595 * @var int new_post_id The newly created post ID
1596 * @var array row Post data
1597 * @since 3.2.4-RC1
1598 */
1599 $vars = array(
1600 'new_topic_id',
1601 'to_forum_id',
1602 'new_post_id',
1603 'row',
1604 );
1605 extract($phpbb_dispatcher->trigger_event('core.mcp_main_fork_sql_after', compact($vars)));
1606
1607 switch ($row['post_visibility'])
1608 {
1609 case ITEM_APPROVED:
1610 $total_posts++;
1611 break;
1612 case ITEM_UNAPPROVED:
1613 case ITEM_REAPPROVE:
1614 $total_posts_unapproved++;
1615 break;
1616 case ITEM_DELETED:
1617 $total_posts_softdeleted++;
1618 break;
1619 }
1620
1621 // Copy whether the topic is dotted
1622 markread('post', $to_forum_id, $new_topic_id, 0, $row['poster_id']);
1623
1624 if (!empty($search_type))
1625 {
1626 $search->index($search_mode, $new_post_id, $sql_ary['post_text'], $sql_ary['post_subject'], $sql_ary['poster_id'], ($topic_row['topic_type'] == POST_GLOBAL) ? 0 : $to_forum_id);
1627 $search_mode = 'reply'; // After one we index replies
1628 }
1629
1630 // Copy Attachments
1631 if ($row['post_attachment'])
1632 {
1633 $sql = 'SELECT * FROM ' . ATTACHMENTS_TABLE . '
1634 WHERE post_msg_id = ' . (int) $row['post_id'] . '
1635 AND topic_id = ' . (int) $topic_id . '
1636 AND in_message = 0
1637 ORDER BY attach_id ASC';
1638 $result = $db->sql_query($sql);
1639
1640 $sql_ary = array();
1641 while ($attach_row = $db->sql_fetchrow($result))
1642 {
1643 $sql_ary[] = array(
1644 'post_msg_id' => (int) $new_post_id,
1645 'topic_id' => (int) $new_topic_id,
1646 'in_message' => 0,
1647 'is_orphan' => (int) $attach_row['is_orphan'],
1648 'poster_id' => (int) $attach_row['poster_id'],
1649 'physical_filename' => (string) utf8_basename($attach_row['physical_filename']),
1650 'real_filename' => (string) utf8_basename($attach_row['real_filename']),
1651 'download_count' => (int) $attach_row['download_count'],
1652 'attach_comment' => (string) $attach_row['attach_comment'],
1653 'extension' => (string) $attach_row['extension'],
1654 'mimetype' => (string) $attach_row['mimetype'],
1655 'filesize' => (int) $attach_row['filesize'],
1656 'filetime' => (int) $attach_row['filetime'],
1657 'thumbnail' => (int) $attach_row['thumbnail']
1658 );
1659 }
1660 $db->sql_freeresult($result);
1661
1662 if (count($sql_ary))
1663 {
1664 $db->sql_multi_insert(ATTACHMENTS_TABLE, $sql_ary);
1665 }
1666 }
1667 }
1668
1669 // Copy topic subscriptions to new topic
1670 $sql = 'SELECT user_id, notify_status
1671 FROM ' . TOPICS_WATCH_TABLE . '
1672 WHERE topic_id = ' . $topic_id;
1673 $result = $db->sql_query($sql);
1674
1675 $sql_ary = array();
1676 while ($row = $db->sql_fetchrow($result))
1677 {
1678 $sql_ary[] = array(
1679 'topic_id' => (int) $new_topic_id,
1680 'user_id' => (int) $row['user_id'],
1681 'notify_status' => (int) $row['notify_status'],
1682 );
1683 }
1684 $db->sql_freeresult($result);
1685
1686 if (count($sql_ary))
1687 {
1688 $db->sql_multi_insert(TOPICS_WATCH_TABLE, $sql_ary);
1689 }
1690
1691 // Copy bookmarks to new topic
1692 $sql = 'SELECT user_id
1693 FROM ' . BOOKMARKS_TABLE . '
1694 WHERE topic_id = ' . $topic_id;
1695 $result = $db->sql_query($sql);
1696
1697 $sql_ary = array();
1698 while ($row = $db->sql_fetchrow($result))
1699 {
1700 $sql_ary[] = array(
1701 'topic_id' => (int) $new_topic_id,
1702 'user_id' => (int) $row['user_id'],
1703 );
1704 }
1705 $db->sql_freeresult($result);
1706
1707 if (count($sql_ary))
1708 {
1709 $db->sql_multi_insert(BOOKMARKS_TABLE, $sql_ary);
1710 }
1711 }
1712
1713 // Sync new topics, parent forums and board stats
1714 $sql = 'UPDATE ' . FORUMS_TABLE . '
1715 SET forum_posts_approved = forum_posts_approved + ' . $total_posts . ',
1716 forum_posts_unapproved = forum_posts_unapproved + ' . $total_posts_unapproved . ',
1717 forum_posts_softdeleted = forum_posts_softdeleted + ' . $total_posts_softdeleted . ',
1718 forum_topics_approved = forum_topics_approved + ' . $total_topics . ',
1719 forum_topics_unapproved = forum_topics_unapproved + ' . $total_topics_unapproved . ',
1720 forum_topics_softdeleted = forum_topics_softdeleted + ' . $total_topics_softdeleted . '
1721 WHERE forum_id = ' . $to_forum_id;
1722 $db->sql_query($sql);
1723
1724 if (!empty($counter))
1725 {
1726 // Do only one query per user and not a query per post.
1727 foreach ($counter as $user_id => $count)
1728 {
1729 $sql = 'UPDATE ' . USERS_TABLE . '
1730 SET user_posts = user_posts + ' . (int) $count . '
1731 WHERE user_id = ' . (int) $user_id;
1732 $db->sql_query($sql);
1733 }
1734 }
1735
1736 sync('topic', 'topic_id', $new_topic_id_list);
1737 sync('forum', 'forum_id', $to_forum_id);
1738
1739 $config->increment('num_topics', count($new_topic_id_list), false);
1740 $config->increment('num_posts', $total_posts, false);
1741
1742 foreach ($new_topic_id_list as $topic_id => $new_topic_id)
1743 {
1744 $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_FORK', false, array(
1745 'forum_id' => $to_forum_id,
1746 'topic_id' => $new_topic_id,
1747 $topic_row['forum_name']
1748 ));
1749 }
1750
1751 $success_msg = (count($topic_ids) == 1) ? 'TOPIC_FORKED_SUCCESS' : 'TOPICS_FORKED_SUCCESS';
1752 }
1753 else
1754 {
1755 $template->assign_vars(array(
1756 'S_FORUM_SELECT' => make_forum_select($to_forum_id, false, false, true, true, true),
1757 'S_CAN_LEAVE_SHADOW' => false,
1758 'ADDITIONAL_MSG' => $additional_msg)
1759 );
1760
1761 confirm_box(false, 'FORK_TOPIC' . ((count($topic_ids) == 1) ? '' : 'S'), $s_hidden_fields, 'mcp_move.html');
1762 }
1763
1764 $redirect = $request->variable('redirect', "index.$phpEx");
1765 $redirect = reapply_sid($redirect);
1766
1767 if (!$success_msg)
1768 {
1769 redirect($redirect);
1770 }
1771 else
1772 {
1773 $redirect_url = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id);
1774 meta_refresh(3, $redirect_url);
1775 $return_link = sprintf($user->lang['RETURN_FORUM'], '<a href="' . $redirect_url . '">', '</a>');
1776
1777 if ($forum_id != $to_forum_id)
1778 {
1779 $return_link .= '<br /><br />' . sprintf($user->lang['RETURN_NEW_FORUM'], '<a href="' . append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $to_forum_id) . '">', '</a>');
1780 }
1781
1782 trigger_error($user->lang[$success_msg] . '<br /><br />' . $return_link);
1783 }
1784 }
1785