Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 493
0.00% covered (danger)
0.00%
0 / 3
CRAP
n/a
0 / 0
mcp_topic_view
0.00% covered (danger)
0.00%
0 / 246
0.00% covered (danger)
0.00%
0 / 1
6806
split_topic
0.00% covered (danger)
0.00%
0 / 177
0.00% covered (danger)
0.00%
0 / 1
702
merge_posts
0.00% covered (danger)
0.00%
0 / 68
0.00% covered (danger)
0.00%
0 / 1
132
1<?php
2/**
3*
4* This file is part of the phpBB Forum Software package.
5*
6* @copyright (c) phpBB Limited <https://www.phpbb.com>
7* @license GNU General Public License, version 2 (GPL-2.0)
8*
9* For full copyright and license information, please see
10* the docs/CREDITS.txt file.
11*
12*/
13
14/**
15* @ignore
16*/
17if (!defined('IN_PHPBB'))
18{
19    exit;
20}
21
22/**
23* View topic in MCP
24*/
25function mcp_topic_view($id, $mode, $action)
26{
27    global $phpEx, $phpbb_root_path, $config, $request;
28    global $template, $db, $user, $auth, $phpbb_container, $phpbb_dispatcher;
29
30    $url = append_sid("{$phpbb_root_path}mcp.$phpEx?" . phpbb_extra_url());
31
32    /* @var $pagination \phpbb\pagination */
33    $pagination = $phpbb_container->get('pagination');
34    $user->add_lang('viewtopic');
35
36    $topic_id = $request->variable('t', 0);
37    $topic_info = phpbb_get_topic_data(array($topic_id), false, true);
38
39    if (!count($topic_info))
40    {
41        trigger_error('TOPIC_NOT_EXIST');
42    }
43
44    $topic_info = $topic_info[$topic_id];
45
46    // Set up some vars
47    $icon_id        = $request->variable('icon', 0);
48    $subject        = $request->variable('subject', '', true);
49    $start            = $request->variable('start', 0);
50    $sort_days_old    = $request->variable('st_old', 0);
51    $forum_id        = $request->variable('f', 0);
52    $to_topic_id    = $request->variable('to_topic_id', 0);
53    $to_forum_id    = $request->variable('to_forum_id', 0);
54    $sort            = isset($_POST['sort']) ? true : false;
55    $submitted_id_list    = $request->variable('post_ids', array(0));
56    $checked_ids = $post_id_list = $request->variable('post_id_list', array(0));
57    $view        = $request->variable('view', '');
58
59    add_form_key('mcp_topic');
60
61    // Resync Topic?
62    if ($action == 'resync')
63    {
64        if (!check_form_key('mcp_topic'))
65        {
66            trigger_error('FORM_INVALID');
67        }
68
69        if (!function_exists('mcp_resync_topics'))
70        {
71            include($phpbb_root_path . 'includes/mcp/mcp_forum.' . $phpEx);
72        }
73        mcp_resync_topics(array($topic_id));
74    }
75
76    // Split Topic?
77    if ($action == 'split_all' || $action == 'split_beyond')
78    {
79        if (!$sort)
80        {
81            split_topic($action, $topic_id, $to_forum_id, $subject);
82        }
83        $action = 'split';
84    }
85
86    // Merge Posts?
87    if ($action == 'merge_posts')
88    {
89        if (!$sort)
90        {
91            merge_posts($topic_id, $to_topic_id);
92        }
93        $action = 'merge';
94    }
95
96    if ($action == 'split' && !$subject)
97    {
98        $subject = $topic_info['topic_title'];
99    }
100
101    // Restore or approve posts?
102    if (($action == 'restore' || $action == 'approve') && $auth->acl_get('m_approve', $topic_info['forum_id']))
103    {
104        if (!class_exists('mcp_queue'))
105        {
106            include($phpbb_root_path . 'includes/mcp/mcp_queue.' . $phpEx);
107        }
108
109        include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx);
110
111        if (!count($post_id_list))
112        {
113            trigger_error('NO_POST_SELECTED');
114        }
115
116        if (!$sort)
117        {
118            mcp_queue::approve_posts($action, $post_id_list, $id, $mode);
119        }
120    }
121
122    // Jumpbox, sort selects and that kind of things
123    make_jumpbox($url . "&amp;i=$id&amp;mode=forum_view", $topic_info['forum_id'], false, 'm_', true);
124    $where_sql = ($action == 'reports') ? 'WHERE post_reported = 1 AND ' : 'WHERE';
125
126    $sort_days = $total = 0;
127    $sort_key = $sort_dir = '';
128    $sort_by_sql = $sort_order_sql = array();
129    phpbb_mcp_sorting('viewtopic', $sort_days, $sort_key, $sort_dir, $sort_by_sql, $sort_order_sql, $total, $topic_info['forum_id'], $topic_id, $where_sql);
130
131    /* @var $phpbb_content_visibility \phpbb\content_visibility */
132    $phpbb_content_visibility = $phpbb_container->get('content.visibility');
133    $limit_time_sql = ($sort_days) ? 'AND p.post_time >= ' . (time() - ($sort_days * 86400)) : '';
134
135    if ($total == -1)
136    {
137        $total = $phpbb_content_visibility->get_count('topic_posts', $topic_info, $topic_info['forum_id']);
138    }
139
140    $posts_per_page = max(0, $request->variable('posts_per_page', intval($config['posts_per_page'])));
141    if ($posts_per_page == 0)
142    {
143        $posts_per_page = $total;
144    }
145
146    if ((!empty($sort_days_old) && $sort_days_old != $sort_days) || $total <= $posts_per_page)
147    {
148        $start = 0;
149    }
150    $start = $pagination->validate_start($start, $posts_per_page, $total);
151
152    $sql_where = (($action == 'reports') ? 'p.post_reported = 1 AND ' : '') . '
153            p.topic_id = ' . $topic_id . '
154            AND ' .    $phpbb_content_visibility->get_visibility_sql('post', $topic_info['forum_id'], 'p.') . '
155            AND p.poster_id = u.user_id ' .
156            $limit_time_sql;
157
158    $sql_ary = array(
159        'SELECT'    => 'u.username, u.username_clean, u.user_colour, p.*',
160        'FROM'        => array(
161            POSTS_TABLE        => 'p',
162            USERS_TABLE        => 'u'
163        ),
164        'LEFT_JOIN'    => array(),
165        'WHERE'        => $sql_where,
166        'ORDER_BY'    => $sort_order_sql,
167    );
168
169    /**
170    * Event to modify the SQL query before the MCP topic review posts is queried
171    *
172    * @event core.mcp_topic_modify_sql_ary
173    * @var    array    sql_ary        The SQL array to get the data of the MCP topic review posts
174    * @since 3.2.8-RC1
175    */
176    $vars = array('sql_ary');
177    extract($phpbb_dispatcher->trigger_event('core.mcp_topic_modify_sql_ary', compact($vars)));
178
179    $sql = $db->sql_build_query('SELECT', $sql_ary);
180    unset($sql_ary);
181
182    $result = $db->sql_query_limit($sql, $posts_per_page, $start);
183
184    $rowset = $post_id_list = array();
185    while ($row = $db->sql_fetchrow($result))
186    {
187        $rowset[] = $row;
188        $post_id_list[] = $row['post_id'];
189        $rowset_posttime['post_time'] = $row['post_time'];
190    }
191    $db->sql_freeresult($result);
192
193    // Get topic tracking info
194    if ($config['load_db_lastread'])
195    {
196        $tmp_topic_data = array($topic_id => $topic_info);
197        $topic_tracking_info = get_topic_tracking($topic_info['forum_id'], $topic_id, $tmp_topic_data, array($topic_info['forum_id'] => $topic_info['forum_mark_time']));
198        unset($tmp_topic_data);
199    }
200    else
201    {
202        $topic_tracking_info = get_complete_topic_tracking($topic_info['forum_id'], $topic_id);
203    }
204
205    $first_unread = $post_unread = false;
206
207    $post_unread = (isset($topic_tracking_info[$topic_id]) && $rowset_posttime['post_time'] > $topic_tracking_info[$topic_id]) ? true : false;
208
209    $s_first_unread = false;
210    if (!$first_unread && $post_unread)
211    {
212        $s_first_unread = $first_unread = true;
213    }
214
215    $has_unapproved_posts = $has_deleted_posts = false;
216
217    // Grab extensions
218    $attachments = array();
219    if ($topic_info['topic_attachment'] && count($post_id_list))
220    {
221        // Get attachments...
222        if ($auth->acl_get('u_download') && $auth->acl_get('f_download', $topic_info['forum_id']))
223        {
224            $sql = 'SELECT *
225                FROM ' . ATTACHMENTS_TABLE . '
226                WHERE ' . $db->sql_in_set('post_msg_id', $post_id_list) . '
227                    AND in_message = 0
228                ORDER BY filetime DESC, post_msg_id ASC';
229            $result = $db->sql_query($sql);
230
231            while ($row = $db->sql_fetchrow($result))
232            {
233                $attachments[$row['post_msg_id']][] = $row;
234            }
235            $db->sql_freeresult($result);
236        }
237    }
238
239    /**
240    * Event to modify the post data for the MCP topic review before assigning the posts
241    *
242    * @event core.mcp_topic_modify_post_data
243    * @var    array    attachments        List of attachments post_id => array of attachments
244    * @var    int        forum_id        The forum ID we are currently in
245    * @var    int        id                ID of the tab we are displaying
246    * @var    string    mode            Mode of the MCP page we are displaying
247    * @var    array    post_id_list    Array with post ids we are going to display
248    * @var    array    rowset            Array with the posts data
249    * @var    int        topic_id        The topic ID we are currently reviewing
250    * @since 3.1.7-RC1
251    */
252    $vars = array(
253        'attachments',
254        'forum_id',
255        'id',
256        'mode',
257        'post_id_list',
258        'rowset',
259        'topic_id',
260    );
261    extract($phpbb_dispatcher->trigger_event('core.mcp_topic_modify_post_data', compact($vars)));
262
263    foreach ($rowset as $current_row_number => $row)
264    {
265        $message = $row['post_text'];
266        $post_subject = ($row['post_subject'] != '') ? $row['post_subject'] : $topic_info['topic_title'];
267
268        $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES;
269        $message = generate_text_for_display($message, $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, false);
270
271        if (!empty($attachments[$row['post_id']]))
272        {
273            $update_count = array();
274            parse_attachments($topic_info['forum_id'], $message, $attachments[$row['post_id']], $update_count);
275        }
276
277        if ($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE)
278        {
279            $has_unapproved_posts = true;
280        }
281
282        if ($row['post_visibility'] == ITEM_DELETED)
283        {
284            $has_deleted_posts = true;
285        }
286
287        $post_unread = (isset($topic_tracking_info[$topic_id]) && $row['post_time'] > $topic_tracking_info[$topic_id]) ? true : false;
288
289        $post_row = array(
290            'POST_AUTHOR_FULL'        => get_username_string('full', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']),
291            'POST_AUTHOR_COLOUR'    => get_username_string('colour', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']),
292            'POST_AUTHOR'            => get_username_string('username', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']),
293            'U_POST_AUTHOR'            => get_username_string('profile', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']),
294
295            'POST_DATE'        => $user->format_date($row['post_time']),
296            'POST_SUBJECT'    => $post_subject,
297            'MESSAGE'        => $message,
298            'POST_ID'        => $row['post_id'],
299            'RETURN_TOPIC'    => sprintf($user->lang['RETURN_TOPIC'], '<a href="' . append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=' . $topic_id) . '">', '</a>'),
300
301            'MINI_POST_IMG'            => ($post_unread) ? $user->img('icon_post_target_unread', 'UNREAD_POST') : $user->img('icon_post_target', 'POST'),
302
303            'S_POST_REPORTED'    => ($row['post_reported'] && $auth->acl_get('m_report', $topic_info['forum_id'])),
304            'S_POST_UNAPPROVED'    => (($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE) && $auth->acl_get('m_approve', $topic_info['forum_id'])),
305            'S_POST_DELETED'    => ($row['post_visibility'] == ITEM_DELETED && $auth->acl_get('m_approve', $topic_info['forum_id'])),
306            'S_CHECKED'            => (($submitted_id_list && !in_array(intval($row['post_id']), $submitted_id_list)) || in_array(intval($row['post_id']), $checked_ids)) ? true : false,
307            'S_HAS_ATTACHMENTS'    => (!empty($attachments[$row['post_id']])) ? true : false,
308            'S_FIRST_UNREAD'    => $s_first_unread,
309            'S_UNREAD_VIEW'        => $view == 'unread',
310
311            'U_POST_DETAILS'    => "$url&amp;i=$id&amp;p={$row['post_id']}&amp;mode=post_details",
312            'U_MCP_APPROVE'        => ($auth->acl_get('m_approve', $topic_info['forum_id'])) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&amp;mode=approve_details&amp;p=' . $row['post_id']) : '',
313            'U_MCP_REPORT'        => ($auth->acl_get('m_report', $topic_info['forum_id'])) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=reports&amp;mode=report_details&amp;p=' . $row['post_id']) : '',
314            'U_MINI_POST'        => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'p=' . $row['post_id']) . '#p' . $row['post_id'],
315        );
316
317        /**
318        * Event to modify the template data block for topic reviews in the MCP
319        *
320        * @event core.mcp_topic_review_modify_row
321        * @var    int        id                    ID of the tab we are displaying
322        * @var    string    mode                Mode of the MCP page we are displaying
323        * @var    int        topic_id            The topic ID we are currently reviewing
324        * @var    int        forum_id            The forum ID we are currently in
325        * @var    int        start                Start item of this page
326        * @var    int        current_row_number    Number of the post on this page
327        * @var    array    post_row            Template block array of the current post
328        * @var    array    row                    Array with original post and user data
329        * @var    array    topic_info            Array with topic data
330        * @var    int        total                Total posts count
331        * @since 3.1.4-RC1
332        */
333        $vars = array(
334            'id',
335            'mode',
336            'topic_id',
337            'forum_id',
338            'start',
339            'current_row_number',
340            'post_row',
341            'row',
342            'topic_info',
343            'total',
344        );
345        extract($phpbb_dispatcher->trigger_event('core.mcp_topic_review_modify_row', compact($vars)));
346
347        $template->assign_block_vars('postrow', $post_row);
348
349        // Display not already displayed Attachments for this post, we already parsed them. ;)
350        if (!empty($attachments[$row['post_id']]))
351        {
352            foreach ($attachments[$row['post_id']] as $attachment)
353            {
354                $template->assign_block_vars('postrow.attachment', array(
355                    'DISPLAY_ATTACHMENT'    => $attachment)
356                );
357            }
358        }
359
360        unset($rowset[$current_row_number]);
361    }
362
363    // Display topic icons for split topic
364    $s_topic_icons = false;
365
366    if ($auth->acl_gets('m_split', 'm_merge', (int) $topic_info['forum_id']))
367    {
368        include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx);
369        $s_topic_icons = posting_gen_topic_icons('', $icon_id);
370
371        // Has the user selected a topic for merge?
372        if ($to_topic_id)
373        {
374            $to_topic_info = phpbb_get_topic_data(array($to_topic_id), 'm_merge');
375
376            if (!count($to_topic_info))
377            {
378                $to_topic_id = 0;
379            }
380            else
381            {
382                $to_topic_info = $to_topic_info[$to_topic_id];
383
384                if (!$to_topic_info['enable_icons'] || $auth->acl_get('!f_icons', $topic_info['forum_id']))
385                {
386                    $s_topic_icons = false;
387                }
388            }
389        }
390    }
391
392    $s_hidden_fields = build_hidden_fields(array(
393        'st_old'    => $sort_days,
394        'post_ids'    => $post_id_list,
395    ));
396
397    $base_url = append_sid("{$phpbb_root_path}mcp.$phpEx", "i=$id&amp;t={$topic_info['topic_id']}&amp;mode=$mode&amp;action=$action&amp;to_topic_id=$to_topic_id&amp;posts_per_page=$posts_per_page&amp;st=$sort_days&amp;sk=$sort_key&amp;sd=$sort_dir");
398    if ($posts_per_page)
399    {
400        $pagination->generate_template_pagination($base_url, 'pagination', 'start', $total, $posts_per_page, $start);
401    }
402
403    $topic_row = [
404        'TOPIC_TITLE'        => $topic_info['topic_title'],
405        'U_VIEW_TOPIC'        => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=' . $topic_info['topic_id']),
406
407        'TO_TOPIC_ID'        => $to_topic_id ?: '',
408        'TO_TOPIC_INFO'        => ($to_topic_id) ? sprintf($user->lang['YOU_SELECTED_TOPIC'], $to_topic_id, '<a href="' . append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=' . $to_topic_id) . '">' . $to_topic_info['topic_title'] . '</a>') : '',
409
410        'SPLIT_SUBJECT'        => $subject,
411        'POSTS_PER_PAGE'    => $posts_per_page,
412        'ACTION'            => $action,
413
414        'REPORTED_IMG'        => $user->img('icon_topic_reported', 'POST_REPORTED'),
415        'UNAPPROVED_IMG'    => $user->img('icon_topic_unapproved', 'POST_UNAPPROVED'),
416        'DELETED_IMG'        => $user->img('icon_topic_deleted', 'POST_DELETED_RESTORE'),
417        'INFO_IMG'            => $user->img('icon_post_info', 'VIEW_INFO'),
418
419        'S_MCP_ACTION'        => "$url&amp;i=$id&amp;mode=$mode&amp;action=$action&amp;start=$start",
420        'S_FORUM_SELECT'    => ($to_forum_id) ? make_forum_select($to_forum_id, false, false, true, true, true) : make_forum_select($topic_info['forum_id'], false, false, true, true, true),
421        'S_CAN_SPLIT'        => ($auth->acl_get('m_split', $topic_info['forum_id'])) ? true : false,
422        'S_CAN_MERGE'        => ($auth->acl_get('m_merge', $topic_info['forum_id'])) ? true : false,
423        'S_CAN_DELETE'        => ($auth->acl_get('m_delete', $topic_info['forum_id'])) ? true : false,
424        'S_CAN_APPROVE'        => ($has_unapproved_posts && $auth->acl_get('m_approve', $topic_info['forum_id'])) ? true : false,
425        'S_CAN_RESTORE'        => ($has_deleted_posts && $auth->acl_get('m_approve', $topic_info['forum_id'])) ? true : false,
426        'S_CAN_LOCK'        => ($auth->acl_get('m_lock', $topic_info['forum_id'])) ? true : false,
427        'S_CAN_REPORT'        => ($auth->acl_get('m_report', $topic_info['forum_id'])) ? true : false,
428        'S_CAN_SYNC'        => $auth->acl_get('m_', $topic_info['forum_id']),
429        'S_REPORT_VIEW'        => ($action == 'reports') ? true : false,
430        'S_MERGE_VIEW'        => ($action == 'merge') ? true : false,
431        'S_SPLIT_VIEW'        => ($action == 'split') ? true : false,
432
433        'S_HIDDEN_FIELDS'    => $s_hidden_fields,
434
435        'S_SHOW_TOPIC_ICONS'    => $s_topic_icons,
436        'S_TOPIC_ICON'            => $icon_id,
437
438        'U_SELECT_TOPIC'    => "$url&amp;i=$id&amp;mode=forum_view&amp;action=merge_select" . (($forum_id) ? "&amp;f=$forum_id" : ''),
439
440        'RETURN_TOPIC'        => sprintf($user->lang['RETURN_TOPIC'], '<a href="' . append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t={$topic_info['topic_id']}&amp;start=$start") . '">', '</a>'),
441        'RETURN_FORUM'        => sprintf($user->lang['RETURN_FORUM'], '<a href="' . append_sid("{$phpbb_root_path}viewforum.$phpEx", "f={$topic_info['forum_id']}&amp;start=$start") . '">', '</a>'),
442
443        'TOTAL_POSTS'        => $user->lang('VIEW_TOPIC_POSTS', (int) $total),
444    ];
445
446    /**
447     * Event to modify the template data block for topic data output in the MCP
448     *
449     * @event core.mcp_topic_review_modify_topic_row
450     * @var    string    action                    Moderation action type to be performed with the topic
451     * @var    bool    has_unapproved_posts    Flag indicating if the topic has unapproved posts
452     * @var    int        icon_id                    Split topic icon ID
453     * @var    int        id                        ID of the tab we are displaying
454     * @var    string    mode                    Mode of the MCP page we are displaying
455     * @var    int        topic_id                The topic ID we are currently reviewing
456     * @var    int        forum_id                The forum ID we are currently in
457     * @var    bool    s_topic_icons            Flag indicating if split topic icon to be displayed
458     * @var    int        start                    Start item of this page
459     * @var    string    subject                    Subject of the topic to be split
460     * @var    array    topic_info                Array with topic data
461     * @var    int        to_forum_id                Forum id the topic is being moved to
462     * @var    int        to_topic_id                Topic ID the topic is being merged with
463     * @var    array    topic_row                Topic template data array
464     * @var    int        total                    Total posts count
465     * @since 3.3.5-RC1
466     */
467    $vars = [
468        'action',
469        'has_unapproved_posts',
470        'icon_id',
471        'id',
472        'mode',
473        'topic_id',
474        'forum_id',
475        's_topic_icons',
476        'start',
477        'subject',
478        'topic_info',
479        'to_forum_id',
480        'to_topic_id',
481        'topic_row',
482        'total',
483    ];
484    extract($phpbb_dispatcher->trigger_event('core.mcp_topic_review_modify_topic_row', compact($vars)));
485
486    $template->assign_vars($topic_row);
487}
488
489/**
490* Split topic
491*/
492function split_topic($action, $topic_id, $to_forum_id, $subject)
493{
494    global $db, $template, $user, $phpEx, $phpbb_root_path, $auth, $config, $phpbb_log, $request;
495    global $phpbb_container, $phpbb_dispatcher;
496
497    $post_id_list    = $request->variable('post_id_list', array(0));
498    $forum_id        = $request->variable('forum_id', 0);
499    $start            = $request->variable('start', 0);
500
501    if (!count($post_id_list))
502    {
503        $template->assign_var('MESSAGE', $user->lang['NO_POST_SELECTED']);
504        return;
505    }
506
507    if (!phpbb_check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_split')))
508    {
509        return;
510    }
511
512    $post_id = $post_id_list[0];
513    $post_info = phpbb_get_post_data(array($post_id));
514
515    if (!count($post_info))
516    {
517        $template->assign_var('MESSAGE', $user->lang['NO_POST_SELECTED']);
518        return;
519    }
520
521    $post_info = $post_info[$post_id];
522    $subject = trim($subject);
523
524    /**
525     * Replace Emojis and other 4bit UTF-8 chars not allowed by MySQL to UCR/NCR.
526     * Using their Numeric Character Reference's Hexadecimal notation.
527     */
528    $subject = utf8_encode_ucr($subject);
529
530    // Make some tests
531    if (!$subject)
532    {
533        $template->assign_var('MESSAGE', $user->lang['EMPTY_SUBJECT']);
534        return;
535    }
536
537    if ($to_forum_id <= 0)
538    {
539        $template->assign_var('MESSAGE', $user->lang['NO_DESTINATION_FORUM']);
540        return;
541    }
542
543    $forum_info = phpbb_get_forum_data(array($to_forum_id), 'f_post');
544
545    if (!count($forum_info))
546    {
547        $template->assign_var('MESSAGE', $user->lang['USER_CANNOT_POST']);
548        return;
549    }
550
551    $forum_info = $forum_info[$to_forum_id];
552
553    if ($forum_info['forum_type'] != FORUM_POST)
554    {
555        $template->assign_var('MESSAGE', $user->lang['FORUM_NOT_POSTABLE']);
556        return;
557    }
558
559    $redirect = $request->variable('redirect', build_url(array('quickmod')));
560
561    $s_hidden_fields = build_hidden_fields(array(
562        'i'                => 'main',
563        'post_id_list'    => $post_id_list,
564        'f'                => $forum_id,
565        'mode'            => 'topic_view',
566        'start'            => $start,
567        'action'        => $action,
568        't'                => $topic_id,
569        'redirect'        => $redirect,
570        'subject'        => $subject,
571        'to_forum_id'    => $to_forum_id,
572        'icon'            => $request->variable('icon', 0))
573    );
574
575    if (confirm_box(true))
576    {
577        if ($action == 'split_beyond')
578        {
579            $sort_days = $total = 0;
580            $sort_key = $sort_dir = '';
581            $sort_by_sql = $sort_order_sql = array();
582            phpbb_mcp_sorting('viewtopic', $sort_days, $sort_key, $sort_dir, $sort_by_sql, $sort_order_sql, $total, $forum_id, $topic_id);
583
584            $limit_time_sql = ($sort_days) ? 'AND t.topic_last_post_time >= ' . (time() - ($sort_days * 86400)) : '';
585
586            if ($sort_order_sql[0] == 'u')
587            {
588                $sql = 'SELECT p.post_id, p.forum_id, p.post_visibility
589                    FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u
590                    WHERE p.topic_id = $topic_id
591                        AND p.poster_id = u.user_id
592                        $limit_time_sql
593                    ORDER BY $sort_order_sql";
594            }
595            else
596            {
597                $sql = 'SELECT p.post_id, p.forum_id, p.post_visibility
598                    FROM ' . POSTS_TABLE . " p
599                    WHERE p.topic_id = $topic_id
600                        $limit_time_sql
601                    ORDER BY $sort_order_sql";
602            }
603            $result = $db->sql_query_limit($sql, 0, $start);
604
605            $store = false;
606            $post_id_list = array();
607            while ($row = $db->sql_fetchrow($result))
608            {
609                // If split from selected post (split_beyond), we split the unapproved items too.
610                if (($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE) && !$auth->acl_get('m_approve', $row['forum_id']))
611                {
612//                    continue;
613                }
614
615                // Start to store post_ids as soon as we see the first post that was selected
616                if ($row['post_id'] == $post_id)
617                {
618                    $store = true;
619                }
620
621                if ($store)
622                {
623                    $post_id_list[] = $row['post_id'];
624                }
625            }
626            $db->sql_freeresult($result);
627        }
628
629        if (!count($post_id_list))
630        {
631            trigger_error('NO_POST_SELECTED');
632        }
633
634        $icon_id = $request->variable('icon', 0);
635
636        $sql_ary = array(
637            'forum_id'            => $to_forum_id,
638            'topic_title'        => $subject,
639            'icon_id'            => $icon_id,
640            'topic_visibility'    => 1
641        );
642
643        $sql = 'INSERT INTO ' . TOPICS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
644        $db->sql_query($sql);
645
646        $to_topic_id = $db->sql_nextid();
647        move_posts($post_id_list, $to_topic_id);
648
649        $topic_info = phpbb_get_topic_data(array($topic_id));
650        $topic_info = $topic_info[$topic_id];
651
652        $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_SPLIT_DESTINATION', false, array(
653            'forum_id' => $to_forum_id,
654            'topic_id' => $to_topic_id,
655            $subject
656        ));
657        $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_SPLIT_SOURCE', false, array(
658            'forum_id' => $forum_id,
659            'topic_id' => $topic_id,
660            $topic_info['topic_title']
661        ));
662
663        // Change topic title of first post and write icon_id to post
664        $sql_ary = [
665            'post_subject'        => $subject,
666            'icon_id'            => $icon_id,
667        ];
668        $sql = 'UPDATE ' . POSTS_TABLE . '
669            SET ' . $db->sql_build_array('UPDATE', $sql_ary) . "
670            WHERE post_id = {$post_id_list[0]}";
671        $db->sql_query($sql);
672
673        // Grab data for first post in split topic
674        $sql_array = array(
675            'SELECT'  => 'p.post_id, p.forum_id, p.poster_id, p.post_text, f.enable_indexing',
676            'FROM' => array(
677                POSTS_TABLE => 'p',
678            ),
679            'LEFT_JOIN' => array(
680                array(
681                    'FROM' => array(FORUMS_TABLE => 'f'),
682                    'ON' => 'p.forum_id = f.forum_id',
683                )
684            ),
685            'WHERE' => "post_id = {$post_id_list[0]}",
686        );
687        $sql = $db->sql_build_query('SELECT', $sql_array);
688        $result = $db->sql_query($sql);
689        $first_post_data = $db->sql_fetchrow($result);
690        $db->sql_freeresult($result);
691
692        // Index first post as if it were edited
693        if ($first_post_data['enable_indexing'])
694        {
695            // Select the search method and do some additional checks to ensure it can actually be utilised
696            try
697            {
698                $search_backend_factory = $phpbb_container->get('search.backend_factory');
699                $search = $search_backend_factory->get_active();
700            }
701            catch (\phpbb\search\exception\no_search_backend_found_exception $e)
702            {
703                trigger_error('NO_SUCH_SEARCH_MODULE');
704            }
705
706            $search->index('edit', (int) $first_post_data['post_id'], $first_post_data['post_text'], $subject, (int) $first_post_data['poster_id'], (int) $first_post_data['forum_id']);
707        }
708
709        // Copy topic subscriptions to new topic
710        $sql = 'SELECT user_id, notify_status
711            FROM ' . TOPICS_WATCH_TABLE . '
712            WHERE topic_id = ' . $topic_id;
713        $result = $db->sql_query($sql);
714
715        $sql_ary = array();
716        while ($row = $db->sql_fetchrow($result))
717        {
718            $sql_ary[] = array(
719                'topic_id'        => (int) $to_topic_id,
720                'user_id'        => (int) $row['user_id'],
721                'notify_status'    => (int) $row['notify_status'],
722            );
723        }
724        $db->sql_freeresult($result);
725
726        if (count($sql_ary))
727        {
728            $db->sql_multi_insert(TOPICS_WATCH_TABLE, $sql_ary);
729        }
730
731        // Copy bookmarks to new topic
732        $sql = 'SELECT user_id
733            FROM ' . BOOKMARKS_TABLE . '
734            WHERE topic_id = ' . $topic_id;
735        $result = $db->sql_query($sql);
736
737        $sql_ary = array();
738        while ($row = $db->sql_fetchrow($result))
739        {
740            $sql_ary[] = array(
741                'topic_id'        => (int) $to_topic_id,
742                'user_id'        => (int) $row['user_id'],
743            );
744        }
745        $db->sql_freeresult($result);
746
747        if (count($sql_ary))
748        {
749            $db->sql_multi_insert(BOOKMARKS_TABLE, $sql_ary);
750        }
751
752        $success_msg = 'TOPIC_SPLIT_SUCCESS';
753
754        // Update forum statistics
755        $config->increment('num_topics', 1, false);
756        sync('forum', 'forum_id', [$to_forum_id], true, true);
757
758        // Link back to both topics
759        $return_link = sprintf($user->lang['RETURN_TOPIC'], '<a href="' . append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=' . $post_info['topic_id']) . '">', '</a>') . '<br /><br />' . sprintf($user->lang['RETURN_NEW_TOPIC'], '<a href="' . append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=' . $to_topic_id) . '">', '</a>');
760        $redirect = $request->variable('redirect', "{$phpbb_root_path}viewtopic.$phpEx?t=$to_topic_id");
761        $redirect = reapply_sid($redirect);
762
763        /**
764         * Event to access topic data after split
765         *
766         * @event core.mcp_topic_split_topic_after
767         * @var    string    action            Split action type to be performed with the topic
768         * @var    int        topic_id        The topic ID we are currently splitting
769         * @var    int        forum_id        The forum ID we are currently in
770         * @var    int        start            Start item of this page
771         * @var    string    subject            Subject of the topic to be split
772         * @var    array    topic_info        Array with topic data
773         * @var    int        to_forum_id        Forum id the topic is being moved to
774         * @var    int        to_topic_id        Topic ID the topic is being split to
775         * @since 3.3.5-RC1
776         */
777        $vars = [
778            'action',
779            'topic_id',
780            'forum_id',
781            'start',
782            'subject',
783            'topic_info',
784            'to_forum_id',
785            'to_topic_id',
786        ];
787        extract($phpbb_dispatcher->trigger_event('core.mcp_topic_split_topic_after', compact($vars)));
788
789        meta_refresh(3, $redirect);
790        trigger_error($user->lang[$success_msg] . '<br /><br />' . $return_link);
791    }
792    else
793    {
794        confirm_box(false, ($action == 'split_all') ? 'SPLIT_TOPIC_ALL' : 'SPLIT_TOPIC_BEYOND', $s_hidden_fields);
795    }
796}
797
798/**
799* Merge selected posts into selected topic
800*/
801function merge_posts($topic_id, $to_topic_id)
802{
803    global $db, $template, $user, $phpEx, $phpbb_root_path, $phpbb_log, $request, $phpbb_dispatcher;
804
805    if (!$to_topic_id)
806    {
807        $template->assign_var('MESSAGE', $user->lang['NO_FINAL_TOPIC_SELECTED']);
808        return;
809    }
810
811    $sync_topics = array($topic_id, $to_topic_id);
812
813    $topic_data = phpbb_get_topic_data($sync_topics, 'm_merge');
814
815    if (!count($topic_data) || empty($topic_data[$to_topic_id]))
816    {
817        $template->assign_var('MESSAGE', $user->lang['NO_FINAL_TOPIC_SELECTED']);
818        return;
819    }
820
821    $sync_forums = array();
822    foreach ($topic_data as $data)
823    {
824        $sync_forums[$data['forum_id']] = $data['forum_id'];
825    }
826
827    $topic_data = $topic_data[$to_topic_id];
828
829    $post_id_list    = $request->variable('post_id_list', array(0));
830    $start            = $request->variable('start', 0);
831
832    if (!count($post_id_list))
833    {
834        $template->assign_var('MESSAGE', $user->lang['NO_POST_SELECTED']);
835        return;
836    }
837
838    if (!phpbb_check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_merge')))
839    {
840        return;
841    }
842
843    $redirect = $request->variable('redirect', build_url(array('quickmod')));
844
845    $s_hidden_fields = build_hidden_fields(array(
846        'i'                => 'main',
847        'post_id_list'    => $post_id_list,
848        'to_topic_id'    => $to_topic_id,
849        'mode'            => 'topic_view',
850        'action'        => 'merge_posts',
851        'start'            => $start,
852        'redirect'        => $redirect,
853        't'                => $topic_id)
854    );
855    $return_link = '';
856
857    if (confirm_box(true))
858    {
859        $to_forum_id = $topic_data['forum_id'];
860
861        move_posts($post_id_list, $to_topic_id, false);
862
863        $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_MERGE', false, array(
864            'forum_id' => $to_forum_id,
865            'topic_id' => $to_topic_id,
866            $topic_data['topic_title']
867        ));
868
869        // Message and return links
870        $success_msg = 'POSTS_MERGED_SUCCESS';
871
872        // Does the original topic still exist? If yes, link back to it
873        $sql = 'SELECT forum_id
874            FROM ' . POSTS_TABLE . '
875            WHERE topic_id = ' . $topic_id;
876        $result = $db->sql_query_limit($sql, 1);
877        $row = $db->sql_fetchrow($result);
878        $db->sql_freeresult($result);
879
880        if ($row)
881        {
882            $return_link .= sprintf($user->lang['RETURN_TOPIC'], '<a href="' . append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=' . $topic_id) . '">', '</a>');
883        }
884        else
885        {
886            if (!function_exists('phpbb_update_rows_avoiding_duplicates_notify_status'))
887            {
888                include($phpbb_root_path . 'includes/functions_database_helper.' . $phpEx);
889            }
890
891            // If the topic no longer exist, we will update the topic watch table.
892            phpbb_update_rows_avoiding_duplicates_notify_status($db, TOPICS_WATCH_TABLE, 'topic_id', array($topic_id), $to_topic_id);
893
894            // If the topic no longer exist, we will update the bookmarks table.
895            phpbb_update_rows_avoiding_duplicates($db, BOOKMARKS_TABLE, 'topic_id', array($topic_id), $to_topic_id);
896        }
897
898        // Re-sync the topics and forums because the auto-sync was deactivated in the call of move_posts()
899        sync('topic_reported', 'topic_id', $sync_topics);
900        sync('topic_attachment', 'topic_id', $sync_topics);
901        sync('topic', 'topic_id', $sync_topics, true);
902        sync('forum', 'forum_id', $sync_forums, true, true);
903
904        // Link to the new topic
905        $return_link .= (($return_link) ? '<br /><br />' : '') . sprintf($user->lang['RETURN_NEW_TOPIC'], '<a href="' . append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=' . $to_topic_id) . '">', '</a>');
906        $redirect = $request->variable('redirect', "{$phpbb_root_path}viewtopic.$phpEx?t=$to_topic_id");
907        $redirect = reapply_sid($redirect);
908
909        /**
910         * Perform additional actions after merging posts.
911         *
912         * @event core.mcp_topics_merge_posts_after
913         * @var    int        topic_id        The topic ID from which posts are being moved
914         * @var    int        to_topic_id        The topic ID to which posts are being moved
915         * @since 3.1.11-RC1
916         */
917        $vars = array(
918            'topic_id',
919            'to_topic_id',
920        );
921        extract($phpbb_dispatcher->trigger_event('core.mcp_topics_merge_posts_after', compact($vars)));
922
923        meta_refresh(3, $redirect);
924        trigger_error($user->lang[$success_msg] . '<br /><br />' . $return_link);
925    }
926    else
927    {
928        confirm_box(false, 'MERGE_POSTS', $s_hidden_fields);
929    }
930}