diff options
Diffstat (limited to 'phpBB/viewtopic.php')
-rw-r--r-- | phpBB/viewtopic.php | 1091 |
1 files changed, 764 insertions, 327 deletions
diff --git a/phpBB/viewtopic.php b/phpBB/viewtopic.php index f52e04e1a8..bb1f2c925d 100644 --- a/phpBB/viewtopic.php +++ b/phpBB/viewtopic.php @@ -1,10 +1,13 @@ <?php /** * -* @package phpBB3 -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. * */ @@ -17,6 +20,7 @@ $phpEx = substr(strrchr(__FILE__, '.'), 1); include($phpbb_root_path . 'common.' . $phpEx); include($phpbb_root_path . 'includes/functions_display.' . $phpEx); include($phpbb_root_path . 'includes/bbcode.' . $phpEx); +include($phpbb_root_path . 'includes/functions_user.' . $phpEx); // Start session management $user->session_begin(); @@ -44,6 +48,8 @@ $sort_dir = request_var('sd', $default_sort_dir); $update = request_var('update', false); +$pagination = $phpbb_container->get('pagination'); + $s_can_vote = false; /** * @todo normalize? @@ -56,6 +62,8 @@ if (!$topic_id && !$post_id) trigger_error('NO_TOPIC'); } +$phpbb_content_visibility = $phpbb_container->get('content.visibility'); + // Find topic id if user requested a newer or older topic if ($view && !$post_id) { @@ -78,16 +86,15 @@ if ($view && !$post_id) { // Get topic tracking info $topic_tracking_info = get_complete_topic_tracking($forum_id, $topic_id); - $topic_last_read = (isset($topic_tracking_info[$topic_id])) ? $topic_tracking_info[$topic_id] : 0; $sql = 'SELECT post_id, topic_id, forum_id FROM ' . POSTS_TABLE . " WHERE topic_id = $topic_id - " . (($auth->acl_get('m_approve', $forum_id)) ? '' : 'AND post_approved = 1') . " + AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id) . " AND post_time > $topic_last_read AND forum_id = $forum_id - ORDER BY post_time ASC"; + ORDER BY post_time ASC, post_id ASC"; $result = $db->sql_query_limit($sql, 1); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); @@ -138,8 +145,8 @@ if ($view && !$post_id) WHERE forum_id = ' . $row['forum_id'] . " AND topic_moved_id = 0 AND topic_last_post_time $sql_condition {$row['topic_last_post_time']} - " . (($auth->acl_get('m_approve', $row['forum_id'])) ? '' : 'AND topic_approved = 1') . " - ORDER BY topic_last_post_time $sql_ordering"; + AND " . $phpbb_content_visibility->get_visibility_sql('topic', $row['forum_id']) . " + ORDER BY topic_last_post_time $sql_ordering, topic_last_post_id $sql_ordering"; $result = $db->sql_query_limit($sql, 1); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); @@ -159,26 +166,12 @@ if ($view && !$post_id) else { $topic_id = $row['topic_id']; - - // Check for global announcement correctness? - if (!$row['forum_id'] && !$forum_id) - { - trigger_error('NO_TOPIC'); - } - else if ($row['forum_id']) - { - $forum_id = $row['forum_id']; - } + $forum_id = $row['forum_id']; } } } - // Check for global announcement correctness? - if ((!isset($row) || !$row['forum_id']) && !$forum_id) - { - trigger_error('NO_TOPIC'); - } - else if (isset($row) && $row['forum_id']) + if (isset($row) && $row['forum_id']) { $forum_id = $row['forum_id']; } @@ -193,17 +186,10 @@ $sql_array = array( 'FROM' => array(FORUMS_TABLE => 'f'), ); -// Firebird handles two columns of the same name a little differently, this -// addresses that by forcing the forum_id to come from the forums table. -if ($db->sql_layer === 'firebird') -{ - $sql_array['SELECT'] = 'f.forum_id AS forum_id, ' . $sql_array['SELECT']; -} - // The FROM-Order is quite important here, else t.* columns can not be correctly bound. if ($post_id) { - $sql_array['SELECT'] .= ', p.post_approved, p.post_time, p.post_id'; + $sql_array['SELECT'] .= ', p.post_visibility, p.post_time, p.post_id'; $sql_array['FROM'][POSTS_TABLE] = 'p'; } @@ -254,26 +240,8 @@ else $sql_array['WHERE'] = "p.post_id = $post_id AND t.topic_id = p.topic_id"; } -$sql_array['WHERE'] .= ' AND (f.forum_id = t.forum_id'; - -if (!$forum_id) -{ - // If it is a global announcement make sure to set the forum id to a postable forum - $sql_array['WHERE'] .= ' OR (t.topic_type = ' . POST_GLOBAL . ' - AND f.forum_type = ' . FORUM_POST . ')'; -} -else -{ - $sql_array['WHERE'] .= ' OR (t.topic_type = ' . POST_GLOBAL . " - AND f.forum_id = $forum_id)"; -} - -$sql_array['WHERE'] .= ')'; +$sql_array['WHERE'] .= ' AND f.forum_id = t.forum_id'; -// Join to forum table on topic forum_id unless topic forum_id is zero -// whereupon we join on the forum_id passed as a parameter ... this -// is done so navigation, forum name, etc. remain consistent with where -// user clicked to view a global topic $sql = $db->sql_build_query('SELECT', $sql_array); $result = $db->sql_query($sql); $topic_data = $db->sql_fetchrow($result); @@ -292,11 +260,18 @@ if (!$topic_data) } $forum_id = (int) $topic_data['forum_id']; + +// Now we know the forum_id and can check the permissions +if ($topic_data['topic_visibility'] != ITEM_APPROVED && !$auth->acl_get('m_approve', $forum_id)) +{ + trigger_error('NO_TOPIC'); +} + // This is for determining where we are (page) if ($post_id) { // are we where we are supposed to be? - if (!$topic_data['post_approved'] && !$auth->acl_get('m_approve', $topic_data['forum_id'])) + if (($topic_data['post_visibility'] == ITEM_UNAPPROVED || $topic_data['post_visibility'] == ITEM_REAPPROVE) && !$auth->acl_get('m_approve', $topic_data['forum_id'])) { // If post_id was submitted, we try at least to display the topic as a last resort... if ($topic_id) @@ -312,7 +287,7 @@ if ($post_id) if ($sort_dir == $check_sort) { - $topic_data['prev_posts'] = ($auth->acl_get('m_approve', $forum_id)) ? $topic_data['topic_replies_real'] : $topic_data['topic_replies']; + $topic_data['prev_posts'] = $phpbb_content_visibility->get_count('topic_posts', $topic_data, $forum_id) - 1; } else { @@ -324,7 +299,7 @@ if ($post_id) $sql = 'SELECT COUNT(p.post_id) AS prev_posts FROM ' . POSTS_TABLE . " p WHERE p.topic_id = {$topic_data['topic_id']} - " . ((!$auth->acl_get('m_approve', $forum_id)) ? 'AND p.post_approved = 1' : ''); + AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id, 'p.'); if ($sort_dir == 'd') { @@ -344,8 +319,7 @@ if ($post_id) } $topic_id = (int) $topic_data['topic_id']; -// -$topic_replies = ($auth->acl_get('m_approve', $forum_id)) ? $topic_data['topic_replies_real'] : $topic_data['topic_replies']; +$topic_replies = $phpbb_content_visibility->get_count('topic_posts', $topic_data, $forum_id) - 1; // Check sticky/announcement time limit if (($topic_data['topic_type'] == POST_STICKY || $topic_data['topic_type'] == POST_ANNOUNCE) && $topic_data['topic_time_limit'] && ($topic_data['topic_time'] + $topic_data['topic_time_limit']) < time()) @@ -362,13 +336,41 @@ if (($topic_data['topic_type'] == POST_STICKY || $topic_data['topic_type'] == PO // Setup look and feel $user->setup('viewtopic', $topic_data['forum_style']); -if (!$topic_data['topic_approved'] && !$auth->acl_get('m_approve', $forum_id)) -{ - trigger_error('NO_TOPIC'); -} +$overrides_f_read_check = false; +$overrides_forum_password_check = false; +$topic_tracking_info = isset($topic_tracking_info) ? $topic_tracking_info : null; + +/** +* Event to apply extra permissions and to override original phpBB's f_read permission and forum password check +* on viewtopic access +* +* @event core.viewtopic_before_f_read_check +* @var int forum_id The forum id from where the topic belongs +* @var int topic_id The id of the topic the user tries to access +* @var int post_id The id of the post the user tries to start viewing at. +* It may be 0 for none given. +* @var array topic_data All the information from the topic and forum tables for this topic +* It includes posts information if post_id is not 0 +* @var bool overrides_f_read_check Set true to remove f_read check afterwards +* @var bool overrides_forum_password_check Set true to remove forum_password check afterwards +* @var array topic_tracking_info Information upon calling get_topic_tracking() +* Set it to NULL to allow auto-filling later. +* Set it to an array to override original data. +* @since 3.1.3-RC1 +*/ +$vars = array( + 'forum_id', + 'topic_id', + 'post_id', + 'topic_data', + 'overrides_f_read_check', + 'overrides_forum_password_check', + 'topic_tracking_info', +); +extract($phpbb_dispatcher->trigger_event('core.viewtopic_before_f_read_check', compact($vars))); // Start auth check -if (!$auth->acl_get('f_read', $forum_id)) +if (!$overrides_f_read_check && !$auth->acl_get('f_read', $forum_id)) { if ($user->data['user_id'] != ANONYMOUS) { @@ -380,28 +382,15 @@ if (!$auth->acl_get('f_read', $forum_id)) // Forum is passworded ... check whether access has been granted to this // user this session, if not show login box -if ($topic_data['forum_password']) +if (!$overrides_forum_password_check && $topic_data['forum_password']) { login_forum_box($topic_data); } -// Redirect to login or to the correct post upon emailed notification links -if (isset($_GET['e'])) +// Redirect to login upon emailed notification links if user is not logged in. +if (isset($_GET['e']) && $user->data['user_id'] == ANONYMOUS) { - $jump_to = request_var('e', 0); - - $redirect_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id"); - - if ($user->data['user_id'] == ANONYMOUS) - { - login_box($redirect_url . "&p=$post_id&e=$jump_to", $user->lang['LOGIN_NOTIFY_TOPIC']); - } - - if ($jump_to > 0) - { - // We direct the already logged in user to the correct post... - redirect($redirect_url . ((!$post_id) ? "&p=$jump_to" : "&p=$post_id") . "#p$jump_to"); - } + login_box(build_url('e') . '#unread', $user->lang['LOGIN_NOTIFY_TOPIC']); } // What is start equal to? @@ -432,7 +421,7 @@ if (!isset($topic_tracking_info)) $limit_days = array(0 => $user->lang['ALL_POSTS'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); $sort_by_text = array('a' => $user->lang['AUTHOR'], 't' => $user->lang['POST_TIME'], 's' => $user->lang['SUBJECT']); -$sort_by_sql = array('a' => array('u.username_clean', 'p.post_id'), 't' => 'p.post_time', 's' => array('p.post_subject', 'p.post_id')); +$sort_by_sql = array('a' => array('u.username_clean', 'p.post_id'), 't' => array('p.post_time', 'p.post_id'), 's' => array('p.post_subject', 'p.post_id')); $join_user_sql = array('a' => true, 't' => false, 's' => false); $s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = ''; @@ -449,7 +438,7 @@ if ($sort_days) FROM ' . POSTS_TABLE . " WHERE topic_id = $topic_id AND post_time >= $min_post_time - " . (($auth->acl_get('m_approve', $forum_id)) ? '' : 'AND post_approved = 1'); + AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id); $result = $db->sql_query($sql); $total_posts = (int) $db->sql_fetchfield('num_posts'); $db->sql_freeresult($result); @@ -479,10 +468,7 @@ if ($hilit_words) } // Make sure $start is set to the last page if it exceeds the amount -if ($start < 0 || $start >= $total_posts) -{ - $start = ($start < 0) ? 0 : floor(($total_posts - 1) / $config['posts_per_page']) * $config['posts_per_page']; -} +$start = $pagination->validate_start($start, $config['posts_per_page'], $total_posts); // General Viewtopic URL for return links $viewtopic_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id" . (($start == 0) ? '' : "&start=$start") . ((strlen($u_sort_param)) ? "&$u_sort_param" : '') . (($highlight_match) ? "&hilit=$highlight" : '')); @@ -490,11 +476,13 @@ $viewtopic_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&a // Are we watching this topic? $s_watching_topic = array( 'link' => '', + 'link_toggle' => '', 'title' => '', + 'title_toggle' => '', 'is_watching' => false, ); -if (($config['email_enable'] || $config['jab_enable']) && $config['allow_topic_notify']) +if ($config['allow_topic_notify']) { $notify_status = (isset($topic_data['notify_status'])) ? $topic_data['notify_status'] : null; watch_topic_forum('topic', $s_watching_topic, $user->data['user_id'], $forum_id, $topic_id, $notify_status, $start, $topic_data['topic_title']); @@ -527,11 +515,21 @@ if ($config['allow_bookmarks'] && $user->data['is_registered'] && request_var('b AND topic_id = $topic_id"; $db->sql_query($sql); } - $message = (($topic_data['bookmarked']) ? $user->lang['BOOKMARK_REMOVED'] : $user->lang['BOOKMARK_ADDED']) . '<br /><br />' . sprintf($user->lang['RETURN_TOPIC'], '<a href="' . $viewtopic_url . '">', '</a>'); + $message = (($topic_data['bookmarked']) ? $user->lang['BOOKMARK_REMOVED'] : $user->lang['BOOKMARK_ADDED']); + + if (!$request->is_ajax()) + { + $message .= '<br /><br />' . $user->lang('RETURN_TOPIC', '<a href="' . $viewtopic_url . '">', '</a>'); + } } else { - $message = $user->lang['BOOKMARK_ERR'] . '<br /><br />' . sprintf($user->lang['RETURN_TOPIC'], '<a href="' . $viewtopic_url . '">', '</a>'); + $message = $user->lang['BOOKMARK_ERR']; + + if (!$request->is_ajax()) + { + $message .= '<br /><br />' . $user->lang('RETURN_TOPIC', '<a href="' . $viewtopic_url . '">', '</a>'); + } } meta_refresh(3, $viewtopic_url); @@ -558,22 +556,45 @@ gen_forum_auth_level('topic', $forum_id, $topic_data['forum_status']); // Quick mod tools $allow_change_type = ($auth->acl_get('m_', $forum_id) || ($user->data['is_registered'] && $user->data['user_id'] == $topic_data['topic_poster'])) ? true : false; -$topic_mod = ''; -$topic_mod .= ($auth->acl_get('m_lock', $forum_id) || ($auth->acl_get('f_user_lock', $forum_id) && $user->data['is_registered'] && $user->data['user_id'] == $topic_data['topic_poster'] && $topic_data['topic_status'] == ITEM_UNLOCKED)) ? (($topic_data['topic_status'] == ITEM_UNLOCKED) ? '<option value="lock">' . $user->lang['LOCK_TOPIC'] . '</option>' : '<option value="unlock">' . $user->lang['UNLOCK_TOPIC'] . '</option>') : ''; -$topic_mod .= ($auth->acl_get('m_delete', $forum_id)) ? '<option value="delete_topic">' . $user->lang['DELETE_TOPIC'] . '</option>' : ''; -$topic_mod .= ($auth->acl_get('m_move', $forum_id) && $topic_data['topic_status'] != ITEM_MOVED) ? '<option value="move">' . $user->lang['MOVE_TOPIC'] . '</option>' : ''; -$topic_mod .= ($auth->acl_get('m_split', $forum_id)) ? '<option value="split">' . $user->lang['SPLIT_TOPIC'] . '</option>' : ''; -$topic_mod .= ($auth->acl_get('m_merge', $forum_id)) ? '<option value="merge">' . $user->lang['MERGE_POSTS'] . '</option>' : ''; -$topic_mod .= ($auth->acl_get('m_merge', $forum_id)) ? '<option value="merge_topic">' . $user->lang['MERGE_TOPIC'] . '</option>' : ''; -$topic_mod .= ($auth->acl_get('m_move', $forum_id)) ? '<option value="fork">' . $user->lang['FORK_TOPIC'] . '</option>' : ''; -$topic_mod .= ($allow_change_type && $auth->acl_gets('f_sticky', 'f_announce', $forum_id) && $topic_data['topic_type'] != POST_NORMAL) ? '<option value="make_normal">' . $user->lang['MAKE_NORMAL'] . '</option>' : ''; -$topic_mod .= ($allow_change_type && $auth->acl_get('f_sticky', $forum_id) && $topic_data['topic_type'] != POST_STICKY) ? '<option value="make_sticky">' . $user->lang['MAKE_STICKY'] . '</option>' : ''; -$topic_mod .= ($allow_change_type && $auth->acl_get('f_announce', $forum_id) && $topic_data['topic_type'] != POST_ANNOUNCE) ? '<option value="make_announce">' . $user->lang['MAKE_ANNOUNCE'] . '</option>' : ''; -$topic_mod .= ($allow_change_type && $auth->acl_get('f_announce', $forum_id) && $topic_data['topic_type'] != POST_GLOBAL) ? '<option value="make_global">' . $user->lang['MAKE_GLOBAL'] . '</option>' : ''; -$topic_mod .= ($auth->acl_get('m_', $forum_id)) ? '<option value="topic_logs">' . $user->lang['VIEW_TOPIC_LOGS'] . '</option>' : ''; +$s_quickmod_action = append_sid( + "{$phpbb_root_path}mcp.$phpEx", + array( + 'f' => $forum_id, + 't' => $topic_id, + 'start' => $start, + 'quickmod' => 1, + 'redirect' => urlencode(str_replace('&', '&', $viewtopic_url)), + ), + true, + $user->session_id +); -// If we've got a hightlight set pass it on to pagination. -$pagination = generate_pagination(append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id" . ((strlen($u_sort_param)) ? "&$u_sort_param" : '') . (($highlight_match) ? "&hilit=$highlight" : '')), $total_posts, $config['posts_per_page'], $start); +$quickmod_array = array( +// 'key' => array('LANG_KEY', $userHasPermissions), + + 'lock' => array('LOCK_TOPIC', ($topic_data['topic_status'] == ITEM_UNLOCKED) && ($auth->acl_get('m_lock', $forum_id) || ($auth->acl_get('f_user_lock', $forum_id) && $user->data['is_registered'] && $user->data['user_id'] == $topic_data['topic_poster']))), + 'unlock' => array('UNLOCK_TOPIC', ($topic_data['topic_status'] != ITEM_UNLOCKED) && ($auth->acl_get('m_lock', $forum_id))), + 'delete_topic' => array('DELETE_TOPIC', ($auth->acl_get('m_delete', $forum_id) || (($topic_data['topic_visibility'] != ITEM_DELETED) && $auth->acl_get('m_softdelete', $forum_id)))), + 'restore_topic' => array('RESTORE_TOPIC', (($topic_data['topic_visibility'] == ITEM_DELETED) && $auth->acl_get('m_approve', $forum_id))), + 'move' => array('MOVE_TOPIC', $auth->acl_get('m_move', $forum_id) && $topic_data['topic_status'] != ITEM_MOVED), + 'split' => array('SPLIT_TOPIC', $auth->acl_get('m_split', $forum_id)), + 'merge' => array('MERGE_POSTS', $auth->acl_get('m_merge', $forum_id)), + 'merge_topic' => array('MERGE_TOPIC', $auth->acl_get('m_merge', $forum_id)), + 'fork' => array('FORK_TOPIC', $auth->acl_get('m_move', $forum_id)), + 'make_normal' => array('MAKE_NORMAL', ($allow_change_type && $auth->acl_gets('f_sticky', 'f_announce', $forum_id) && $topic_data['topic_type'] != POST_NORMAL)), + 'make_sticky' => array('MAKE_STICKY', ($allow_change_type && $auth->acl_get('f_sticky', $forum_id) && $topic_data['topic_type'] != POST_STICKY)), + 'make_announce' => array('MAKE_ANNOUNCE', ($allow_change_type && $auth->acl_get('f_announce', $forum_id) && $topic_data['topic_type'] != POST_ANNOUNCE)), + 'make_global' => array('MAKE_GLOBAL', ($allow_change_type && $auth->acl_get('f_announce', $forum_id) && $topic_data['topic_type'] != POST_GLOBAL)), + 'topic_logs' => array('VIEW_TOPIC_LOGS', $auth->acl_get('m_', $forum_id)), +); + +foreach($quickmod_array as $option => $qm_ary) +{ + if (!empty($qm_ary[1])) + { + phpbb_add_quickmod_option($s_quickmod_action, $option, $qm_ary[0]); + } +} // Navigation links generate_forum_nav($topic_data); @@ -612,6 +633,42 @@ if (!empty($_EXTRA_URL)) } } +// If we've got a hightlight set pass it on to pagination. +$base_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id" . ((strlen($u_sort_param)) ? "&$u_sort_param" : '') . (($highlight_match) ? "&hilit=$highlight" : '')); + +/** +* Event to modify data before template variables are being assigned +* +* @event core.viewtopic_assign_template_vars_before +* @var string base_url URL to be passed to generate pagination +* @var int forum_id Forum ID +* @var int post_id Post ID +* @var array quickmod_array Array with quick moderation options data +* @var int start Pagination information +* @var array topic_data Array with topic data +* @var int topic_id Topic ID +* @var array topic_tracking_info Array with topic tracking data +* @var int total_posts Topic total posts count +* @var string viewtopic_url URL to the topic page +* @since 3.1.0-RC4 +* @change 3.1.2-RC1 Added viewtopic_url +*/ +$vars = array( + 'base_url', + 'forum_id', + 'post_id', + 'quickmod_array', + 'start', + 'topic_data', + 'topic_id', + 'topic_tracking_info', + 'total_posts', + 'viewtopic_url', +); +extract($phpbb_dispatcher->trigger_event('core.viewtopic_assign_template_vars_before', compact($vars))); + +$pagination->generate_template_pagination($base_url, 'pagination', 'start', $total_posts, $config['posts_per_page'], $start); + // Send vars to template $template->assign_vars(array( 'FORUM_ID' => $forum_id, @@ -625,27 +682,21 @@ $template->assign_vars(array( 'TOPIC_AUTHOR_COLOUR' => get_username_string('colour', $topic_data['topic_poster'], $topic_data['topic_first_poster_name'], $topic_data['topic_first_poster_colour']), 'TOPIC_AUTHOR' => get_username_string('username', $topic_data['topic_poster'], $topic_data['topic_first_poster_name'], $topic_data['topic_first_poster_colour']), - 'PAGINATION' => $pagination, - 'PAGE_NUMBER' => on_page($total_posts, $config['posts_per_page'], $start), - 'TOTAL_POSTS' => ($total_posts == 1) ? $user->lang['VIEW_TOPIC_POST'] : sprintf($user->lang['VIEW_TOPIC_POSTS'], $total_posts), + 'TOTAL_POSTS' => $user->lang('VIEW_TOPIC_POSTS', (int) $total_posts), 'U_MCP' => ($auth->acl_get('m_', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", "i=main&mode=topic_view&f=$forum_id&t=$topic_id" . (($start == 0) ? '' : "&start=$start") . ((strlen($u_sort_param)) ? "&$u_sort_param" : ''), true, $user->session_id) : '', - 'MODERATORS' => (isset($forum_moderators[$forum_id]) && sizeof($forum_moderators[$forum_id])) ? implode(', ', $forum_moderators[$forum_id]) : '', + 'MODERATORS' => (isset($forum_moderators[$forum_id]) && sizeof($forum_moderators[$forum_id])) ? implode($user->lang['COMMA_SEPARATOR'], $forum_moderators[$forum_id]) : '', 'POST_IMG' => ($topic_data['forum_status'] == ITEM_LOCKED) ? $user->img('button_topic_locked', 'FORUM_LOCKED') : $user->img('button_topic_new', 'POST_NEW_TOPIC'), 'QUOTE_IMG' => $user->img('icon_post_quote', 'REPLY_WITH_QUOTE'), 'REPLY_IMG' => ($topic_data['forum_status'] == ITEM_LOCKED || $topic_data['topic_status'] == ITEM_LOCKED) ? $user->img('button_topic_locked', 'TOPIC_LOCKED') : $user->img('button_topic_reply', 'REPLY_TO_TOPIC'), 'EDIT_IMG' => $user->img('icon_post_edit', 'EDIT_POST'), 'DELETE_IMG' => $user->img('icon_post_delete', 'DELETE_POST'), + 'DELETED_IMG' => $user->img('icon_topic_deleted', 'POST_DELETED_RESTORE'), 'INFO_IMG' => $user->img('icon_post_info', 'VIEW_INFO'), 'PROFILE_IMG' => $user->img('icon_user_profile', 'READ_PROFILE'), 'SEARCH_IMG' => $user->img('icon_user_search', 'SEARCH_USER_POSTS'), 'PM_IMG' => $user->img('icon_contact_pm', 'SEND_PRIVATE_MESSAGE'), 'EMAIL_IMG' => $user->img('icon_contact_email', 'SEND_EMAIL'), - 'WWW_IMG' => $user->img('icon_contact_www', 'VISIT_WEBSITE'), - 'ICQ_IMG' => $user->img('icon_contact_icq', 'ICQ'), - 'AIM_IMG' => $user->img('icon_contact_aim', 'AIM'), - 'MSN_IMG' => $user->img('icon_contact_msnm', 'MSNM'), - 'YIM_IMG' => $user->img('icon_contact_yahoo', 'YIM'), 'JABBER_IMG' => $user->img('icon_contact_jabber', 'JABBER') , 'REPORT_IMG' => $user->img('icon_post_report', 'REPORT_POST'), 'REPORTED_IMG' => $user->img('icon_topic_reported', 'POST_REPORTED'), @@ -658,10 +709,11 @@ $template->assign_vars(array( 'S_SELECT_SORT_DAYS' => $s_limit_days, 'S_SINGLE_MODERATOR' => (!empty($forum_moderators[$forum_id]) && sizeof($forum_moderators[$forum_id]) > 1) ? false : true, 'S_TOPIC_ACTION' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id" . (($start == 0) ? '' : "&start=$start")), - 'S_TOPIC_MOD' => ($topic_mod != '') ? '<select name="action" id="quick-mod-select">' . $topic_mod . '</select>' : '', - 'S_MOD_ACTION' => append_sid("{$phpbb_root_path}mcp.$phpEx", "f=$forum_id&t=$topic_id" . (($start == 0) ? '' : "&start=$start") . "&quickmod=1&redirect=" . urlencode(str_replace('&', '&', $viewtopic_url)), true, $user->session_id), + 'S_MOD_ACTION' => $s_quickmod_action, + 'L_RETURN_TO_FORUM' => $user->lang('RETURN_TO', $topic_data['forum_name']), 'S_VIEWTOPIC' => true, + 'S_UNREAD_VIEW' => $view == 'unread', 'S_DISPLAY_SEARCHBOX' => ($auth->acl_get('u_search') && $auth->acl_get('f_search', $forum_id) && $config['load_search']) ? true : false, 'S_SEARCHBOX_ACTION' => append_sid("{$phpbb_root_path}search.$phpEx"), 'S_SEARCH_LOCAL_HIDDEN_FIELDS' => build_hidden_fields($s_search_hidden_fields), @@ -673,18 +725,23 @@ $template->assign_vars(array( 'U_TOPIC' => "{$server_path}viewtopic.$phpEx?f=$forum_id&t=$topic_id", 'U_FORUM' => $server_path, 'U_VIEW_TOPIC' => $viewtopic_url, + 'U_CANONICAL' => generate_board_url() . '/' . append_sid("viewtopic.$phpEx", "t=$topic_id" . (($start) ? "&start=$start" : ''), true, ''), 'U_VIEW_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id), 'U_VIEW_OLDER_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id&view=previous"), 'U_VIEW_NEWER_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id&view=next"), 'U_PRINT_TOPIC' => ($auth->acl_get('f_print', $forum_id)) ? $viewtopic_url . '&view=print' : '', 'U_EMAIL_TOPIC' => ($auth->acl_get('f_email', $forum_id) && $config['email_enable']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=email&t=$topic_id") : '', - 'U_WATCH_TOPIC' => $s_watching_topic['link'], - 'L_WATCH_TOPIC' => $s_watching_topic['title'], + 'U_WATCH_TOPIC' => $s_watching_topic['link'], + 'U_WATCH_TOPIC_TOGGLE' => $s_watching_topic['link_toggle'], + 'S_WATCH_TOPIC_TITLE' => $s_watching_topic['title'], + 'S_WATCH_TOPIC_TOGGLE' => $s_watching_topic['title_toggle'], 'S_WATCHING_TOPIC' => $s_watching_topic['is_watching'], 'U_BOOKMARK_TOPIC' => ($user->data['is_registered'] && $config['allow_bookmarks']) ? $viewtopic_url . '&bookmark=1&hash=' . generate_link_hash("topic_$topic_id") : '', - 'L_BOOKMARK_TOPIC' => ($user->data['is_registered'] && $config['allow_bookmarks'] && $topic_data['bookmarked']) ? $user->lang['BOOKMARK_TOPIC_REMOVE'] : $user->lang['BOOKMARK_TOPIC'], + 'S_BOOKMARK_TOPIC' => ($user->data['is_registered'] && $config['allow_bookmarks'] && $topic_data['bookmarked']) ? $user->lang['BOOKMARK_TOPIC_REMOVE'] : $user->lang['BOOKMARK_TOPIC'], + 'S_BOOKMARK_TOGGLE' => (!$user->data['is_registered'] || !$config['allow_bookmarks'] || !$topic_data['bookmarked']) ? $user->lang['BOOKMARK_TOPIC_REMOVE'] : $user->lang['BOOKMARK_TOPIC'], + 'S_BOOKMARKED_TOPIC' => ($user->data['is_registered'] && $config['allow_bookmarks'] && $topic_data['bookmarked']) ? true : false, 'U_POST_NEW_TOPIC' => ($auth->acl_get('f_post', $forum_id) || $user->data['user_id'] == ANONYMOUS) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=post&f=$forum_id") : '', 'U_POST_REPLY_TOPIC' => ($auth->acl_get('f_reply', $forum_id) || $user->data['user_id'] == ANONYMOUS) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=reply&f=$forum_id&t=$topic_id") : '', @@ -702,10 +759,12 @@ if (!empty($topic_data['poll_start'])) ORDER BY o.poll_option_id"; $result = $db->sql_query($sql); - $poll_info = array(); + $poll_info = $vote_counts = array(); while ($row = $db->sql_fetchrow($result)) { $poll_info[] = $row; + $option_id = (int) $row['poll_option_id']; + $vote_counts[$option_id] = (int) $row['poll_option_total']; } $db->sql_freeresult($result); @@ -729,9 +788,9 @@ if (!empty($topic_data['poll_start'])) // Cookie based guest tracking ... I don't like this but hum ho // it's oft requested. This relies on "nice" users who don't feel // the need to delete cookies to mess with results. - if (isset($_COOKIE[$config['cookie_name'] . '_poll_' . $topic_id])) + if ($request->is_set($config['cookie_name'] . '_poll_' . $topic_id, \phpbb\request\request_interface::COOKIE)) { - $cur_voted_id = explode(',', $_COOKIE[$config['cookie_name'] . '_poll_' . $topic_id]); + $cur_voted_id = explode(',', $request->variable($config['cookie_name'] . '_poll_' . $topic_id, '', true, \phpbb\request\request_interface::COOKIE)); $cur_voted_id = array_map('intval', $cur_voted_id); } } @@ -745,6 +804,36 @@ if (!empty($topic_data['poll_start'])) ($auth->acl_get('f_votechg', $forum_id) && $topic_data['poll_vote_change']))) ? true : false; $s_display_results = (!$s_can_vote || ($s_can_vote && sizeof($cur_voted_id)) || $view == 'viewpoll') ? true : false; + /** + * Event to manipulate the poll data + * + * @event core.viewtopic_modify_poll_data + * @var array cur_voted_id Array with options' IDs current user has voted for + * @var int forum_id The topic's forum id + * @var array poll_info Array with the poll information + * @var bool s_can_vote Flag indicating if a user can vote + * @var bool s_display_results Flag indicating if results or poll options should be displayed + * @var int topic_id The id of the topic the user tries to access + * @var array topic_data All the information from the topic and forum tables for this topic + * @var string viewtopic_url URL to the topic page + * @var array vote_counts Array with the vote counts for every poll option + * @var array voted_id Array with updated options' IDs current user is voting for + * @since 3.1.5-RC1 + */ + $vars = array( + 'cur_voted_id', + 'forum_id', + 'poll_info', + 's_can_vote', + 's_display_results', + 'topic_id', + 'topic_data', + 'viewtopic_url', + 'vote_counts', + 'voted_id', + ); + extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_poll_data', compact($vars))); + if ($update && $s_can_vote) { @@ -787,6 +876,8 @@ if (!empty($topic_data['poll_start'])) AND topic_id = ' . (int) $topic_id; $db->sql_query($sql); + $vote_counts[$option]++; + if ($user->data['is_registered']) { $sql_ary = array( @@ -811,6 +902,8 @@ if (!empty($topic_data['poll_start'])) AND topic_id = ' . (int) $topic_id; $db->sql_query($sql); + $vote_counts[$option]--; + if ($user->data['is_registered']) { $sql = 'DELETE FROM ' . POLL_VOTES_TABLE . ' @@ -834,76 +927,77 @@ if (!empty($topic_data['poll_start'])) $db->sql_query($sql); $redirect_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id" . (($start == 0) ? '' : "&start=$start")); + $message = $user->lang['VOTE_SUBMITTED'] . '<br /><br />' . sprintf($user->lang['RETURN_TOPIC'], '<a href="' . $redirect_url . '">', '</a>'); + + if ($request->is_ajax()) + { + // Filter out invalid options + $valid_user_votes = array_intersect(array_keys($vote_counts), $voted_id); + + $data = array( + 'NO_VOTES' => $user->lang['NO_VOTES'], + 'success' => true, + 'user_votes' => array_flip($valid_user_votes), + 'vote_counts' => $vote_counts, + 'total_votes' => array_sum($vote_counts), + 'can_vote' => !sizeof($valid_user_votes) || ($auth->acl_get('f_votechg', $forum_id) && $topic_data['poll_vote_change']), + ); + $json_response = new \phpbb\json_response(); + $json_response->send($data); + } meta_refresh(5, $redirect_url); - trigger_error($user->lang['VOTE_SUBMITTED'] . '<br /><br />' . sprintf($user->lang['RETURN_TOPIC'], '<a href="' . $redirect_url . '">', '</a>')); + trigger_error($message); } $poll_total = 0; + $poll_most = 0; foreach ($poll_info as $poll_option) { $poll_total += $poll_option['poll_option_total']; + $poll_most = ($poll_option['poll_option_total'] >= $poll_most) ? $poll_option['poll_option_total'] : $poll_most; } - if ($poll_info[0]['bbcode_bitfield']) - { - $poll_bbcode = new bbcode(); - } - else - { - $poll_bbcode = false; - } + $parse_flags = ($poll_info[0]['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES; for ($i = 0, $size = sizeof($poll_info); $i < $size; $i++) { - $poll_info[$i]['poll_option_text'] = censor_text($poll_info[$i]['poll_option_text']); - - if ($poll_bbcode !== false) - { - $poll_bbcode->bbcode_second_pass($poll_info[$i]['poll_option_text'], $poll_info[$i]['bbcode_uid'], $poll_option['bbcode_bitfield']); - } - - $poll_info[$i]['poll_option_text'] = bbcode_nl2br($poll_info[$i]['poll_option_text']); - $poll_info[$i]['poll_option_text'] = smiley_text($poll_info[$i]['poll_option_text']); - } - - $topic_data['poll_title'] = censor_text($topic_data['poll_title']); - - if ($poll_bbcode !== false) - { - $poll_bbcode->bbcode_second_pass($topic_data['poll_title'], $poll_info[0]['bbcode_uid'], $poll_info[0]['bbcode_bitfield']); + $poll_info[$i]['poll_option_text'] = generate_text_for_display($poll_info[$i]['poll_option_text'], $poll_info[$i]['bbcode_uid'], $poll_option['bbcode_bitfield'], $parse_flags, true); } - $topic_data['poll_title'] = bbcode_nl2br($topic_data['poll_title']); - $topic_data['poll_title'] = smiley_text($topic_data['poll_title']); - - unset($poll_bbcode); + $topic_data['poll_title'] = generate_text_for_display($topic_data['poll_title'], $poll_info[0]['bbcode_uid'], $poll_info[0]['bbcode_bitfield'], $parse_flags, true); + $poll_template_data = $poll_options_template_data = array(); foreach ($poll_info as $poll_option) { $option_pct = ($poll_total > 0) ? $poll_option['poll_option_total'] / $poll_total : 0; $option_pct_txt = sprintf("%.1d%%", round($option_pct * 100)); - - $template->assign_block_vars('poll_option', array( - 'POLL_OPTION_ID' => $poll_option['poll_option_id'], - 'POLL_OPTION_CAPTION' => $poll_option['poll_option_text'], - 'POLL_OPTION_RESULT' => $poll_option['poll_option_total'], - 'POLL_OPTION_PERCENT' => $option_pct_txt, - 'POLL_OPTION_PCT' => round($option_pct * 100), - 'POLL_OPTION_IMG' => $user->img('poll_center', $option_pct_txt, round($option_pct * 250)), - 'POLL_OPTION_VOTED' => (in_array($poll_option['poll_option_id'], $cur_voted_id)) ? true : false) + $option_pct_rel = ($poll_most > 0) ? $poll_option['poll_option_total'] / $poll_most : 0; + $option_pct_rel_txt = sprintf("%.1d%%", round($option_pct_rel * 100)); + $option_most_votes = ($poll_option['poll_option_total'] > 0 && $poll_option['poll_option_total'] == $poll_most) ? true : false; + + $poll_options_template_data[] = array( + 'POLL_OPTION_ID' => $poll_option['poll_option_id'], + 'POLL_OPTION_CAPTION' => $poll_option['poll_option_text'], + 'POLL_OPTION_RESULT' => $poll_option['poll_option_total'], + 'POLL_OPTION_PERCENT' => $option_pct_txt, + 'POLL_OPTION_PERCENT_REL' => $option_pct_rel_txt, + 'POLL_OPTION_PCT' => round($option_pct * 100), + 'POLL_OPTION_WIDTH' => round($option_pct * 250), + 'POLL_OPTION_VOTED' => (in_array($poll_option['poll_option_id'], $cur_voted_id)) ? true : false, + 'POLL_OPTION_MOST_VOTES' => $option_most_votes, ); } $poll_end = $topic_data['poll_length'] + $topic_data['poll_start']; - $template->assign_vars(array( + $poll_template_data = array( 'POLL_QUESTION' => $topic_data['poll_title'], 'TOTAL_VOTES' => $poll_total, 'POLL_LEFT_CAP_IMG' => $user->img('poll_left'), 'POLL_RIGHT_CAP_IMG'=> $user->img('poll_right'), - 'L_MAX_VOTES' => ($topic_data['poll_max_options'] == 1) ? $user->lang['MAX_OPTION_SELECT'] : sprintf($user->lang['MAX_OPTIONS_SELECT'], $topic_data['poll_max_options']), + 'L_MAX_VOTES' => $user->lang('MAX_OPTIONS_SELECT', (int) $topic_data['poll_max_options']), 'L_POLL_LENGTH' => ($topic_data['poll_length']) ? sprintf($user->lang[($poll_end > time()) ? 'POLL_RUN_TILL' : 'POLL_ENDED_AT'], $user->format_date($poll_end)) : '', 'S_HAS_POLL' => true, @@ -912,10 +1006,46 @@ if (!empty($topic_data['poll_start'])) 'S_IS_MULTI_CHOICE' => ($topic_data['poll_max_options'] > 1) ? true : false, 'S_POLL_ACTION' => $viewtopic_url, - 'U_VIEW_RESULTS' => $viewtopic_url . '&view=viewpoll') + 'U_VIEW_RESULTS' => $viewtopic_url . '&view=viewpoll', + ); + + /** + * Event to add/modify poll template data + * + * @event core.viewtopic_modify_poll_template_data + * @var array cur_voted_id Array with options' IDs current user has voted for + * @var int poll_end The poll end time + * @var array poll_info Array with the poll information + * @var array poll_options_template_data Array with the poll options template data + * @var array poll_template_data Array with the common poll template data + * @var int poll_total Total poll votes count + * @var int poll_most Mostly voted option votes count + * @var array topic_data All the information from the topic and forum tables for this topic + * @var string viewtopic_url URL to the topic page + * @var array vote_counts Array with the vote counts for every poll option + * @var array voted_id Array with updated options' IDs current user is voting for + * @since 3.1.5-RC1 + */ + $vars = array( + 'cur_voted_id', + 'poll_end', + 'poll_info', + 'poll_options_template_data', + 'poll_template_data', + 'poll_total', + 'poll_most', + 'topic_data', + 'viewtopic_url', + 'vote_counts', + 'voted_id', ); + extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_poll_template_data', compact($vars))); + + $template->assign_block_vars_array('poll_option', $poll_options_template_data); - unset($poll_end, $poll_info, $voted_id); + $template->assign_vars($poll_template_data); + + unset($poll_end, $poll_info, $poll_options_template_data, $poll_template_data, $voted_id); } // If the user is trying to reach the second half of the topic, fetch it starting from the end @@ -927,14 +1057,11 @@ if ($start > $total_posts / 2) { $store_reverse = true; - if ($start + $config['posts_per_page'] > $total_posts) - { - $sql_limit = min($config['posts_per_page'], max(1, $total_posts - $start)); - } - // Select the sort order $direction = (($sort_dir == 'd') ? 'ASC' : 'DESC'); - $sql_start = max(0, $total_posts - $sql_limit - $start); + + $sql_limit = $pagination->reverse_limit($start, $sql_limit, $total_posts); + $sql_start = $pagination->reverse_start($start, $sql_limit, $total_posts); } else { @@ -953,16 +1080,15 @@ else } // Container for user details, only process once -$post_list = $user_cache = $id_cache = $attachments = $attach_list = $rowset = $update_count = $post_edit_list = array(); -$has_attachments = $display_notice = false; -$bbcode_bitfield = ''; +$post_list = $user_cache = $id_cache = $attachments = $attach_list = $rowset = $update_count = $post_edit_list = $post_delete_list = array(); +$has_unapproved_attachments = $has_approved_attachments = $display_notice = false; $i = $i_total = 0; // Go ahead and pull all data for this topic $sql = 'SELECT p.post_id FROM ' . POSTS_TABLE . ' p' . (($join_user_sql[$sort_key]) ? ', ' . USERS_TABLE . ' u': '') . " WHERE p.topic_id = $topic_id - " . ((!$auth->acl_get('m_approve', $forum_id)) ? 'AND p.post_approved = 1' : '') . " + AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id, 'p.') . " " . (($join_user_sql[$sort_key]) ? 'AND u.user_id = p.poster_id': '') . " $limit_posts_time ORDER BY $sql_sort_order"; @@ -992,7 +1118,7 @@ if (!sizeof($post_list)) // We need to grab it because we do reverse ordering sometimes $max_post_time = 0; -$sql = $db->sql_build_query('SELECT', array( +$sql_ary = array( 'SELECT' => 'u.*, z.friend, z.foe, p.*', 'FROM' => array( @@ -1003,17 +1129,48 @@ $sql = $db->sql_build_query('SELECT', array( 'LEFT_JOIN' => array( array( 'FROM' => array(ZEBRA_TABLE => 'z'), - 'ON' => 'z.user_id = ' . $user->data['user_id'] . ' AND z.zebra_id = p.poster_id' - ) + 'ON' => 'z.user_id = ' . $user->data['user_id'] . ' AND z.zebra_id = p.poster_id', + ), ), 'WHERE' => $db->sql_in_set('p.post_id', $post_list) . ' - AND u.user_id = p.poster_id' -)); + AND u.user_id = p.poster_id', +); +/** +* Event to modify the SQL query before the post and poster data is retrieved +* +* @event core.viewtopic_get_post_data +* @var int forum_id Forum ID +* @var int topic_id Topic ID +* @var array topic_data Array with topic data +* @var array post_list Array with post_ids we are going to retrieve +* @var int sort_days Display posts of previous x days +* @var string sort_key Key the posts are sorted by +* @var string sort_dir Direction the posts are sorted by +* @var int start Pagination information +* @var array sql_ary The SQL array to get the data of posts and posters +* @since 3.1.0-a1 +* @change 3.1.0-a2 Added vars forum_id, topic_id, topic_data, post_list, sort_days, sort_key, sort_dir, start +*/ +$vars = array( + 'forum_id', + 'topic_id', + 'topic_data', + 'post_list', + 'sort_days', + 'sort_key', + 'sort_dir', + 'start', + 'sql_ary', +); +extract($phpbb_dispatcher->trigger_event('core.viewtopic_get_post_data', compact($vars))); + +$sql = $db->sql_build_query('SELECT', $sql_ary); $result = $db->sql_query($sql); -$now = phpbb_gmgetdate(time() + $user->timezone + $user->dst); +$now = $user->create_datetime(); +$now = phpbb_gmgetdate($now->getTimestamp() + $now->getOffset()); // Posts are stored in the $rowset array while $attach_list, $user_cache // and the global bbcode_bitfield are built @@ -1032,14 +1189,18 @@ while ($row = $db->sql_fetchrow($result)) { $attach_list[] = (int) $row['post_id']; - if ($row['post_approved']) + if ($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE) + { + $has_unapproved_attachments = true; + } + else if ($row['post_visibility'] == ITEM_APPROVED) { - $has_attachments = true; + $has_approved_attachments = true; } } - $rowset[$row['post_id']] = array( - 'hide_post' => ($row['foe'] && ($view != 'show' || $post_id != $row['post_id'])) ? true : false, + $rowset_data = array( + 'hide_post' => (($row['foe'] || $row['post_visibility'] == ITEM_DELETED) && ($view != 'show' || $post_id != $row['post_id'])) ? true : false, 'post_id' => $row['post_id'], 'post_time' => $row['post_time'], @@ -1054,11 +1215,14 @@ while ($row = $db->sql_fetchrow($result)) 'post_edit_reason' => $row['post_edit_reason'], 'post_edit_user' => $row['post_edit_user'], 'post_edit_locked' => $row['post_edit_locked'], + 'post_delete_time' => $row['post_delete_time'], + 'post_delete_reason'=> $row['post_delete_reason'], + 'post_delete_user' => $row['post_delete_user'], // Make sure the icon actually exists 'icon_id' => (isset($icons[$row['icon_id']]['img'], $icons[$row['icon_id']]['height'], $icons[$row['icon_id']]['width'])) ? $row['icon_id'] : 0, 'post_attachment' => $row['post_attachment'], - 'post_approved' => $row['post_approved'], + 'post_visibility' => $row['post_visibility'], 'post_reported' => $row['post_reported'], 'post_username' => $row['post_username'], 'post_text' => $row['post_text'], @@ -1070,14 +1234,18 @@ while ($row = $db->sql_fetchrow($result)) 'foe' => $row['foe'], ); - // Define the global bbcode bitfield, will be used to load bbcodes - $bbcode_bitfield = $bbcode_bitfield | base64_decode($row['bbcode_bitfield']); + /** + * Modify the post rowset containing data to be displayed with posts + * + * @event core.viewtopic_post_rowset_data + * @var array rowset_data Array with the rowset data for this post + * @var array row Array with original user and post data + * @since 3.1.0-a1 + */ + $vars = array('rowset_data', 'row'); + extract($phpbb_dispatcher->trigger_event('core.viewtopic_post_rowset_data', compact($vars))); - // Is a signature attached? Are we going to display it? - if ($row['enable_sig'] && $config['allow_sig'] && $user->optionget('viewsigs')) - { - $bbcode_bitfield = $bbcode_bitfield | base64_decode($row['user_sig_bbcode_bitfield']); - } + $rowset[$row['post_id']] = $rowset_data; // Cache various user specific data ... so we don't have to recompute // this each time the same user appears on this page @@ -1085,48 +1253,59 @@ while ($row = $db->sql_fetchrow($result)) { if ($poster_id == ANONYMOUS) { - $user_cache[$poster_id] = array( + $user_cache_data = array( + 'user_type' => USER_IGNORE, 'joined' => '', 'posts' => '', - 'from' => '', 'sig' => '', 'sig_bbcode_uid' => '', 'sig_bbcode_bitfield' => '', 'online' => false, - 'avatar' => ($user->optionget('viewavatars')) ? get_user_avatar($row['user_avatar'], $row['user_avatar_type'], $row['user_avatar_width'], $row['user_avatar_height']) : '', + 'avatar' => ($user->optionget('viewavatars')) ? phpbb_get_user_avatar($row) : '', 'rank_title' => '', 'rank_image' => '', 'rank_image_src' => '', 'sig' => '', - 'profile' => '', 'pm' => '', 'email' => '', - 'www' => '', - 'icq_status_img' => '', - 'icq' => '', - 'aim' => '', - 'msn' => '', - 'yim' => '', 'jabber' => '', 'search' => '', 'age' => '', 'username' => $row['username'], 'user_colour' => $row['user_colour'], + 'contact_user' => '', 'warnings' => 0, 'allow_pm' => 0, ); - get_user_rank($row['user_rank'], false, $user_cache[$poster_id]['rank_title'], $user_cache[$poster_id]['rank_image'], $user_cache[$poster_id]['rank_image_src']); + /** + * Modify the guest user's data displayed with the posts + * + * @event core.viewtopic_cache_guest_data + * @var array user_cache_data Array with the user's data + * @var int poster_id Poster's user id + * @var array row Array with original user and post data + * @since 3.1.0-a1 + */ + $vars = array('user_cache_data', 'poster_id', 'row'); + extract($phpbb_dispatcher->trigger_event('core.viewtopic_cache_guest_data', compact($vars))); + + $user_cache[$poster_id] = $user_cache_data; + + $user_rank_data = phpbb_get_user_rank($row, false); + $user_cache[$poster_id]['rank_title'] = $user_rank_data['title']; + $user_cache[$poster_id]['rank_image'] = $user_rank_data['img']; + $user_cache[$poster_id]['rank_image_src'] = $user_rank_data['img_src']; } else { $user_sig = ''; - // We add the signature to every posters entry because enable_sig is post dependant + // We add the signature to every posters entry because enable_sig is post dependent if ($row['user_sig'] && $config['allow_sig'] && $user->optionget('viewsigs')) { $user_sig = $row['user_sig']; @@ -1134,11 +1313,13 @@ while ($row = $db->sql_fetchrow($result)) $id_cache[] = $poster_id; - $user_cache[$poster_id] = array( + $user_cache_data = array( + 'user_type' => $row['user_type'], + 'user_inactive_reason' => $row['user_inactive_reason'], + 'joined' => $user->format_date($row['user_regdate']), 'posts' => $row['user_posts'], 'warnings' => (isset($row['user_warnings'])) ? $row['user_warnings'] : 0, - 'from' => (!empty($row['user_from'])) ? $row['user_from'] : '', 'sig' => $user_sig, 'sig_bbcode_uid' => (!empty($row['user_sig_bbcode_uid'])) ? $row['user_sig_bbcode_uid'] : '', @@ -1147,7 +1328,7 @@ while ($row = $db->sql_fetchrow($result)) 'viewonline' => $row['user_allow_viewonline'], 'allow_pm' => $row['user_allow_pm'], - 'avatar' => ($user->optionget('viewavatars')) ? get_user_avatar($row['user_avatar'], $row['user_avatar_type'], $row['user_avatar_width'], $row['user_avatar_height']) : '', + 'avatar' => ($user->optionget('viewavatars')) ? phpbb_get_user_avatar($row) : '', 'age' => '', 'rank_title' => '', @@ -1156,15 +1337,11 @@ while ($row = $db->sql_fetchrow($result)) 'username' => $row['username'], 'user_colour' => $row['user_colour'], + 'contact_user' => $user->lang('CONTACT_USER', get_username_string('username', $poster_id, $row['username'], $row['user_colour'], $row['username'])), 'online' => false, - 'profile' => append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=viewprofile&u=$poster_id"), - 'www' => $row['user_website'], - 'aim' => ($row['user_aim'] && $auth->acl_get('u_sendim')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=contact&action=aim&u=$poster_id") : '', - 'msn' => ($row['user_msnm'] && $auth->acl_get('u_sendim')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=contact&action=msnm&u=$poster_id") : '', - 'yim' => ($row['user_yim']) ? 'http://edit.yahoo.com/config/send_webmesg?.target=' . urlencode($row['user_yim']) . '&.src=pg' : '', - 'jabber' => ($row['user_jabber'] && $auth->acl_get('u_sendim')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=contact&action=jabber&u=$poster_id") : '', - 'search' => ($auth->acl_get('u_search')) ? append_sid("{$phpbb_root_path}search.$phpEx", "author_id=$poster_id&sr=posts") : '', + 'jabber' => ($config['jab_enable'] && $row['user_jabber'] && $auth->acl_get('u_sendim')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=contact&action=jabber&u=$poster_id") : '', + 'search' => ($config['load_search'] && $auth->acl_get('u_search')) ? append_sid("{$phpbb_root_path}search.$phpEx", "author_id=$poster_id&sr=posts") : '', 'author_full' => get_username_string('full', $poster_id, $row['username'], $row['user_colour']), 'author_colour' => get_username_string('colour', $poster_id, $row['username'], $row['user_colour']), @@ -1172,7 +1349,24 @@ while ($row = $db->sql_fetchrow($result)) 'author_profile' => get_username_string('profile', $poster_id, $row['username'], $row['user_colour']), ); - get_user_rank($row['user_rank'], $row['user_posts'], $user_cache[$poster_id]['rank_title'], $user_cache[$poster_id]['rank_image'], $user_cache[$poster_id]['rank_image_src']); + /** + * Modify the users' data displayed with their posts + * + * @event core.viewtopic_cache_user_data + * @var array user_cache_data Array with the user's data + * @var int poster_id Poster's user id + * @var array row Array with original user and post data + * @since 3.1.0-a1 + */ + $vars = array('user_cache_data', 'poster_id', 'row'); + extract($phpbb_dispatcher->trigger_event('core.viewtopic_cache_user_data', compact($vars))); + + $user_cache[$poster_id] = $user_cache_data; + + $user_rank_data = phpbb_get_user_rank($row, $row['user_posts']); + $user_cache[$poster_id]['rank_title'] = $user_rank_data['title']; + $user_cache[$poster_id]['rank_image'] = $user_rank_data['img']; + $user_cache[$poster_id]['rank_image_src'] = $user_rank_data['img_src']; if ((!empty($row['user_allow_viewemail']) && $auth->acl_get('u_sendemail')) || $auth->acl_get('a_email')) { @@ -1183,17 +1377,6 @@ while ($row = $db->sql_fetchrow($result)) $user_cache[$poster_id]['email'] = ''; } - if (!empty($row['user_icq'])) - { - $user_cache[$poster_id]['icq'] = 'http://www.icq.com/people/' . urlencode($row['user_icq']) . '/'; - $user_cache[$poster_id]['icq_status_img'] = '<img src="http://web.icq.com/whitepages/online?icq=' . $row['user_icq'] . '&img=5" width="18" height="18" alt="" />'; - } - else - { - $user_cache[$poster_id]['icq_status_img'] = ''; - $user_cache[$poster_id]['icq'] = ''; - } - if ($config['allow_birthdays'] && !empty($row['user_birthday'])) { list($bday_day, $bday_month, $bday_year) = array_map('intval', explode('-', $row['user_birthday'])); @@ -1221,14 +1404,10 @@ $db->sql_freeresult($result); // Load custom profile fields if ($config['load_cpf_viewtopic']) { - if (!class_exists('custom_profile')) - { - include($phpbb_root_path . 'includes/functions_profile_fields.' . $phpEx); - } - $cp = new custom_profile(); + $cp = $phpbb_container->get('profilefields.manager'); // Grab all profile fields from users in id cache for later use - similar to the poster cache - $profile_fields_tmp = $cp->generate_profile_fields_template('grab', $id_cache); + $profile_fields_tmp = $cp->grab_profile_fields_data($id_cache); // filter out fields not to be displayed on viewtopic. Yes, it's a hack, but this shouldn't break any MODs. $profile_fields_cache = array(); @@ -1297,8 +1476,8 @@ if (sizeof($attach_list)) $sql = 'SELECT a.post_msg_id as post_id FROM ' . ATTACHMENTS_TABLE . ' a, ' . POSTS_TABLE . " p WHERE p.topic_id = $topic_id - AND p.post_approved = 1 - AND p.topic_id = a.topic_id"; + AND p.post_visibility = " . ITEM_APPROVED . ' + AND p.topic_id = a.topic_id'; $result = $db->sql_query_limit($sql, 1); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); @@ -1319,7 +1498,7 @@ if (sizeof($attach_list)) $db->sql_query($sql); } } - else if ($has_attachments && !$topic_data['topic_attachment']) + else if ($has_approved_attachments && !$topic_data['topic_attachment']) { // Topic has approved attachments but its flag is wrong $sql = 'UPDATE ' . TOPICS_TABLE . " @@ -1329,6 +1508,11 @@ if (sizeof($attach_list)) $topic_data['topic_attachment'] = 1; } + else if ($has_unapproved_attachments && !$topic_data['topic_attachment']) + { + // Topic has only unapproved attachments but we have the right to see and download them + $topic_data['topic_attachment'] = 1; + } } else { @@ -1336,19 +1520,61 @@ if (sizeof($attach_list)) } } -// Instantiate BBCode if need be -if ($bbcode_bitfield !== '') -{ - $bbcode = new bbcode(base64_encode($bbcode_bitfield)); -} +// Get the list of users who can receive private messages +$can_receive_pm_list = $auth->acl_get_list(array_keys($user_cache), 'u_readpm'); +$can_receive_pm_list = (empty($can_receive_pm_list) || !isset($can_receive_pm_list[0]['u_readpm'])) ? array() : $can_receive_pm_list[0]['u_readpm']; + +// Get the list of permanently banned users +$permanently_banned_users = phpbb_get_banned_user_ids(array_keys($user_cache), false); $i_total = sizeof($rowset) - 1; $prev_post_id = ''; $template->assign_vars(array( + 'S_HAS_ATTACHMENTS' => $topic_data['topic_attachment'], 'S_NUM_POSTS' => sizeof($post_list)) ); +/** +* Event to modify the post, poster and attachment data before assigning the posts +* +* @event core.viewtopic_modify_post_data +* @var int forum_id Forum ID +* @var int topic_id Topic ID +* @var array topic_data Array with topic data +* @var array post_list Array with post_ids we are going to display +* @var array rowset Array with post_id => post data +* @var array user_cache Array with prepared user data +* @var int start Pagination information +* @var int sort_days Display posts of previous x days +* @var string sort_key Key the posts are sorted by +* @var string sort_dir Direction the posts are sorted by +* @var bool display_notice Shall we display a notice instead of attachments +* @var bool has_approved_attachments Does the topic have approved attachments +* @var array attachments List of attachments post_id => array of attachments +* @var array permanently_banned_users List of permanently banned users +* @var array can_receive_pm_list Array with posters that can receive pms +* @since 3.1.0-RC3 +*/ +$vars = array( + 'forum_id', + 'topic_id', + 'topic_data', + 'post_list', + 'rowset', + 'user_cache', + 'sort_days', + 'sort_key', + 'sort_dir', + 'start', + 'permanently_banned_users', + 'can_receive_pm_list', + 'display_notice', + 'has_approved_attachments', + 'attachments', +); +extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_post_data', compact($vars))); + // Output the posts $first_unread = $post_unread = false; for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i) @@ -1360,35 +1586,19 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i) continue; } - $row =& $rowset[$post_list[$i]]; + $row = $rowset[$post_list[$i]]; $poster_id = $row['user_id']; // End signature parsing, only if needed if ($user_cache[$poster_id]['sig'] && $row['enable_sig'] && empty($user_cache[$poster_id]['sig_parsed'])) { - $user_cache[$poster_id]['sig'] = censor_text($user_cache[$poster_id]['sig']); - - if ($user_cache[$poster_id]['sig_bbcode_bitfield']) - { - $bbcode->bbcode_second_pass($user_cache[$poster_id]['sig'], $user_cache[$poster_id]['sig_bbcode_uid'], $user_cache[$poster_id]['sig_bbcode_bitfield']); - } - - $user_cache[$poster_id]['sig'] = bbcode_nl2br($user_cache[$poster_id]['sig']); - $user_cache[$poster_id]['sig'] = smiley_text($user_cache[$poster_id]['sig']); - $user_cache[$poster_id]['sig_parsed'] = true; + $parse_flags = ($user_cache[$poster_id]['sig_bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES; + $user_cache[$poster_id]['sig'] = generate_text_for_display($user_cache[$poster_id]['sig'], $user_cache[$poster_id]['sig_bbcode_uid'], $user_cache[$poster_id]['sig_bbcode_bitfield'], $parse_flags, true); } // Parse the message and subject - $message = censor_text($row['post_text']); - - // Second parse bbcode here - if ($row['bbcode_bitfield']) - { - $bbcode->bbcode_second_pass($message, $row['bbcode_uid'], $row['bbcode_bitfield']); - } - - $message = bbcode_nl2br($message); - $message = smiley_text($message); + $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES; + $message = generate_text_for_display($row['post_text'], $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, true); if (!empty($attachments[$row['post_id']])) { @@ -1430,8 +1640,6 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i) unset($post_storage_list); } - $l_edit_time_total = ($row['post_edit_count'] == 1) ? $user->lang['EDITED_TIME_TOTAL'] : $user->lang['EDITED_TIMES_TOTAL']; - if ($row['post_edit_reason']) { // User having edited the post also being the post author? @@ -1444,7 +1652,7 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i) $display_username = get_username_string('full', $row['post_edit_user'], $post_edit_list[$row['post_edit_user']]['username'], $post_edit_list[$row['post_edit_user']]['user_colour']); } - $l_edited_by = sprintf($l_edit_time_total, $display_username, $user->format_date($row['post_edit_time'], false, true), $row['post_edit_count']); + $l_edited_by = $user->lang('EDITED_TIMES_TOTAL', (int) $row['post_edit_count'], $display_username, $user->format_date($row['post_edit_time'], false, true)); } else { @@ -1463,7 +1671,7 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i) $display_username = get_username_string('full', $row['post_edit_user'], $user_cache[$row['post_edit_user']]['username'], $user_cache[$row['post_edit_user']]['user_colour']); } - $l_edited_by = sprintf($l_edit_time_total, $display_username, $user->format_date($row['post_edit_time'], false, true), $row['post_edit_count']); + $l_edited_by = $user->lang('EDITED_TIMES_TOTAL', (int) $row['post_edit_count'], $display_username, $user->format_date($row['post_edit_time'], false, true)); } } else @@ -1471,6 +1679,62 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i) $l_edited_by = ''; } + // Deleting information + if ($row['post_visibility'] == ITEM_DELETED && $row['post_delete_user']) + { + // Get usernames for all following posts if not already stored + if (!sizeof($post_delete_list) && ($row['post_delete_reason'] || ($row['post_delete_user'] && !isset($user_cache[$row['post_delete_user']])))) + { + // Remove all post_ids already parsed (we do not have to check them) + $post_storage_list = (!$store_reverse) ? array_slice($post_list, $i) : array_slice(array_reverse($post_list), $i); + + $sql = 'SELECT DISTINCT u.user_id, u.username, u.user_colour + FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u + WHERE ' . $db->sql_in_set('p.post_id', $post_storage_list) . ' + AND p.post_delete_user <> 0 + AND p.post_delete_user = u.user_id'; + $result2 = $db->sql_query($sql); + while ($user_delete_row = $db->sql_fetchrow($result2)) + { + $post_delete_list[$user_delete_row['user_id']] = $user_delete_row; + } + $db->sql_freeresult($result2); + + unset($post_storage_list); + } + + if ($row['post_delete_user'] && !isset($user_cache[$row['post_delete_user']])) + { + $user_cache[$row['post_delete_user']] = $post_delete_list[$row['post_delete_user']]; + } + + $display_postername = get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']); + + // User having deleted the post also being the post author? + if (!$row['post_delete_user'] || $row['post_delete_user'] == $poster_id) + { + $display_username = $display_postername; + } + else + { + $display_username = get_username_string('full', $row['post_delete_user'], $user_cache[$row['post_delete_user']]['username'], $user_cache[$row['post_delete_user']]['user_colour']); + } + + if ($row['post_delete_reason']) + { + $l_deleted_message = $user->lang('POST_DELETED_BY_REASON', $display_postername, $display_username, $user->format_date($row['post_delete_time'], false, true), $row['post_delete_reason']); + } + else + { + $l_deleted_message = $user->lang('POST_DELETED_BY', $display_postername, $display_username, $user->format_date($row['post_delete_time'], false, true)); + } + $l_deleted_by = $user->lang('DELETED_INFORMATION', $display_username, $user->format_date($row['post_delete_time'], false, true)); + } + else + { + $l_deleted_by = $l_deleted_message = ''; + } + // Bump information if ($topic_data['topic_bumped'] && $row['post_id'] == $topic_data['topic_last_post_id'] && isset($user_cache[$topic_data['topic_bumper']]) ) { @@ -1489,7 +1753,7 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i) // if ($config['load_cpf_viewtopic']) { - $cp_row = (isset($profile_fields_cache[$poster_id])) ? $cp->generate_profile_fields_template('show', false, $profile_fields_cache[$poster_id]) : array(); + $cp_row = (isset($profile_fields_cache[$poster_id])) ? $cp->generate_profile_fields_template_data($profile_fields_cache[$poster_id]) : array(); } $post_unread = (isset($topic_tracking_info[$topic_id]) && $row['post_time'] > $topic_tracking_info[$topic_id]) ? true : false; @@ -1500,30 +1764,95 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i) $s_first_unread = $first_unread = true; } - $edit_allowed = ($user->data['is_registered'] && ($auth->acl_get('m_edit', $forum_id) || ( - $user->data['user_id'] == $poster_id && - $auth->acl_get('f_edit', $forum_id) && - $topic_data['topic_status'] != ITEM_LOCKED && - !$row['post_edit_locked'] && - ($row['post_time'] > time() - ($config['edit_time'] * 60) || !$config['edit_time']) + $force_edit_allowed = $force_delete_allowed = false; + + $s_cannot_edit = !$auth->acl_get('f_edit', $forum_id) || $user->data['user_id'] != $poster_id; + $s_cannot_edit_time = $config['edit_time'] && $row['post_time'] <= time() - ($config['edit_time'] * 60); + $s_cannot_edit_locked = $topic_data['topic_status'] == ITEM_LOCKED || $row['post_edit_locked']; + + $s_cannot_delete = $user->data['user_id'] != $poster_id || ( + !$auth->acl_get('f_delete', $forum_id) && + (!$auth->acl_get('f_softdelete', $forum_id) || $row['post_visibility'] == ITEM_DELETED) + ); + $s_cannot_delete_lastpost = $topic_data['topic_last_post_id'] != $row['post_id']; + $s_cannot_delete_time = $config['delete_time'] && $row['post_time'] <= time() - ($config['delete_time'] * 60); + // we do not want to allow removal of the last post if a moderator locked it! + $s_cannot_delete_locked = $topic_data['topic_status'] == ITEM_LOCKED || $row['post_edit_locked']; + + /** + * This event allows you to modify the conditions for the "can edit post" and "can delete post" checks + * + * @event core.viewtopic_modify_post_action_conditions + * @var array row Array with post data + * @var array topic_data Array with topic data + * @var bool force_edit_allowed Allow the user to edit the post (all permissions and conditions are ignored) + * @var bool s_cannot_edit User can not edit the post because it's not his + * @var bool s_cannot_edit_locked User can not edit the post because it's locked + * @var bool s_cannot_edit_time User can not edit the post because edit_time has passed + * @var bool force_delete_allowed Allow the user to delete the post (all permissions and conditions are ignored) + * @var bool s_cannot_delete User can not delete the post because it's not his + * @var bool s_cannot_delete_lastpost User can not delete the post because it's not the last post of the topic + * @var bool s_cannot_delete_locked User can not delete the post because it's locked + * @var bool s_cannot_delete_time User can not delete the post because edit_time has passed + * @since 3.1.0-b4 + */ + $vars = array( + 'row', + 'topic_data', + 'force_edit_allowed', + 's_cannot_edit', + 's_cannot_edit_locked', + 's_cannot_edit_time', + 'force_delete_allowed', + 's_cannot_delete', + 's_cannot_delete_lastpost', + 's_cannot_delete_locked', + 's_cannot_delete_time', + ); + extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_post_action_conditions', compact($vars))); + + $edit_allowed = $force_edit_allowed || ($user->data['is_registered'] && ($auth->acl_get('m_edit', $forum_id) || ( + !$s_cannot_edit && + !$s_cannot_edit_time && + !$s_cannot_edit_locked ))); $quote_allowed = $auth->acl_get('m_edit', $forum_id) || ($topic_data['topic_status'] != ITEM_LOCKED && ($user->data['user_id'] == ANONYMOUS || $auth->acl_get('f_reply', $forum_id)) ); - $delete_allowed = ($user->data['is_registered'] && ($auth->acl_get('m_delete', $forum_id) || ( - $user->data['user_id'] == $poster_id && - $auth->acl_get('f_delete', $forum_id) && - $topic_data['topic_status'] != ITEM_LOCKED && - $topic_data['topic_last_post_id'] == $row['post_id'] && - ($row['post_time'] > time() - ($config['delete_time'] * 60) || !$config['delete_time']) && - // we do not want to allow removal of the last post if a moderator locked it! - !$row['post_edit_locked'] - ))); + $delete_allowed = $force_delete_allowed || ($user->data['is_registered'] && ( + ($auth->acl_get('m_delete', $forum_id) || ($auth->acl_get('m_softdelete', $forum_id) && $row['post_visibility'] != ITEM_DELETED)) || + (!$s_cannot_delete && !$s_cannot_delete_lastpost && !$s_cannot_delete_time && !$s_cannot_delete_locked) + )); + + // Can this user receive a Private Message? + $can_receive_pm = ( + // They must be a "normal" user + $user_cache[$poster_id]['user_type'] != USER_IGNORE && + + // They must not be deactivated by the administrator + ($user_cache[$poster_id]['user_type'] != USER_INACTIVE || $user_cache[$poster_id]['user_inactive_reason'] != INACTIVE_MANUAL) && + + // They must be able to read PMs + in_array($poster_id, $can_receive_pm_list) && + + // They must not be permanently banned + !in_array($poster_id, $permanently_banned_users) && + + // They must allow users to contact via PM + (($auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_')) || $user_cache[$poster_id]['allow_pm']) + ); + + $u_pm = ''; + + if ($config['allow_privmsg'] && $auth->acl_get('u_sendpm') && $can_receive_pm) + { + $u_pm = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=compose&action=quotepost&p=' . $row['post_id']); + } // - $postrow = array( + $post_row = array( 'POST_AUTHOR_FULL' => ($poster_id != ANONYMOUS) ? $user_cache[$poster_id]['author_full'] : get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), 'POST_AUTHOR_COLOUR' => ($poster_id != ANONYMOUS) ? $user_cache[$poster_id]['author_colour'] : get_username_string('colour', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), 'POST_AUTHOR' => ($poster_id != ANONYMOUS) ? $user_cache[$poster_id]['author_username'] : get_username_string('username', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), @@ -1534,10 +1863,10 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i) 'RANK_IMG_SRC' => $user_cache[$poster_id]['rank_image_src'], 'POSTER_JOINED' => $user_cache[$poster_id]['joined'], 'POSTER_POSTS' => $user_cache[$poster_id]['posts'], - 'POSTER_FROM' => $user_cache[$poster_id]['from'], 'POSTER_AVATAR' => $user_cache[$poster_id]['avatar'], - 'POSTER_WARNINGS' => $user_cache[$poster_id]['warnings'], + 'POSTER_WARNINGS' => $auth->acl_get('m_warn') ? $user_cache[$poster_id]['warnings'] : '', 'POSTER_AGE' => $user_cache[$poster_id]['age'], + 'CONTACT_USER' => $user_cache[$poster_id]['contact_user'], 'POST_DATE' => $user->format_date($row['post_time'], false, ($view == 'print') ? true : false), 'POST_SUBJECT' => $row['post_subject'], @@ -1545,13 +1874,14 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i) 'SIGNATURE' => ($row['enable_sig']) ? $user_cache[$poster_id]['sig'] : '', 'EDITED_MESSAGE' => $l_edited_by, 'EDIT_REASON' => $row['post_edit_reason'], + 'DELETED_MESSAGE' => $l_deleted_by, + 'DELETE_REASON' => $row['post_delete_reason'], 'BUMPED_MESSAGE' => $l_bumped_by, 'MINI_POST_IMG' => ($post_unread) ? $user->img('icon_post_target_unread', 'UNREAD_POST') : $user->img('icon_post_target', 'POST'), 'POST_ICON_IMG' => ($topic_data['enable_icons'] && !empty($row['icon_id'])) ? $icons[$row['icon_id']]['img'] : '', 'POST_ICON_IMG_WIDTH' => ($topic_data['enable_icons'] && !empty($row['icon_id'])) ? $icons[$row['icon_id']]['width'] : '', 'POST_ICON_IMG_HEIGHT' => ($topic_data['enable_icons'] && !empty($row['icon_id'])) ? $icons[$row['icon_id']]['height'] : '', - 'ICQ_STATUS_IMG' => $user_cache[$poster_id]['icq_status_img'], 'ONLINE_IMG' => ($poster_id == ANONYMOUS || !$config['load_onlinetrack']) ? '' : (($user_cache[$poster_id]['online']) ? $user->img('icon_user_online', 'ONLINE') : $user->img('icon_user_offline', 'OFFLINE')), 'S_ONLINE' => ($poster_id == ANONYMOUS || !$config['load_onlinetrack']) ? false : (($user_cache[$poster_id]['online']) ? true : false), @@ -1560,21 +1890,17 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i) 'U_INFO' => ($auth->acl_get('m_info', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", "i=main&mode=post_details&f=$forum_id&p=" . $row['post_id'], true, $user->session_id) : '', 'U_DELETE' => ($delete_allowed) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=delete&f=$forum_id&p={$row['post_id']}") : '', - 'U_PROFILE' => $user_cache[$poster_id]['profile'], 'U_SEARCH' => $user_cache[$poster_id]['search'], - 'U_PM' => ($poster_id != ANONYMOUS && $config['allow_privmsg'] && $auth->acl_get('u_sendpm') && ($user_cache[$poster_id]['allow_pm'] || $auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_'))) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=compose&action=quotepost&p=' . $row['post_id']) : '', + 'U_PM' => $u_pm, 'U_EMAIL' => $user_cache[$poster_id]['email'], - 'U_WWW' => $user_cache[$poster_id]['www'], - 'U_ICQ' => $user_cache[$poster_id]['icq'], - 'U_AIM' => $user_cache[$poster_id]['aim'], - 'U_MSN' => $user_cache[$poster_id]['msn'], - 'U_YIM' => $user_cache[$poster_id]['yim'], 'U_JABBER' => $user_cache[$poster_id]['jabber'], + 'U_APPROVE_ACTION' => append_sid("{$phpbb_root_path}mcp.$phpEx", "i=queue&p={$row['post_id']}&f=$forum_id&redirect=" . urlencode(str_replace('&', '&', $viewtopic_url . '&p=' . $row['post_id'] . '#p' . $row['post_id']))), 'U_REPORT' => ($auth->acl_get('f_report', $forum_id)) ? append_sid("{$phpbb_root_path}report.$phpEx", 'f=' . $forum_id . '&p=' . $row['post_id']) : '', 'U_MCP_REPORT' => ($auth->acl_get('m_report', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=reports&mode=report_details&f=' . $forum_id . '&p=' . $row['post_id'], true, $user->session_id) : '', 'U_MCP_APPROVE' => ($auth->acl_get('m_approve', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=approve_details&f=' . $forum_id . '&p=' . $row['post_id'], true, $user->session_id) : '', - 'U_MINI_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'p=' . $row['post_id']) . (($topic_data['topic_type'] == POST_GLOBAL) ? '&f=' . $forum_id : '') . '#p' . $row['post_id'], + 'U_MCP_RESTORE' => ($auth->acl_get('m_approve', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=' . (($topic_data['topic_visibility'] != ITEM_DELETED) ? 'deleted_posts' : 'deleted_topics') . '&f=' . $forum_id . '&p=' . $row['post_id'], true, $user->session_id) : '', + 'U_MINI_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'p=' . $row['post_id']) . '#p' . $row['post_id'], 'U_NEXT_POST_ID' => ($i < $i_total && isset($rowset[$post_list[$i + 1]])) ? $rowset[$post_list[$i + 1]]['post_id'] : '', 'U_PREV_POST_ID' => $prev_post_id, 'U_NOTES' => ($auth->acl_getf_global('m_')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=notes&mode=user_notes&u=' . $poster_id, true, $user->session_id) : '', @@ -1585,7 +1911,10 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i) 'POSTER_ID' => $poster_id, 'S_HAS_ATTACHMENTS' => (!empty($attachments[$row['post_id']])) ? true : false, - 'S_POST_UNAPPROVED' => ($row['post_approved']) ? false : true, + 'S_MULTIPLE_ATTACHMENTS' => !empty($attachments[$row['post_id']]) && sizeof($attachments[$row['post_id']]) > 1, + 'S_POST_UNAPPROVED' => ($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE) ? true : false, + 'S_POST_DELETED' => ($row['post_visibility'] == ITEM_DELETED) ? true : false, + 'L_POST_DELETED_MESSAGE' => $l_deleted_message, 'S_POST_REPORTED' => ($row['post_reported'] && $auth->acl_get('m_report', $forum_id)) ? true : false, 'S_DISPLAY_NOTICE' => $display_notice && $row['post_attachment'], 'S_FRIEND' => ($row['friend']) ? true : false, @@ -1594,23 +1923,101 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i) 'S_CUSTOM_FIELDS' => (isset($cp_row['row']) && sizeof($cp_row['row'])) ? true : false, 'S_TOPIC_POSTER' => ($topic_data['topic_poster'] == $poster_id) ? true : false, - 'S_IGNORE_POST' => ($row['hide_post']) ? true : false, - 'L_IGNORE_POST' => ($row['hide_post']) ? sprintf($user->lang['POST_BY_FOE'], get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), '<a href="' . $viewtopic_url . "&p={$row['post_id']}&view=show#p{$row['post_id']}" . '">', '</a>') : '', + 'S_IGNORE_POST' => ($row['foe']) ? true : false, + 'L_IGNORE_POST' => ($row['foe']) ? sprintf($user->lang['POST_BY_FOE'], get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username'])) : '', + 'S_POST_HIDDEN' => $row['hide_post'], + 'L_POST_DISPLAY' => ($row['hide_post']) ? $user->lang('POST_DISPLAY', '<a class="display_post" data-post-id="' . $row['post_id'] . '" href="' . $viewtopic_url . "&p={$row['post_id']}&view=show#p{$row['post_id']}" . '">', '</a>') : '', ); + $user_poster_data = $user_cache[$poster_id]; + + $current_row_number = $i; + + /** + * Modify the posts template block + * + * @event core.viewtopic_modify_post_row + * @var int start Start item of this page + * @var int current_row_number Number of the post on this page + * @var int end Number of posts on this page + * @var int total_posts Total posts count + * @var int poster_id Post author id + * @var array row Array with original post and user data + * @var array cp_row Custom profile field data of the poster + * @var array attachments List of attachments + * @var array user_poster_data Poster's data from user cache + * @var array post_row Template block array of the post + * @var array topic_data Array with topic data + * @since 3.1.0-a1 + * @change 3.1.0-a3 Added vars start, current_row_number, end, attachments + * @change 3.1.0-b3 Added topic_data array, total_posts + * @change 3.1.0-RC3 Added poster_id + */ + $vars = array( + 'start', + 'current_row_number', + 'end', + 'total_posts', + 'poster_id', + 'row', + 'cp_row', + 'attachments', + 'user_poster_data', + 'post_row', + 'topic_data', + ); + extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_post_row', compact($vars))); + + $i = $current_row_number; + if (isset($cp_row['row']) && sizeof($cp_row['row'])) { - $postrow = array_merge($postrow, $cp_row['row']); + $post_row = array_merge($post_row, $cp_row['row']); } // Dump vars into template - $template->assign_block_vars('postrow', $postrow); + $template->assign_block_vars('postrow', $post_row); + + $contact_fields = array( + array( + 'ID' => 'pm', + 'NAME' => $user->lang['SEND_PRIVATE_MESSAGE'], + 'U_CONTACT' => $u_pm, + ), + array( + 'ID' => 'email', + 'NAME' => $user->lang['SEND_EMAIL'], + 'U_CONTACT' => $user_cache[$poster_id]['email'], + ), + array( + 'ID' => 'jabber', + 'NAME' => $user->lang['JABBER'], + 'U_CONTACT' => $user_cache[$poster_id]['jabber'], + ), + ); + + foreach ($contact_fields as $field) + { + if ($field['U_CONTACT']) + { + $template->assign_block_vars('postrow.contact', $field); + } + } if (!empty($cp_row['blockrow'])) { foreach ($cp_row['blockrow'] as $field_data) { $template->assign_block_vars('postrow.custom_fields', $field_data); + + if ($field_data['S_PROFILE_CONTACT']) + { + $template->assign_block_vars('postrow.contact', array( + 'ID' => $field_data['PROFILE_FIELD_IDENT'], + 'NAME' => $field_data['PROFILE_FIELD_NAME'], + 'U_CONTACT' => $field_data['PROFILE_FIELD_CONTACT'], + )); + } } } @@ -1625,6 +2032,41 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i) } } + $current_row_number = $i; + + /** + * Event after the post data has been assigned to the template + * + * @event core.viewtopic_post_row_after + * @var int start Start item of this page + * @var int current_row_number Number of the post on this page + * @var int end Number of posts on this page + * @var int total_posts Total posts count + * @var array row Array with original post and user data + * @var array cp_row Custom profile field data of the poster + * @var array attachments List of attachments + * @var array user_poster_data Poster's data from user cache + * @var array post_row Template block array of the post + * @var array topic_data Array with topic data + * @since 3.1.0-a3 + * @change 3.1.0-b3 Added topic_data array, total_posts + */ + $vars = array( + 'start', + 'current_row_number', + 'end', + 'total_posts', + 'row', + 'cp_row', + 'attachments', + 'user_poster_data', + 'post_row', + 'topic_data', + ); + extract($phpbb_dispatcher->trigger_event('core.viewtopic_post_row_after', compact($vars))); + + $i = $current_row_number; + $prev_post_id = $row['post_id']; unset($rowset[$post_list[$i]]); @@ -1650,41 +2092,21 @@ if (isset($user->data['session_page']) && !$user->data['is_bot'] && (strpos($use } } -// Get last post time for all global announcements -// to keep proper forums tracking -if ($topic_data['topic_type'] == POST_GLOBAL) -{ - $sql = 'SELECT topic_last_post_time as forum_last_post_time - FROM ' . TOPICS_TABLE . ' - WHERE forum_id = 0 - ORDER BY topic_last_post_time DESC'; - $result = $db->sql_query_limit($sql, 1); - $topic_data['forum_last_post_time'] = (int) $db->sql_fetchfield('forum_last_post_time'); - $db->sql_freeresult($result); - - $sql = 'SELECT mark_time as forum_mark_time - FROM ' . FORUMS_TRACK_TABLE . ' - WHERE forum_id = 0 - AND user_id = ' . $user->data['user_id']; - $result = $db->sql_query($sql); - $topic_data['forum_mark_time'] = (int) $db->sql_fetchfield('forum_mark_time'); - $db->sql_freeresult($result); -} - // Only mark topic if it's currently unread. Also make sure we do not set topic tracking back if earlier pages are viewed. if (isset($topic_tracking_info[$topic_id]) && $topic_data['topic_last_post_time'] > $topic_tracking_info[$topic_id] && $max_post_time > $topic_tracking_info[$topic_id]) { - markread('topic', (($topic_data['topic_type'] == POST_GLOBAL) ? 0 : $forum_id), $topic_id, $max_post_time); + markread('topic', $forum_id, $topic_id, $max_post_time); // Update forum info - $all_marked_read = update_forum_tracking_info((($topic_data['topic_type'] == POST_GLOBAL) ? 0 : $forum_id), $topic_data['forum_last_post_time'], (isset($topic_data['forum_mark_time'])) ? $topic_data['forum_mark_time'] : false, false); + $all_marked_read = update_forum_tracking_info($forum_id, $topic_data['forum_last_post_time'], (isset($topic_data['forum_mark_time'])) ? $topic_data['forum_mark_time'] : false, false); } else { $all_marked_read = true; } -// If there are absolutely no more unread posts in this forum and unread posts shown, we can savely show the #unread link +// If there are absolutely no more unread posts in this forum +// and unread posts shown, we can safely show the #unread link if ($all_marked_read) { if ($post_unread) @@ -1767,19 +2189,36 @@ if ($s_can_vote || $s_quick_reply) // We overwrite $_REQUEST['f'] if there is no forum specified // to be able to display the correct online list. // One downside is that the user currently viewing this topic/post is not taken into account. -if (empty($_REQUEST['f'])) +if (!request_var('f', 0)) { - $_REQUEST['f'] = $forum_id; + $request->overwrite('f', $forum_id); } // We need to do the same with the topic_id. See #53025. -if (empty($_REQUEST['t']) && !empty($topic_id)) +if (!request_var('t', 0) && !empty($topic_id)) { - $_REQUEST['t'] = $topic_id; + $request->overwrite('t', $topic_id); } +$page_title = $topic_data['topic_title'] . ($start ? ' - ' . sprintf($user->lang['PAGE_TITLE_NUMBER'], $pagination->get_on_page($config['posts_per_page'], $start)) : ''); + +/** +* You can use this event to modify the page title of the viewtopic page +* +* @event core.viewtopic_modify_page_title +* @var string page_title Title of the viewtopic page +* @var array topic_data Array with topic data +* @var int forum_id Forum ID of the topic +* @var int start Start offset used to calculate the page +* @var array post_list Array with post_ids we are going to display +* @since 3.1.0-a1 +* @change 3.1.0-RC4 Added post_list var +*/ +$vars = array('page_title', 'topic_data', 'forum_id', 'start', 'post_list'); +extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_page_title', compact($vars))); + // Output the page -page_header($user->lang['VIEW_TOPIC'] . ' - ' . $topic_data['topic_title'], true, $forum_id); +page_header($page_title, true, $forum_id); $template->set_filenames(array( 'body' => ($view == 'print') ? 'viewtopic_print.html' : 'viewtopic_body.html') @@ -1787,5 +2226,3 @@ $template->set_filenames(array( make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx"), $forum_id); page_footer(); - -?>
\ No newline at end of file |