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