/** * Get the latest posts of a forum. * * @param mixed[] $latestPostOptions * @return array */ function getLastPosts($latestPostOptions) { global $scripturl, $modSettings; $db = database(); // Find all the posts. Newer ones will have higher IDs. (assuming the last 20 * number are accessable...) // @todo SLOW This query is now slow, NEEDS to be fixed. Maybe break into two? $request = $db->query('substring', ' SELECT m.poster_time, m.subject, m.id_topic, m.id_member, m.id_msg, IFNULL(mem.real_name, m.poster_name) AS poster_name, t.id_board, b.name AS board_name, SUBSTRING(m.body, 1, 385) AS body, m.smileys_enabled FROM {db_prefix}messages AS m INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic) INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member) WHERE m.id_msg >= {int:likely_max_msg}' . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? ' AND b.id_board != {int:recycle_board}' : '') . ' AND {query_wanna_see_board}' . ($modSettings['postmod_active'] ? ' AND t.approved = {int:is_approved} AND m.approved = {int:is_approved}' : '') . ' ORDER BY m.id_msg DESC LIMIT ' . $latestPostOptions['number_posts'], array('likely_max_msg' => max(0, $modSettings['maxMsgID'] - 50 * $latestPostOptions['number_posts']), 'recycle_board' => $modSettings['recycle_board'], 'is_approved' => 1)); $posts = array(); while ($row = $db->fetch_assoc($request)) { // Censor the subject and post for the preview ;). censorText($row['subject']); censorText($row['body']); $row['body'] = strip_tags(strtr(parse_bbc($row['body'], $row['smileys_enabled'], $row['id_msg']), array('<br />' => ' '))); $row['body'] = Util::shorten_text($row['body'], !empty($modSettings['lastpost_preview_characters']) ? $modSettings['lastpost_preview_characters'] : 128, true); // Build the array. $posts[] = array('board' => array('id' => $row['id_board'], 'name' => $row['board_name'], 'href' => $scripturl . '?board=' . $row['id_board'] . '.0', 'link' => '<a href="' . $scripturl . '?board=' . $row['id_board'] . '.0">' . $row['board_name'] . '</a>'), 'topic' => $row['id_topic'], 'poster' => array('id' => $row['id_member'], 'name' => $row['poster_name'], 'href' => empty($row['id_member']) ? '' : $scripturl . '?action=profile;u=' . $row['id_member'], 'link' => empty($row['id_member']) ? $row['poster_name'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['poster_name'] . '</a>'), 'subject' => $row['subject'], 'short_subject' => Util::shorten_text($row['subject'], $modSettings['subject_length']), 'preview' => $row['body'], 'time' => standardTime($row['poster_time']), 'html_time' => htmlTime($row['poster_time']), 'timestamp' => forum_time(true, $row['poster_time']), 'raw_timestamp' => $row['poster_time'], 'href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . ';topicseen#msg' . $row['id_msg'], 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . ';topicseen#msg' . $row['id_msg'] . '" rel="nofollow">' . $row['subject'] . '</a>'); } $db->free_result($request); return $posts; }
/** * Topic informations, descriptions, etc. */ function template_messages_informations_above() { global $context, $settings, $txt, $scripturl, $modSettings; // Show the topic information - icon, subject, etc. echo ' <div id="forumposts" class="forumposts"> <h2 class="category_header"> <img src="', $settings['images_url'], '/topic/', $context['class'], '.png" alt="" /> ', $txt['topic'], ': ', $context['subject'], ' <span class="views_text">(', $context['num_views_text'], ')</span> <span class="nextlinks">', !empty($context['links']['go_prev']) ? '<a href="' . $context['links']['go_prev'] . '">' . $txt['previous_next_back'] . '</a>' : '', !empty($context['links']['go_next']) ? ' - <a href="' . $context['links']['go_next'] . '">' . $txt['previous_next_forward'] . '</a>' : '', !empty($context['links']['derived_from']) ? ' - <a href="' . $context['links']['derived_from'] . '">' . sprintf($txt['topic_derived_from'], '<em>' . Util::shorten_text($context['topic_derived_from']['subject'], $modSettings['subject_length'])) . '</em></a>' : '', '</span> </h2>'; if (!empty($settings['display_who_viewing']) || !empty($context['topic_redirected_from'])) { echo ' <div class="generalinfo">'; if (!empty($settings['display_who_viewing'])) { echo ' <span id="whoisviewing">'; // Show just numbers...? if ($settings['display_who_viewing'] == 1) { echo count($context['view_members']), ' ', count($context['view_members']) === 1 ? $txt['who_member'] : $txt['members']; } else { echo empty($context['view_members_list']) ? '0 ' . $txt['members'] : implode(', ', $context['view_members_list']) . (empty($context['view_num_hidden']) || $context['can_moderate_forum'] ? '' : ' (+ ' . $context['view_num_hidden'] . ' ' . $txt['hidden'] . ')'); } // Now show how many guests are here too. echo $txt['who_and'], $context['view_num_guests'], ' ', $context['view_num_guests'] == 1 ? $txt['guest'] : $txt['guests'], $txt['who_viewing_topic'], ' </span>'; } // Is this topic a redirect? if (!empty($context['topic_redirected_from'])) { echo ' <span id="redirectfrom"> ' . sprintf($txt['no_redir'], '<a href="' . $context['topic_redirected_from']['redir_href'] . '">' . $context['topic_redirected_from']['subject'] . '</a>'), ' </span>'; } echo ' </div>'; } echo ' <form action="', $scripturl, '?action=quickmod2;topic=', $context['current_topic'], '.', $context['start'], '" method="post" accept-charset="UTF-8" name="quickModForm" id="quickModForm" style="margin: 0;" onsubmit="return oQuickModify.bInEditMode ? oQuickModify.modifySave(\'' . $context['session_id'] . '\', \'' . $context['session_var'] . '\') : false">'; }
/** * Get the latest post made on the system * * - respects approved, recycled, and board permissions * * @package Posts * @return array */ function lastPost() { global $scripturl, $modSettings; $db = database(); // Find it by the board - better to order by board than sort the entire messages table. $request = $db->query('substring', ' SELECT ml.poster_time, ml.subject, ml.id_topic, ml.poster_name, SUBSTRING(ml.body, 1, 385) AS body, ml.smileys_enabled FROM {db_prefix}boards AS b INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = b.id_last_msg) WHERE {query_wanna_see_board}' . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? ' AND b.id_board != {int:recycle_board}' : '') . ' AND ml.approved = {int:is_approved} ORDER BY b.id_msg_updated DESC LIMIT 1', array('recycle_board' => $modSettings['recycle_board'], 'is_approved' => 1)); if ($db->num_rows($request) == 0) { return array(); } $row = $db->fetch_assoc($request); $db->free_result($request); // Censor the subject and post... censorText($row['subject']); censorText($row['body']); $row['body'] = strip_tags(strtr(parse_bbc($row['body'], $row['smileys_enabled']), array('<br />' => ' '))); $row['body'] = Util::shorten_text($row['body'], !empty($modSettings['lastpost_preview_characters']) ? $modSettings['lastpost_preview_characters'] : 128, true); // Send the data. return array('topic' => $row['id_topic'], 'subject' => $row['subject'], 'short_subject' => Util::shorten_text($row['subject'], $modSettings['subject_length']), 'preview' => $row['body'], 'time' => standardTime($row['poster_time']), 'html_time' => htmlTime($row['poster_time']), 'timestamp' => forum_time(true, $row['poster_time']), 'href' => $scripturl . '?topic=' . $row['id_topic'] . '.new;topicseen#new', 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.new;topicseen#new">' . $row['subject'] . '</a>'); }
/** * Recent topic list: * [board] Subject by Poster Date * * @param int $num_recent * @param int[]|null $exclude_boards * @param bool|null $include_boards * @param string $output_method = 'echo' */ function ssi_recentTopics($num_recent = 8, $exclude_boards = null, $include_boards = null, $output_method = 'echo') { global $settings, $scripturl, $txt, $user_info, $modSettings; $db = database(); if ($exclude_boards === null && !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0) { $exclude_boards = array($modSettings['recycle_board']); } else { $exclude_boards = empty($exclude_boards) ? array() : (is_array($exclude_boards) ? $exclude_boards : array($exclude_boards)); } // Only some boards?. if (is_array($include_boards) || (int) $include_boards === $include_boards) { $include_boards = is_array($include_boards) ? $include_boards : array($include_boards); } elseif ($include_boards != null) { $output_method = $include_boards; $include_boards = array(); } require_once SUBSDIR . '/MessageIndex.subs.php'; $icon_sources = MessageTopicIcons(); // Find all the posts in distinct topics. Newer ones will have higher IDs. $request = $db->query('', ' SELECT t.id_topic, b.id_board, b.name AS board_name FROM {db_prefix}topics AS t INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg) LEFT JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) WHERE t.id_last_msg >= {int:min_message_id}' . (empty($exclude_boards) ? '' : ' AND b.id_board NOT IN ({array_int:exclude_boards})') . '' . (empty($include_boards) ? '' : ' AND b.id_board IN ({array_int:include_boards})') . ' AND {query_wanna_see_board}' . ($modSettings['postmod_active'] ? ' AND t.approved = {int:is_approved} AND ml.approved = {int:is_approved}' : '') . ' ORDER BY t.id_last_msg DESC LIMIT ' . $num_recent, array('include_boards' => empty($include_boards) ? '' : $include_boards, 'exclude_boards' => empty($exclude_boards) ? '' : $exclude_boards, 'min_message_id' => $modSettings['maxMsgID'] - 35 * min($num_recent, 5), 'is_approved' => 1)); $topics = array(); while ($row = $db->fetch_assoc($request)) { $topics[$row['id_topic']] = $row; } $db->free_result($request); // Did we find anything? If not, bail. if (empty($topics)) { return array(); } // Find all the posts in distinct topics. Newer ones will have higher IDs. $request = $db->query('substring', ' SELECT mf.poster_time, mf.subject, ml.id_topic, mf.id_member, ml.id_msg, t.num_replies, t.num_views, mg.online_color, IFNULL(mem.real_name, mf.poster_name) AS poster_name, ' . ($user_info['is_guest'] ? '1 AS is_read, 0 AS new_from' : ' IFNULL(lt.id_msg, IFNULL(lmr.id_msg, 0)) >= ml.id_msg_modified AS is_read, IFNULL(lt.id_msg, IFNULL(lmr.id_msg, -1)) + 1 AS new_from') . ', SUBSTRING(mf.body, 1, 384) AS body, mf.smileys_enabled, mf.icon FROM {db_prefix}topics AS t INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg) INNER JOIN {db_prefix}messages AS mf ON (mf.id_msg = t.id_last_msg) LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = mf.id_member)' . (!$user_info['is_guest'] ? ' LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member}) LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member})' : '') . ' LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = mem.id_group) WHERE t.id_topic IN ({array_int:topic_list})', array('current_member' => $user_info['id'], 'topic_list' => array_keys($topics))); $posts = array(); while ($row = $db->fetch_assoc($request)) { $row['body'] = strip_tags(strtr(parse_bbc($row['body'], $row['smileys_enabled'], $row['id_msg']), array('<br />' => ' '))); if (Util::strlen($row['body']) > 128) { $row['body'] = Util::substr($row['body'], 0, 128) . '...'; } // Censor the subject. censorText($row['subject']); censorText($row['body']); if (!empty($modSettings['messageIconChecks_enable']) && !isset($icon_sources[$row['icon']])) { $icon_sources[$row['icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['icon'] . '.png') ? 'images_url' : 'default_images_url'; } // Build the array. $posts[] = array('board' => array('id' => $topics[$row['id_topic']]['id_board'], 'name' => $topics[$row['id_topic']]['board_name'], 'href' => $scripturl . '?board=' . $topics[$row['id_topic']]['id_board'] . '.0', 'link' => '<a href="' . $scripturl . '?board=' . $topics[$row['id_topic']]['id_board'] . '.0">' . $topics[$row['id_topic']]['board_name'] . '</a>'), 'topic' => $row['id_topic'], 'poster' => array('id' => $row['id_member'], 'name' => $row['poster_name'], 'href' => empty($row['id_member']) ? '' : $scripturl . '?action=profile;u=' . $row['id_member'], 'link' => empty($row['id_member']) ? $row['poster_name'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['poster_name'] . '</a>'), 'subject' => $row['subject'], 'replies' => $row['num_replies'], 'views' => $row['num_views'], 'short_subject' => Util::shorten_text($row['subject'], 25), 'preview' => $row['body'], 'time' => standardTime($row['poster_time']), 'html_time' => htmlTime($row['poster_time']), 'timestamp' => forum_time(true, $row['poster_time']), 'href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . ';topicseen#new', 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#new" rel="nofollow">' . $row['subject'] . '</a>', 'new' => !empty($row['is_read']), 'is_new' => empty($row['is_read']), 'new_from' => $row['new_from'], 'icon' => '<img src="' . $settings[$icon_sources[$row['icon']]] . '/post/' . $row['icon'] . '.png" style="vertical-align: middle;" alt="' . $row['icon'] . '" />'); } $db->free_result($request); // Just return it. if ($output_method != 'echo' || empty($posts)) { return $posts; } echo ' <table class="ssi_table">'; foreach ($posts as $post) { echo ' <tr> <td class="righttext top"> [', $post['board']['link'], '] </td> <td class="top"> <a href="', $post['href'], '">', $post['subject'], '</a> ', $txt['by'], ' ', $post['poster']['link'], ' ', !$post['is_new'] ? '' : '<a href="' . $scripturl . '?topic=' . $post['topic'] . '.msg' . $post['new_from'] . ';topicseen#new" rel="nofollow"><span class="new_posts">' . $txt['new'] . '</span></a>', ' </td> <td class="righttext"> ', $post['time'], ' </td> </tr>'; } echo ' </table>'; }
/** * A complicated but relatively quick internal search. */ public function action_search_internal() { global $context, $txt, $helptxt, $scripturl; // Try to get some more memory. setMemoryLimit('128M'); // Load a lot of language files. $language_files = array('Help', 'ManageMail', 'ManageSettings', 'ManageCalendar', 'ManageBoards', 'ManagePaid', 'ManagePermissions', 'Search', 'Login', 'ManageSmileys', 'Maillist'); // All the files we need to include. $include_files = array('AddonSettings.controller', 'AdminLog.controller', 'CoreFeatures.controller', 'ManageAttachments.controller', 'ManageAvatars.controller', 'ManageBBC.controller', 'ManageBoards.controller', 'ManageCalendar.controller', 'ManageDrafts.controller', 'ManageFeatures.controller', 'ManageLanguages.controller', 'ManageMail.controller', 'ManageNews.controller', 'ManagePaid.controller', 'ManagePermissions.controller', 'ManagePosts.controller', 'ManageRegistration.controller', 'ManageSearch.controller', 'ManageSearchEngines.controller', 'ManageSecurity.controller', 'ManageServer.controller', 'ManageSmileys.controller', 'ManageTopics.controller', 'ManageMaillist.controller', 'ManageMembergroups.controller'); // This is a special array of functions that contain setting data // - we query all these to simply pull all setting bits! $settings_search = array(array('settings_search', 'area=logs;sa=pruning', 'AdminLog_Controller'), array('config_vars', 'area=corefeatures', 'CoreFeatures_Controller'), array('basicSettings_search', 'area=featuresettings;sa=basic', 'ManageFeatures_Controller'), array('layoutSettings_search', 'area=featuresettings;sa=layout', 'ManageFeatures_Controller'), array('karmaSettings_search', 'area=featuresettings;sa=karma', 'ManageFeatures_Controller'), array('likesSettings_search', 'area=featuresettings;sa=likes', 'ManageFeatures_Controller'), array('mentionSettings_search', 'area=featuresettings;sa=mention', 'ManageFeatures_Controller'), array('signatureSettings_search', 'area=featuresettings;sa=sig', 'ManageFeatures_Controller'), array('settings_search', 'area=addonsettings;sa=general', 'AddonSettings_Controller'), array('settings_search', 'area=manageattachments;sa=attachments', 'ManageAttachments_Controller'), array('settings_search', 'area=manageattachments;sa=avatars', 'ManageAvatars_Controller'), array('settings_search', 'area=postsettings;sa=bbc', 'ManageBBC_Controller'), array('settings_search', 'area=manageboards;sa=settings', 'ManageBoards_Controller'), array('settings_search', 'area=managecalendar;sa=settings', 'ManageCalendar_Controller'), array('settings_search', 'area=managedrafts', 'ManageDrafts_Controller'), array('settings_search', 'area=languages;sa=settings', 'ManageLanguages_Controller'), array('settings_search', 'area=mailqueue;sa=settings', 'ManageMail_Controller'), array('settings_search', 'area=maillist;sa=emailsettings', 'ManageMaillist_Controller'), array('settings_search', 'area=membergroups;sa=settings', 'ManageMembergroups_Controller'), array('settings_search', 'area=news;sa=settings', 'ManageNews_Controller'), array('settings_search', 'area=paidsubscribe;sa=settings', 'ManagePaid_Controller'), array('settings_search', 'area=permissions;sa=settings', 'ManagePermissions_Controller'), array('settings_search', 'area=postsettings;sa=posts', 'ManagePosts_Controller'), array('settings_search', 'area=regcenter;sa=settings', 'ManageRegistration_Controller'), array('settings_search', 'area=managesearch;sa=settings', 'ManageSearch_Controller'), array('settings_search', 'area=sengines;sa=settings', 'ManageSearchEngines_Controller'), array('securitySettings_search', 'area=securitysettings;sa=general', 'ManageSecurity_Controller'), array('spamSettings_search', 'area=securitysettings;sa=spam', 'ManageSecurity_Controller'), array('moderationSettings_search', 'area=securitysettings;sa=moderation', 'ManageSecurity_Controller'), array('bbSettings_search', 'area=securitysettings;sa=badbehavior', 'ManageSecurity_Controller'), array('generalSettings_search', 'area=serversettings;sa=general', 'ManageServer_Controller'), array('databaseSettings_search', 'area=serversettings;sa=database', 'ManageServer_Controller'), array('cookieSettings_search', 'area=serversettings;sa=cookie', 'ManageServer_Controller'), array('cacheSettings_search', 'area=serversettings;sa=cache', 'ManageServer_Controller'), array('balancingSettings_search', 'area=serversettings;sa=loads', 'ManageServer_Controller'), array('settings_search', 'area=smileys;sa=settings', 'ManageSmileys_Controller'), array('settings_search', 'area=postsettings;sa=topics', 'ManageTopics_Controller')); call_integration_hook('integrate_admin_search', array(&$language_files, &$include_files, &$settings_search)); loadLanguage(implode('+', $language_files)); foreach ($include_files as $file) { require_once ADMINDIR . '/' . $file . '.php'; } /* This is the huge array that defines everything ... it's items are formatted as follows: 0 = Language index (Can be array of indexes) to search through for this setting. 1 = URL for this indexes page. 2 = Help index for help associated with this item (If different from 0) */ $search_data = array('sections' => array(), 'settings' => array(array('COPPA', 'area=regcenter;sa=settings'), array('CAPTCHA', 'area=securitysettings;sa=spam'))); // Go through the admin menu structure trying to find suitably named areas! foreach ($context[$context['admin_menu_name']]['sections'] as $section) { foreach ($section['areas'] as $menu_key => $menu_item) { $search_data['sections'][] = array($menu_item['label'], 'area=' . $menu_key); if (!empty($menu_item['subsections'])) { foreach ($menu_item['subsections'] as $key => $sublabel) { if (isset($sublabel['label'])) { $search_data['sections'][] = array($sublabel['label'], 'area=' . $menu_key . ';sa=' . $key); } } } } } foreach ($settings_search as $setting_area) { // Get a list of their variables. if (isset($setting_area[2])) { // an OOP controller: get the settings from the settings method. $controller = new $setting_area[2](); $config_vars = $controller->{$setting_area[0]}(); } else { // a good ole' procedural controller: get the settings from the function. $config_vars = $setting_area[0](true); } foreach ($config_vars as $var) { if (!empty($var[1]) && !in_array($var[0], array('permissions', 'switch', 'warning'))) { $search_data['settings'][] = array($var[isset($var[2]) && in_array($var[2], array('file', 'db')) ? 0 : 1], $setting_area[1]); } } } $context['page_title'] = $txt['admin_search_results']; $context['search_results'] = array(); // Go through all the search data trying to find this text! $search_term = strtolower(un_htmlspecialchars($context['search_term'])); foreach ($search_data as $section => $data) { foreach ($data as $item) { $found = false; if (!is_array($item[0])) { $item[0] = array($item[0]); } foreach ($item[0] as $term) { if (stripos($term, $search_term) !== false || isset($txt[$term]) && stripos($txt[$term], $search_term) !== false || isset($txt['setting_' . $term]) && stripos($txt['setting_' . $term], $search_term) !== false) { $found = $term; break; } } if ($found) { // Format the name - and remove any descriptions the entry may have. $name = isset($txt[$found]) ? $txt[$found] : (isset($txt['setting_' . $found]) ? $txt['setting_' . $found] : $found); $name = preg_replace('~<(?:div|span)\\sclass="smalltext">.+?</(?:div|span)>~', '', $name); if (!empty($name)) { $context['search_results'][] = array('url' => (substr($item[1], 0, 4) == 'area' ? $scripturl . '?action=admin;' . $item[1] : $item[1]) . ';' . $context['session_var'] . '=' . $context['session_id'] . (substr($item[1], 0, 4) == 'area' && $section == 'settings' ? '#' . $item[0][0] : ''), 'name' => $name, 'type' => $section, 'help' => Util::shorten_text(isset($item[2]) ? strip_tags($helptxt[$item[2]]) : (isset($helptxt[$found]) ? strip_tags($helptxt[$found]) : ''), 255)); } } } } }
/** * Fetches a list of boards and (optional) categories including * statistical information, sub-boards and moderators. * - Used by both the board index (main data) and the message index (child * boards). * - Depending on the include_categories setting returns an associative * array with categories->boards->child_boards or an associative array * with boards->child_boards. * * @return array */ public function getBoards() { global $txt; // Find all boards and categories, as well as related information. $result_boards = $this->_db->query('boardindex_fetch_boards', ' SELECT' . ($this->_options['include_categories'] ? ' c.id_cat, c.name AS cat_name,' : '') . ' b.id_board, b.name AS board_name, b.description, CASE WHEN b.redirect != {string:blank_string} THEN 1 ELSE 0 END AS is_redirect, b.num_posts, b.num_topics, b.unapproved_posts, b.unapproved_topics, b.id_parent, IFNULL(m.poster_time, 0) AS poster_time, IFNULL(mem.member_name, m.poster_name) AS poster_name, m.subject, m.id_topic, IFNULL(mem.real_name, m.poster_name) AS real_name, ' . ($this->_user['is_guest'] ? ' 1 AS is_read, 0 AS new_from,' : ' (IFNULL(lb.id_msg, 0) >= b.id_msg_updated) AS is_read, IFNULL(lb.id_msg, -1) + 1 AS new_from,' . ($this->_options['include_categories'] ? ' c.can_collapse, IFNULL(cc.id_member, 0) AS is_collapsed,' : '')) . ' IFNULL(mem.id_member, 0) AS id_member, mem.avatar, m.id_msg' . ($this->_options['avatars_on_indexes'] ? ', IFNULL(a.id_attach, 0) AS id_attach, a.filename, a.attachment_type, mem.email_address' : '') . ' FROM {db_prefix}boards AS b' . ($this->_options['include_categories'] ? ' LEFT JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat)' : '') . ' LEFT JOIN {db_prefix}messages AS m ON (m.id_msg = b.id_last_msg) LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)' . ($this->_user['is_guest'] ? '' : ' LEFT JOIN {db_prefix}log_boards AS lb ON (lb.id_board = b.id_board AND lb.id_member = {int:current_member})' . ($this->_options['include_categories'] ? ' LEFT JOIN {db_prefix}collapsed_categories AS cc ON (cc.id_cat = c.id_cat AND cc.id_member = {int:current_member})' : '')) . ($this->_options['avatars_on_indexes'] ? ' LEFT JOIN {db_prefix}attachments AS a ON (a.id_member = m.id_member AND a.id_member != 0)' : '') . ' WHERE {query_see_board}' . (empty($this->_options['countChildPosts']) ? empty($this->_options['base_level']) ? '' : ' AND b.child_level >= {int:child_level}' : ' AND b.child_level BETWEEN ' . $this->_options['base_level'] . ' AND ' . ($this->_options['base_level'] + 1)) . ' ORDER BY' . ($this->_options['include_categories'] ? ' c.cat_order,' : '') . ' b.board_order', array('current_member' => $this->_user['id'], 'child_level' => $this->_options['base_level'], 'blank_string' => '')); // Run through the categories and boards (or only boards).... while ($row_board = $this->_db->fetch_assoc($result_boards)) { // Perhaps we are ignoring this board? $ignoreThisBoard = in_array($row_board['id_board'], $this->_user['ignoreboards']); $row_board['is_read'] = !empty($row_board['is_read']) || $ignoreThisBoard ? '1' : '0'; // Not a child. $isChild = false; if ($this->_options['include_categories']) { // Haven't set this category yet. if (empty($this->_categories[$row_board['id_cat']])) { $this->_categories[$row_board['id_cat']] = array('id' => $row_board['id_cat'], 'name' => $row_board['cat_name'], 'is_collapsed' => isset($row_board['can_collapse']) && $row_board['can_collapse'] == 1 && $row_board['is_collapsed'] > 0, 'can_collapse' => isset($row_board['can_collapse']) && $row_board['can_collapse'] == 1, 'collapse_href' => isset($row_board['can_collapse']) ? $this->_scripturl . '?action=collapse;c=' . $row_board['id_cat'] . ';sa=' . ($row_board['is_collapsed'] > 0 ? 'expand;' : 'collapse;') . $this->_session_url . '#c' . $row_board['id_cat'] : '', 'collapse_image' => isset($row_board['can_collapse']) ? '<img src="' . $this->_images_url . ($row_board['is_collapsed'] > 0 ? 'expand.png" alt="+"' : 'collapse.png" alt="-"') . ' />' : '', 'href' => $this->_scripturl . '#c' . $row_board['id_cat'], 'boards' => array(), 'new' => false); $this->_categories[$row_board['id_cat']]['link'] = '<a id="c' . $row_board['id_cat'] . '"></a>' . (!$this->_user['is_guest'] ? '<a href="' . $this->_scripturl . '?action=unread;c=' . $row_board['id_cat'] . '" title="' . sprintf($txt['new_posts_in_category'], strip_tags($row_board['cat_name'])) . '">' . $row_board['cat_name'] . '</a>' : $row_board['cat_name']); } // If this board has new posts in it (and isn't the recycle bin!) then the category is new. if ($this->_recycle_board != $row_board['id_board']) { $this->_categories[$row_board['id_cat']]['new'] |= empty($row_board['is_read']) && $row_board['poster_name'] != ''; } // Avoid showing category unread link where it only has redirection boards. $this->_categories[$row_board['id_cat']]['show_unread'] = !empty($this->_categories[$row_board['id_cat']]['show_unread']) ? 1 : !$row_board['is_redirect']; // Collapsed category - don't do any of this. if ($this->_categories[$row_board['id_cat']]['is_collapsed']) { continue; } // Let's save some typing. Climbing the array might be slower, anyhow. $this->_current_boards =& $this->_categories[$row_board['id_cat']]['boards']; } // This is a parent board. if ($row_board['id_parent'] == $this->_options['parent_id']) { // Is this a new board, or just another moderator? if (!isset($this->_current_boards[$row_board['id_board']])) { $this->_current_boards[$row_board['id_board']] = array('new' => empty($row_board['is_read']), 'id' => $row_board['id_board'], 'name' => $row_board['board_name'], 'description' => $row_board['description'], 'moderators' => array(), 'link_moderators' => array(), 'children' => array(), 'link_children' => array(), 'children_new' => false, 'topics' => $row_board['num_topics'], 'posts' => $row_board['num_posts'], 'is_redirect' => $row_board['is_redirect'], 'unapproved_topics' => $row_board['unapproved_topics'], 'unapproved_posts' => $row_board['unapproved_posts'] - $row_board['unapproved_topics'], 'can_approve_posts' => $this->_user['mod_cache_ap'] == array(0) || in_array($row_board['id_board'], $this->_user['mod_cache_ap']), 'href' => $this->_scripturl . '?board=' . $row_board['id_board'] . '.0', 'link' => '<a href="' . $this->_scripturl . '?board=' . $row_board['id_board'] . '.0">' . $row_board['board_name'] . '</a>'); } $this->_boards[$row_board['id_board']] = $this->_options['include_categories'] ? $row_board['id_cat'] : 0; } elseif (isset($this->_current_boards[$row_board['id_parent']]['children']) && !isset($this->_current_boards[$row_board['id_parent']]['children'][$row_board['id_board']])) { // A valid child! $isChild = true; $this->_current_boards[$row_board['id_parent']]['children'][$row_board['id_board']] = array('id' => $row_board['id_board'], 'name' => $row_board['board_name'], 'description' => $row_board['description'], 'new' => empty($row_board['is_read']) && $row_board['poster_name'] != '', 'topics' => $row_board['num_topics'], 'posts' => $row_board['num_posts'], 'is_redirect' => $row_board['is_redirect'], 'unapproved_topics' => $row_board['unapproved_topics'], 'unapproved_posts' => $row_board['unapproved_posts'] - $row_board['unapproved_topics'], 'can_approve_posts' => $this->_user['mod_cache_ap'] == array(0) || in_array($row_board['id_board'], $this->_user['mod_cache_ap']), 'href' => $this->_scripturl . '?board=' . $row_board['id_board'] . '.0', 'link' => '<a href="' . $this->_scripturl . '?board=' . $row_board['id_board'] . '.0">' . $row_board['board_name'] . '</a>'); // Counting sub-board posts is... slow :/. if (!empty($this->_options['countChildPosts']) && !$row_board['is_redirect']) { $this->_current_boards[$row_board['id_parent']]['posts'] += $row_board['num_posts']; $this->_current_boards[$row_board['id_parent']]['topics'] += $row_board['num_topics']; } // Does this board contain new boards? $this->_current_boards[$row_board['id_parent']]['children_new'] |= empty($row_board['is_read']); // This is easier to use in many cases for the theme.... $this->_current_boards[$row_board['id_parent']]['link_children'][] =& $this->_current_boards[$row_board['id_parent']]['children'][$row_board['id_board']]['link']; } elseif (!empty($this->_options['countChildPosts'])) { // @todo why this is not initialized outside the loop? if (!isset($parent_map)) { $parent_map = array(); } if (!isset($parent_map[$row_board['id_parent']])) { foreach ($this->_current_boards as $id => $board) { if (!isset($board['children'][$row_board['id_parent']])) { continue; } $parent_map[$row_board['id_parent']] = array(&$this->_current_boards[$id], &$this->_current_boards[$id]['children'][$row_board['id_parent']]); $parent_map[$row_board['id_board']] = array(&$this->_current_boards[$id], &$this->_current_boards[$id]['children'][$row_board['id_parent']]); break; } } if (isset($parent_map[$row_board['id_parent']]) && !$row_board['is_redirect']) { $parent_map[$row_board['id_parent']][0]['posts'] += $row_board['num_posts']; $parent_map[$row_board['id_parent']][0]['topics'] += $row_board['num_topics']; $parent_map[$row_board['id_parent']][1]['posts'] += $row_board['num_posts']; $parent_map[$row_board['id_parent']][1]['topics'] += $row_board['num_topics']; continue; } continue; } else { continue; } // Prepare the subject, and make sure it's not too long. censorText($row_board['subject']); $row_board['short_subject'] = Util::shorten_text($row_board['subject'], $this->_subject_length); $this_last_post = array('id' => $row_board['id_msg'], 'time' => $row_board['poster_time'] > 0 ? standardTime($row_board['poster_time']) : $txt['not_applicable'], 'html_time' => $row_board['poster_time'] > 0 ? htmlTime($row_board['poster_time']) : $txt['not_applicable'], 'timestamp' => forum_time(true, $row_board['poster_time']), 'subject' => $row_board['short_subject'], 'member' => array('id' => $row_board['id_member'], 'username' => $row_board['poster_name'] != '' ? $row_board['poster_name'] : $txt['not_applicable'], 'name' => $row_board['real_name'], 'href' => $row_board['poster_name'] != '' && !empty($row_board['id_member']) ? $this->_scripturl . '?action=profile;u=' . $row_board['id_member'] : '', 'link' => $row_board['poster_name'] != '' ? !empty($row_board['id_member']) ? '<a href="' . $this->_scripturl . '?action=profile;u=' . $row_board['id_member'] . '">' . $row_board['real_name'] . '</a>' : $row_board['real_name'] : $txt['not_applicable']), 'start' => 'msg' . $row_board['new_from'], 'topic' => $row_board['id_topic']); if ($this->_options['avatars_on_indexes']) { $this_last_post['member']['avatar'] = determineAvatar($row_board); } // Provide the href and link. if ($row_board['subject'] != '') { $this_last_post['href'] = $this->_scripturl . '?topic=' . $row_board['id_topic'] . '.msg' . ($this->_user['is_guest'] ? $row_board['id_msg'] : $row_board['new_from']) . (empty($row_board['is_read']) ? ';boardseen' : '') . '#new'; $this_last_post['link'] = '<a href="' . $this_last_post['href'] . '" title="' . $row_board['subject'] . '">' . $row_board['short_subject'] . '</a>'; /* The board's and children's 'last_post's have: time, timestamp (a number that represents the time.), id (of the post), topic (topic id.), link, href, subject, start (where they should go for the first unread post.), and member. (which has id, name, link, href, username in it.) */ $this_last_post['last_post_message'] = sprintf($txt['last_post_message'], $this_last_post['member']['link'], $this_last_post['link'], $this_last_post['html_time']); } else { $this_last_post['href'] = ''; $this_last_post['link'] = $txt['not_applicable']; $this_last_post['last_post_message'] = ''; } // Set the last post in the parent board. if ($row_board['id_parent'] == $this->_options['parent_id'] || $isChild && !empty($row_board['poster_time']) && $this->_current_boards[$row_board['id_parent']]['last_post']['timestamp'] < forum_time(true, $row_board['poster_time'])) { $this->_current_boards[$isChild ? $row_board['id_parent'] : $row_board['id_board']]['last_post'] = $this_last_post; } // Just in the child...? if ($isChild) { $this->_current_boards[$row_board['id_parent']]['children'][$row_board['id_board']]['last_post'] = $this_last_post; // If there are no posts in this board, it really can't be new... $this->_current_boards[$row_board['id_parent']]['children'][$row_board['id_board']]['new'] &= $row_board['poster_name'] != ''; } elseif ($row_board['poster_name'] == '') { $this->_current_boards[$row_board['id_board']]['new'] = false; } // Determine a global most recent topic. if ($this->_options['set_latest_post'] && !empty($row_board['poster_time']) && $row_board['poster_time'] > $this->_latest_post['timestamp'] && !$ignoreThisBoard) { $this->_latest_post =& $this->_current_boards[$isChild ? $row_board['id_parent'] : $row_board['id_board']]['last_post']; } } $this->_db->free_result($result_boards); if ($this->_options['get_moderators'] && !empty($this->_boards)) { $this->_getBoardModerators(); } return $this->_options['include_categories'] ? $this->_categories : $this->_current_boards; }
/** * View the user profile summary. * * @uses ProfileInfo template */ public function action_summary() { global $context, $memberContext, $txt, $modSettings, $user_info, $user_profile, $scripturl, $settings; $memID = currentMemberID(); // Attempt to load the member's profile data. if (!loadMemberContext($memID) || !isset($memberContext[$memID])) { fatal_lang_error('not_a_user', false); } loadTemplate('ProfileInfo'); // Set up the stuff and load the user. $context += array('page_title' => sprintf($txt['profile_of_username'], $memberContext[$memID]['name']), 'can_send_pm' => allowedTo('pm_send'), 'can_send_email' => allowedTo('send_email_to_members'), 'can_have_buddy' => allowedTo('profile_identity_own') && !empty($modSettings['enable_buddylist']), 'can_issue_warning' => in_array('w', $context['admin_features']) && allowedTo('issue_warning') && !empty($modSettings['warning_enable'])); $context['member'] =& $memberContext[$memID]; $context['can_view_warning'] = in_array('w', $context['admin_features']) && (allowedTo('issue_warning') && !$context['user']['is_owner']) || !empty($modSettings['warning_show']) && ($modSettings['warning_show'] > 1 || $context['user']['is_owner']); // Set a canonical URL for this page. $context['canonical_url'] = $scripturl . '?action=profile;u=' . $memID; // Are there things we don't show? $context['disabled_fields'] = isset($modSettings['disabled_profile_fields']) ? array_flip(explode(',', $modSettings['disabled_profile_fields'])) : array(); // Menu tab $context[$context['profile_menu_name']]['tab_data'] = array(); // Tab information for use in the summary page // Each tab template defines a div, the value of which are the template(s) to load in that div // Templates are named template_profile_block_YOURNAME $context['summarytabs'] = array('summary' => array('name' => $txt['summary'], 'templates' => array(array('summary', 'user_info'), array('contact', 'other_info'), array('user_customprofileinfo', 'moderation')), 'active' => true), 'recent' => array('name' => $txt['profile_recent_activity'], 'templates' => array('posts', 'topics', 'attachments'), 'active' => true), 'buddies' => array('name' => $txt['buddies'], 'templates' => array('buddies'), 'active' => !empty($modSettings['enable_buddylist']) && $context['user']['is_owner'])); // Let addons add or remove to the tabs array call_integration_hook('integrate_profile_summary', array($memID)); // Go forward with whats left $summary_areas = ''; foreach ($context['summarytabs'] as $id => $tab) { // If the tab is active we add it if ($tab['active'] !== true) { unset($context['summarytabs'][$id]); } else { // All the active templates, used to prevent processing data we don't need foreach ($tab['templates'] as $template) { $summary_areas .= is_array($template) ? implode(',', $template) : ',' . $template; } } } $summary_areas = explode(',', $summary_areas); // See if they have broken any warning levels... if (!empty($modSettings['warning_mute']) && $modSettings['warning_mute'] <= $context['member']['warning']) { $context['warning_status'] = $txt['profile_warning_is_muted']; } elseif (!empty($modSettings['warning_moderate']) && $modSettings['warning_moderate'] <= $context['member']['warning']) { $context['warning_status'] = $txt['profile_warning_is_moderation']; } elseif (!empty($modSettings['warning_watch']) && $modSettings['warning_watch'] <= $context['member']['warning']) { $context['warning_status'] = $txt['profile_warning_is_watch']; } // They haven't even been registered for a full day!? $days_registered = (int) ((time() - $user_profile[$memID]['date_registered']) / (3600 * 24)); if (empty($user_profile[$memID]['date_registered']) || $days_registered < 1) { $context['member']['posts_per_day'] = $txt['not_applicable']; } else { $context['member']['posts_per_day'] = comma_format($context['member']['real_posts'] / $days_registered, 3); } // Set the age... if (empty($context['member']['birth_date'])) { $context['member'] += array('age' => $txt['not_applicable'], 'today_is_birthday' => false); } else { list($birth_year, $birth_month, $birth_day) = sscanf($context['member']['birth_date'], '%d-%d-%d'); $datearray = getdate(forum_time()); $context['member'] += array('age' => $birth_year <= 4 ? $txt['not_applicable'] : $datearray['year'] - $birth_year - ($datearray['mon'] > $birth_month || $datearray['mon'] == $birth_month && $datearray['mday'] >= $birth_day ? 0 : 1), 'today_is_birthday' => $datearray['mon'] == $birth_month && $datearray['mday'] == $birth_day); } if (allowedTo('moderate_forum')) { // Make sure it's a valid ip address; otherwise, don't bother... if (preg_match('/^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/', $memberContext[$memID]['ip']) == 1 && empty($modSettings['disableHostnameLookup'])) { $context['member']['hostname'] = host_from_ip($memberContext[$memID]['ip']); } else { $context['member']['hostname'] = ''; } $context['can_see_ip'] = true; } else { $context['can_see_ip'] = false; } if (!empty($modSettings['who_enabled']) && $context['member']['online']['is_online']) { include_once SUBSDIR . '/Who.subs.php'; $action = determineActions($user_profile[$memID]['url']); loadLanguage('index'); if ($action !== false) { $context['member']['action'] = $action; } } // If the user is awaiting activation, and the viewer has permission - setup some activation context messages. if ($context['member']['is_activated'] % 10 != 1 && allowedTo('moderate_forum')) { $context['activate_type'] = $context['member']['is_activated']; // What should the link text be? $context['activate_link_text'] = in_array($context['member']['is_activated'], array(3, 4, 5, 13, 14, 15)) ? $txt['account_approve'] : $txt['account_activate']; // Should we show a custom message? $context['activate_message'] = isset($txt['account_activate_method_' . $context['member']['is_activated'] % 10]) ? $txt['account_activate_method_' . $context['member']['is_activated'] % 10] : $txt['account_not_activated']; $context['activate_url'] = $scripturl . '?action=profile;save;area=activateaccount;u=' . $memID . ';' . $context['session_var'] . '=' . $context['session_id'] . ';' . $context['profile-aa' . $memID . '_token_var'] . '=' . $context['profile-aa' . $memID . '_token']; } // Is the signature even enabled on this forum? $context['signature_enabled'] = substr($modSettings['signature_settings'], 0, 1) == 1; // How about, are they banned? if (allowedTo('moderate_forum')) { require_once SUBSDIR . '/Bans.subs.php'; $hostname = !empty($context['member']['hostname']) ? $context['member']['hostname'] : ''; $email = !empty($context['member']['email']) ? $context['member']['email'] : ''; $context['member']['bans'] = BanCheckUser($memID, $hostname, $email); // Can they edit the ban? $context['can_edit_ban'] = allowedTo('manage_bans'); } // Load up the most recent attachments for this user for use in profile views etc. $context['thumbs'] = array(); if (!empty($modSettings['attachmentEnable']) && !empty($settings['attachments_on_summary']) && in_array('attachments', $summary_areas)) { $boardsAllowed = boardsAllowedTo('view_attachments'); if (empty($boardsAllowed)) { $boardsAllowed = array(-1); } $attachments = $this->list_getAttachments(0, $settings['attachments_on_summary'], 'm.poster_time DESC', $boardsAllowed, $memID); // Some generic images for mime types $mime_images_url = $settings['default_images_url'] . '/mime_images/'; $mime_path = $settings['default_theme_dir'] . '/images/mime_images/'; // Load them in to $context for use in the template for ($i = 0, $count = count($attachments); $i < $count; $i++) { $context['thumbs'][$i] = array('url' => $scripturl . '?action=dlattach;topic=' . $attachments[$i]['topic'] . '.0;attach=' . $attachments[$i]['id'], 'img' => '', 'filename' => $attachments[$i]['filename'], 'downloads' => $attachments[$i]['downloads'], 'subject' => $attachments[$i]['subject'], 'id' => $attachments[$i]['id']); // Show a thumbnail image as well? if ($attachments[$i]['is_image'] && !empty($modSettings['attachmentShowImages']) && !empty($modSettings['attachmentThumbnails'])) { if (!empty($attachments[$i]['id_thumb'])) { $context['thumbs'][$i]['img'] = '<img id="thumb_' . $attachments[$i]['id'] . '" src="' . $scripturl . '?action=dlattach;topic=' . $attachments[$i]['topic'] . '.0;attach=' . $attachments[$i]['id_thumb'] . ';image" title="" alt="" />'; } else { // No thumbnail available ... use html instead if (!empty($modSettings['attachmentThumbWidth']) && !empty($modSettings['attachmentThumbHeight'])) { if ($attachments[$i]['width'] > $modSettings['attachmentThumbWidth'] || $attachments[$i]['height'] > $modSettings['attachmentThumbHeight']) { $context['thumbs'][$i]['img'] = '<img id="thumb_' . $attachments[$i]['id'] . '" src="' . $scripturl . '?action=dlattach;topic=' . $attachments[$i]['topic'] . '.0;attach=' . $attachments[$i]['id'] . '" title="" alt="" width="' . $modSettings['attachmentThumbWidth'] . '" height="' . $modSettings['attachmentThumbHeight'] . '" />'; } else { $context['thumbs'][$i]['img'] = '<img id="thumb_' . $attachments[$i]['id'] . '" src="' . $scripturl . '?action=dlattach;topic=' . $attachments[$i]['topic'] . '.0;attach=' . $attachments[$i]['id'] . '" title="" alt="" width="' . $attachments[$i]['width'] . '" height="' . $attachments[$i]['height'] . '" />'; } } } } else { if (!empty($modSettings['attachmentThumbWidth']) && !empty($modSettings['attachmentThumbHeight']) && (128 > $modSettings['attachmentThumbWidth'] || 128 > $modSettings['attachmentThumbHeight'])) { $context['thumbs'][$i]['img'] = '<img src="' . $mime_images_url . (!file_exists($mime_path . $attachments[$i]['fileext'] . '.png') ? 'default' : $attachments[$i]['fileext']) . '.png" title="" alt="" width="' . $modSettings['attachmentThumbWidth'] . '" height="' . $modSettings['attachmentThumbHeight'] . '" />'; } else { $context['thumbs'][$i]['img'] = '<img src="' . $mime_images_url . (!file_exists($mime_path . $attachments[$i]['fileext'] . '.png') ? 'default' : $attachments[$i]['fileext']) . '.png" title="" alt="" />'; } } } } // Would you be mine? Could you be mine? Be my buddy :D if (!empty($modSettings['enable_buddylist']) && $context['user']['is_owner'] && !empty($user_info['buddies']) && in_array('buddies', $summary_areas)) { $context['buddies'] = array(); loadMemberData($user_info['buddies'], false, 'profile'); // Get the info for this buddy foreach ($user_info['buddies'] as $buddy) { loadMemberContext($buddy, true); $context['buddies'][$buddy] = $memberContext[$buddy]; } } // How about thier most recent posts? if (in_array('posts', $summary_areas)) { // Is the load average too high just now, then let them know if (!empty($modSettings['loadavg_show_posts']) && $modSettings['current_load'] >= $modSettings['loadavg_show_posts']) { $context['loadaverage'] = true; } else { // Set up to get the last 10 psots of this member $msgCount = count_user_posts($memID); $range_limit = ''; $maxIndex = 10; $start = (int) $_REQUEST['start']; // If they are a frequent poster, we guess the range to help minimize what the query work if ($msgCount > 1000) { list($min_msg_member, $max_msg_member) = findMinMaxUserMessage($memID); $margin = floor(($max_msg_member - $min_msg_member) * (($start + $modSettings['defaultMaxMessages']) / $msgCount) + 0.1 * ($max_msg_member - $min_msg_member)); $range_limit = 'm.id_msg > ' . ($max_msg_member - $margin); } // Find this user's most recent posts $rows = load_user_posts($memID, 0, $maxIndex, $range_limit); $context['posts'] = array(); foreach ($rows as $row) { // Censor.... censorText($row['body']); censorText($row['subject']); // Do the code. $row['body'] = parse_bbc($row['body'], $row['smileys_enabled'], $row['id_msg']); $preview = strip_tags(strtr($row['body'], array('<br />' => ' '))); $preview = Util::shorten_text($preview, !empty($modSettings['ssi_preview_length']) ? $modSettings['ssi_preview_length'] : 128); $short_subject = Util::shorten_text($row['subject'], !empty($modSettings['ssi_subject_length']) ? $modSettings['ssi_subject_length'] : 24); // And the array... $context['posts'][] = array('body' => $preview, 'board' => array('name' => $row['bname'], 'link' => '<a href="' . $scripturl . '?board=' . $row['id_board'] . '.0">' . $row['bname'] . '</a>'), 'subject' => $row['subject'], 'short_subject' => $short_subject, 'time' => standardTime($row['poster_time']), 'html_time' => htmlTime($row['poster_time']), 'timestamp' => forum_time(true, $row['poster_time']), 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'] . '" rel="nofollow">' . $short_subject . '</a>'); } } } // How about the most recent topics that they started? if (in_array('topics', $summary_areas)) { // Is the load average still too high? if (!empty($modSettings['loadavg_show_posts']) && $modSettings['current_load'] >= $modSettings['loadavg_show_posts']) { $context['loadaverage'] = true; } else { // Set up to get the last 10 topics of this member $topicCount = count_user_topics($memID); $range_limit = ''; $maxIndex = 10; // If they are a frequent topic starter we guess the range to help the query if ($topicCount > 1000) { list($min_topic_member, $max_topic_member) = findMinMaxUserTopic($memID); $margin = floor(($max_topic_member - $min_topic_member) * (($start + $modSettings['defaultMaxMessages']) / $topicCount) + 0.1 * ($max_topic_member - $min_topic_member)); $margin *= 5; $range_limit = 't.id_first_msg > ' . ($max_topic_member - $margin); } // Find this user's most recent topics $rows = load_user_topics($memID, 0, $maxIndex, $range_limit); $context['topics'] = array(); foreach ($rows as $row) { // Censor.... censorText($row['body']); censorText($row['subject']); // Do the code. $short_subject = Util::shorten_text($row['subject'], !empty($modSettings['ssi_subject_length']) ? $modSettings['ssi_subject_length'] : 24); // And the array... $context['topics'][] = array('board' => array('name' => $row['bname'], 'link' => '<a href="' . $scripturl . '?board=' . $row['id_board'] . '.0">' . $row['bname'] . '</a>'), 'subject' => $row['subject'], 'short_subject' => $short_subject, 'time' => standardTime($row['poster_time']), 'html_time' => htmlTime($row['poster_time']), 'timestamp' => forum_time(true, $row['poster_time']), 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'] . '" rel="nofollow">' . $short_subject . '</a>'); } } } // To finish this off, custom profile fields. require_once SUBSDIR . '/Profile.subs.php'; loadCustomFields($memID); // To make tabs work, we need jQueryUI $modSettings['jquery_include_ui'] = true; addInlineJavascript(' $(function() {$( "#tabs" ).tabs();});', true); }
/** * RSS Block, Displays rss feed in a block. * * @param mixed[] $parameters * 'url' => url of the feed * 'show_title' => Show the feed title * 'show_content' => Show the content of the feed * 'show_date' => Show the date of the feed item * 'strip_preserve' => preserve tags * 'count' => number of items to show * 'limit' => number of characters of content to show * @param int $id - not used in this block * @param boolean $return_parameters if true returns the configuration options for the block */ function sp_rssFeed($parameters, $id, $return_parameters = false) { global $txt; $block_parameters = array('url' => 'text', 'show_title' => 'check', 'show_content' => 'check', 'show_date' => 'check', 'strip_preserve' => 'text', 'count' => 'int', 'limit' => 'int'); if ($return_parameters) { return $block_parameters; } $feed = !empty($parameters['url']) ? un_htmlspecialchars($parameters['url']) : ''; $show_title = !empty($parameters['show_title']); $show_content = !empty($parameters['show_content']); $show_date = !empty($parameters['show_date']); $strip_preserve = !empty($parameters['strip_preserve']) ? $parameters['strip_preserve'] : 'br'; $strip_preserve = preg_match_all('~[A-Za-z0-9]+~', $strip_preserve, $match) ? $match[0] : array(); $count = !empty($parameters['count']) ? (int) $parameters['count'] : 5; $limit = !empty($parameters['limit']) ? (int) $parameters['limit'] : 0; // Need a feed name to load it if (empty($feed)) { echo ' ', $txt['error_sp_invalid_feed']; return; } $rss = array(); require_once SUBSDIR . '/Package.subs.php'; $data = fetch_web_data($feed); $data_save = $data; // Convert it to UTF8 if we can and its not already preg_match('~encoding="([^"]*)"~', $data, $charset); if (!empty($charset[1]) && $charset != 'UTF-8') { // Use iconv if its available if (function_exists('iconv')) { $data = @iconv($charset[1], 'UTF-8' . '//TRANSLIT//IGNORE', $data); } // No iconv or a false response from it if (!function_exists('iconv') || $data == false) { // PHP (some 5.4 versions) mishandles //TRANSLIT//IGNORE and returns false: see https://bugs.php.net/bug.php?id=61484 if ($data == false) { $data = $data_save; } if (function_exists('mb_convert_encoding')) { // Replace unknown characters with a space @ini_set('mbstring.substitute_character', '32'); $data = @mb_convert_encoding($data, 'UTF-8', $charset[1]); } elseif (function_exists('recode_string')) { $data = @recode_string($charset[1] . '..' . 'UTF-8', $data); } } } $data = str_replace(array("\n", "\r", "\t"), '', $data); $data = preg_replace('~<\\!\\[CDATA\\[(.+?)\\]\\]>~eu', '\'#cdata_escape_encode#\' . Util::htmlspecialchars(\'$1\')', $data); // Find all the feed items preg_match_all('~<item>(.+?)</item>~', $data, $items); foreach ($items[1] as $item_id => $item) { if ($item_id === $count) { break; } preg_match_all('~<([A-Za-z]+)>(.+?)</\\1>~', $item, $match); foreach ($match[0] as $tag_id => $dummy) { if (Util::strpos($match[2][$tag_id], '#cdata_escape_encode#') === 0) { $match[2][$tag_id] = stripslashes(un_htmlspecialchars(Util::substr($match[2][$tag_id], 21))); } $rss[$item_id][strtolower($match[1][$tag_id])] = un_htmlspecialchars($match[2][$tag_id]); } } // Nothing, say its invalid if (empty($rss)) { echo ' ', $txt['error_sp_invalid_feed']; return; } // Add all the items to an array $items = array(); foreach ($rss as $item) { $item['title'] = isset($item['title']) ? strip_tags($item['title']) : ''; $item['description'] = isset($item['description']) ? strip_tags($item['description'], empty($strip_preserve) ? '' : '<' . implode('><', $strip_preserve) . '>') : ''; $items[] = array('title' => $item['title'], 'href' => $item['link'], 'link' => $item['title'] == '' ? '' : ($item['link'] == '' ? $item['title'] : '<a href="' . $item['link'] . '" target="_blank" class="new_win">' . $item['title'] . '</a>'), 'content' => $limit > 0 ? Util::shorten_text($item['description'], $limit, true) : $item['description'], 'date' => !empty($item['pubdate']) ? standardTime(strtotime($item['pubdate']), '%d %B') : ''); } // No items in the feed if (empty($items)) { echo ' ', $txt['error_sp_invalid_feed']; return; } else { $items[count($items) - 1]['is_last'] = true; } if ($show_content) { echo ' <div class="sp_rss_flow"> <ul class="sp_list">'; foreach ($items as $item) { if ($show_title && !empty($item['link'])) { echo ' <li ', sp_embed_class('post', '', 'sp_list_top'), '><strong>', $item['link'], '</strong>', $show_date && !empty($item['date']) ? ' - ' . $item['date'] : '', '</li>'; } echo ' <li', empty($item['is_last']) ? ' class="sp_list_divider"' : '', '>', $item['content'], '</li>'; } echo ' </ul> </div>'; } else { echo ' <ul class="sp_list">'; foreach ($items as $item) { echo ' <li ', sp_embed_class('dot_feed'), '> ', $item['link'], $show_date && !empty($item['date']) ? ' - ' . $item['date'] : '', '</li>'; } echo ' </ul>'; } }
/** * Send out a daily email of all subscribed topics, to members. * * - It sends notifications about replies or new topics, * and moderation actions. */ public function daily_digest() { global $is_weekly, $txt, $mbname, $scripturl, $modSettings, $boardurl; $db = database(); // We'll want this... require_once SUBSDIR . '/Mail.subs.php'; loadEssentialThemeData(); // If the maillist function is on then so is the enhanced digest $maillist = !empty($modSettings['maillist_enabled']) && !empty($modSettings['maillist_digest_enabled']); if ($maillist) { require_once SUBSDIR . '/Emailpost.subs.php'; } $is_weekly = !empty($is_weekly) ? 1 : 0; // Right - get all the notification data FIRST. $request = $db->query('', ' SELECT ln.id_topic, COALESCE(t.id_board, ln.id_board) AS id_board, mem.email_address, mem.member_name, mem.real_name, mem.notify_types, mem.lngfile, mem.id_member FROM {db_prefix}log_notify AS ln INNER JOIN {db_prefix}members AS mem ON (mem.id_member = ln.id_member) LEFT JOIN {db_prefix}topics AS t ON (ln.id_topic != {int:empty_topic} AND t.id_topic = ln.id_topic) WHERE mem.notify_regularity = {int:notify_regularity} AND mem.is_activated = {int:is_activated}', array('empty_topic' => 0, 'notify_regularity' => $is_weekly ? '3' : '2', 'is_activated' => 1)); $members = array(); $langs = array(); $notify = array(); $boards = array(); while ($row = $db->fetch_assoc($request)) { if (!isset($members[$row['id_member']])) { $members[$row['id_member']] = array('email' => $row['email_address'], 'name' => $row['real_name'] == '' ? $row['member_name'] : un_htmlspecialchars($row['real_name']), 'id' => $row['id_member'], 'notifyMod' => $row['notify_types'] < 3 ? true : false, 'lang' => $row['lngfile']); $langs[$row['lngfile']] = $row['lngfile']; } // Store this useful data! $boards[$row['id_board']] = $row['id_board']; if ($row['id_topic']) { $notify['topics'][$row['id_topic']][] = $row['id_member']; } else { $notify['boards'][$row['id_board']][] = $row['id_member']; } } $db->free_result($request); if (empty($boards)) { return true; } // Just get the board names. require_once SUBSDIR . '/Boards.subs.php'; $boards = fetchBoardsInfo(array('boards' => $boards), array('override_permissions' => true)); if (empty($boards)) { return true; } // Get the actual topics... $request = $db->query('', ' SELECT ld.note_type, t.id_topic, t.id_board, t.id_member_started, m.id_msg, m.subject, m.body, ld.id_msg AS last_reply, b.name AS board_name, ml.body as last_body FROM {db_prefix}log_digest AS ld INNER JOIN {db_prefix}topics AS t ON (t.id_topic = ld.id_topic AND t.id_board IN ({array_int:board_list})) INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg) INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = ld.id_msg) INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) WHERE ' . ($is_weekly ? 'ld.daily != {int:daily_value}' : 'ld.daily IN (0, 2)'), array('board_list' => array_keys($boards), 'daily_value' => 2)); $types = array(); while ($row = $db->fetch_assoc($request)) { if (!isset($types[$row['note_type']][$row['id_board']])) { $types[$row['note_type']][$row['id_board']] = array('lines' => array(), 'name' => un_htmlspecialchars($row['board_name']), 'id' => $row['id_board']); } // A reply has been made if ($row['note_type'] === 'reply') { // More than one reply to this topic? if (isset($types[$row['note_type']][$row['id_board']]['lines'][$row['id_topic']])) { $types[$row['note_type']][$row['id_board']]['lines'][$row['id_topic']]['count']++; // keep track of the highest numbered reply and body text for this topic ... if ($types[$row['note_type']][$row['id_board']]['lines'][$row['id_topic']]['body_id'] < $row['last_reply']) { $types[$row['note_type']][$row['id_board']]['lines'][$row['id_topic']]['body_id'] = $row['last_reply']; $types[$row['note_type']][$row['id_board']]['lines'][$row['id_topic']]['body_text'] = $row['last_body']; } } else { // First time we have seen a reply to this topic, so load our array $types[$row['note_type']][$row['id_board']]['lines'][$row['id_topic']] = array('id' => $row['id_topic'], 'subject' => un_htmlspecialchars($row['subject']), 'link' => $scripturl . '?topic=' . $row['id_topic'] . '.new;topicseen#new', 'count' => 1, 'body_id' => $row['last_reply'], 'body_text' => $row['last_body']); } } elseif ($row['note_type'] === 'topic') { if ($maillist) { // Convert to markdown markup e.g. text ;) pbe_prepare_text($row['body']); $row['body'] = Util::shorten_text($row['body'], !empty($modSettings['digest_preview_length']) ? $modSettings['digest_preview_length'] : 375, true); $row['body'] = preg_replace("~\n~s", "\n ", $row['body']); } // Topics are simple since we are only concerned with the first post if (!isset($types[$row['note_type']][$row['id_board']]['lines'][$row['id_topic']])) { $types[$row['note_type']][$row['id_board']]['lines'][$row['id_topic']] = array('id' => $row['id_topic'], 'link' => $scripturl . '?topic=' . $row['id_topic'] . '.new;topicseen#new', 'subject' => un_htmlspecialchars($row['subject']), 'body' => $row['body']); } } elseif ($maillist && empty($modSettings['pbe_no_mod_notices'])) { if (!isset($types[$row['note_type']][$row['id_board']]['lines'][$row['id_topic']])) { $types[$row['note_type']][$row['id_board']]['lines'][$row['id_topic']] = array('id' => $row['id_topic'], 'subject' => un_htmlspecialchars($row['subject']), 'starter' => $row['id_member_started']); } } $types[$row['note_type']][$row['id_board']]['lines'][$row['id_topic']]['members'] = array(); if (!empty($notify['topics'][$row['id_topic']])) { $types[$row['note_type']][$row['id_board']]['lines'][$row['id_topic']]['members'] = array_merge($types[$row['note_type']][$row['id_board']]['lines'][$row['id_topic']]['members'], $notify['topics'][$row['id_topic']]); } if (!empty($notify['boards'][$row['id_board']])) { $types[$row['note_type']][$row['id_board']]['lines'][$row['id_topic']]['members'] = array_merge($types[$row['note_type']][$row['id_board']]['lines'][$row['id_topic']]['members'], $notify['boards'][$row['id_board']]); } } $db->free_result($request); if (empty($types)) { return true; } // Fix the last reply message so its suitable for previewing if ($maillist) { foreach ($types['reply'] as $id => $board) { foreach ($board['lines'] as $topic) { // Replace the body array with the appropriate preview message $body = $types['reply'][$id]['lines'][$topic['id']]['body_text']; pbe_prepare_text($body); $body = Util::shorten_text($body, !empty($modSettings['digest_preview_length']) ? $modSettings['digest_preview_length'] : 375, true); $body = preg_replace("~\n~s", "\n ", $body); $types['reply'][$id]['lines'][$topic['id']]['body'] = $body; unset($types['reply'][$id]['lines'][$topic['id']]['body_text'], $body); } } } // Let's load all the languages into a cache thingy. $langtxt = array(); foreach ($langs as $lang) { loadLanguage('Post', $lang); loadLanguage('index', $lang); loadLanguage('Maillist', $lang); loadLanguage('EmailTemplates', $lang); $langtxt[$lang] = array('subject' => $txt['digest_subject_' . ($is_weekly ? 'weekly' : 'daily')], 'char_set' => 'UTF-8', 'intro' => sprintf($txt['digest_intro_' . ($is_weekly ? 'weekly' : 'daily')], $mbname), 'new_topics' => $txt['digest_new_topics'], 'topic_lines' => $txt['digest_new_topics_line'], 'new_replies' => $txt['digest_new_replies'], 'mod_actions' => $txt['digest_mod_actions'], 'replies_one' => $txt['digest_new_replies_one'], 'replies_many' => $txt['digest_new_replies_many'], 'sticky' => $txt['digest_mod_act_sticky'], 'lock' => $txt['digest_mod_act_lock'], 'unlock' => $txt['digest_mod_act_unlock'], 'remove' => $txt['digest_mod_act_remove'], 'move' => $txt['digest_mod_act_move'], 'merge' => $txt['digest_mod_act_merge'], 'split' => $txt['digest_mod_act_split'], 'bye' => (!empty($modSettings['maillist_sitename_regards']) ? $modSettings['maillist_sitename_regards'] : '') . "\n" . $boardurl, 'preview' => $txt['digest_preview'], 'see_full' => $txt['digest_see_full'], 'reply_preview' => $txt['digest_reply_preview'], 'unread_reply_link' => $txt['digest_unread_reply_link']); } // Right - send out the silly things - this will take quite some space! foreach ($members as $mid => $member) { // Do the start stuff! $email = array('subject' => $mbname . ' - ' . $langtxt[$lang]['subject'], 'body' => $member['name'] . ',' . "\n\n" . $langtxt[$lang]['intro'] . "\n" . $scripturl . '?action=profile;area=notification;u=' . $member['id'] . "\n", 'email' => $member['email']); // All the new topics if (isset($types['topic'])) { $titled = false; // Each type contains a board ID and then a topic number foreach ($types['topic'] as $id => $board) { foreach ($board['lines'] as $topic) { // They have requested notification for new topics in this board if (in_array($mid, $topic['members'])) { // Start of the new topics with a heading bar if (!$titled) { $email['body'] .= "\n" . $langtxt[$lang]['new_topics'] . ':' . "\n" . str_repeat('-', 78); $titled = true; } $email['body'] .= "\n" . sprintf($langtxt[$lang]['topic_lines'], $topic['subject'], $board['name']); if ($maillist) { $email['body'] .= $langtxt[$lang]['preview'] . $topic['body'] . $langtxt[$lang]['see_full'] . $topic['link'] . "\n"; } } } } if ($titled) { $email['body'] .= "\n"; } } // What about replies? if (isset($types['reply'])) { $titled = false; // Each reply will have a board id and then a topic ID foreach ($types['reply'] as $id => $board) { foreach ($board['lines'] as $topic) { // This member wants notices on replys to this topic if (in_array($mid, $topic['members'])) { // First one in the section gets a nice heading if (!$titled) { $email['body'] .= "\n" . $langtxt[$lang]['new_replies'] . ':' . "\n" . str_repeat('-', 78); $titled = true; } $email['body'] .= "\n" . ($topic['count'] === 1 ? sprintf($langtxt[$lang]['replies_one'], $topic['subject']) : sprintf($langtxt[$lang]['replies_many'], $topic['count'], $topic['subject'])); if ($maillist) { $email['body'] .= $langtxt[$lang]['reply_preview'] . $topic['body'] . $langtxt[$lang]['unread_reply_link'] . $topic['link'] . "\n"; } } } } if ($titled) { $email['body'] .= "\n"; } } // Finally, moderation actions! $titled = false; foreach ($types as $note_type => $type) { if ($note_type === 'topic' || $note_type === 'reply') { continue; } foreach ($type as $id => $board) { foreach ($board['lines'] as $topic) { if (in_array($mid, $topic['members'])) { if (!$titled) { $email['body'] .= "\n" . $langtxt[$lang]['mod_actions'] . ':' . "\n" . str_repeat('-', 47); $titled = true; } $email['body'] .= "\n" . sprintf($langtxt[$lang][$note_type], $topic['subject']); } } } } if ($titled) { $email['body'] .= "\n"; } // Then just say our goodbyes! $email['body'] .= "\n\n" . $langtxt[$lang]['bye']; // Send it - low priority! sendmail($email['email'], $email['subject'], $email['body'], null, null, false, 4); } // Using the queue, do a final flush before we say thats all folks if (!empty($modSettings['mail_queue'])) { AddMailQueue(true); } // Clean up... if ($is_weekly) { $db->query('', ' DELETE FROM {db_prefix}log_digest WHERE daily != {int:not_daily}', array('not_daily' => 0)); $db->query('', ' UPDATE {db_prefix}log_digest SET daily = {int:daily_value} WHERE daily = {int:not_daily}', array('daily_value' => 2, 'not_daily' => 0)); } else { // Clear any only weekly ones, and stop us from sending daily again. $db->query('', ' DELETE FROM {db_prefix}log_digest WHERE daily = {int:daily_value}', array('daily_value' => 2)); $db->query('', ' UPDATE {db_prefix}log_digest SET daily = {int:both_value} WHERE daily = {int:no_value}', array('both_value' => 1, 'no_value' => 0)); } // Just in case the member changes their settings mark this as sent. $members = array_keys($members); $db->query('', ' UPDATE {db_prefix}log_notify SET sent = {int:is_sent} WHERE id_member IN ({array_int:member_list})', array('member_list' => $members, 'is_sent' => 1)); // Log we've done it... return true; }
/** * Get the recent topics to display. * The returned array will be generated to match the xml_format. * * @param string $xml_format one of rss, rss2, rdf, atom * @return mixed[] of recent posts */ public function action_xmlrecent($xml_format) { global $scripturl, $modSettings, $board; // Get the latest news require_once SUBSDIR . '/News.subs.php'; $results = getXMLRecent($this->_query_this_board, $board, $this->_limit); // Loop on the results and prepare them in the format requested $data = array(); foreach ($results as $row) { // Limit the length of the message, if the option is set. if (!empty($modSettings['xmlnews_maxlen']) && Util::strlen(str_replace('<br />', "\n", $row['body'])) > $modSettings['xmlnews_maxlen']) { $row['body'] = strtr(Util::shorten_text(str_replace('<br />', "\n", $row['body']), $modSettings['xmlnews_maxlen'], true), array("\n" => '<br />')); } $row['body'] = parse_bbc($row['body'], $row['smileys_enabled'], $row['id_msg']); // You can't say that censorText($row['body']); censorText($row['subject']); // Doesn't work as well as news, but it kinda does.. if ($xml_format == 'rss' || $xml_format == 'rss2') { $data[] = array('title' => $row['subject'], 'link' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'], 'description' => cdata_parse(strtr(un_htmlspecialchars($row['body']), '&', '&')), 'author' => in_array(showEmailAddress(!empty($row['hide_email']), $row['id_member']), array('yes', 'yes_permission_override')) ? $row['poster_email'] . ' (' . un_htmlspecialchars($row['poster_name']) . ')' : '<![CDATA[none@noreply.net (' . un_htmlspecialchars($row['poster_name']) . ')]]>', 'category' => cdata_parse($row['bname']), 'comments' => $scripturl . '?action=post;topic=' . $row['id_topic'] . '.0', 'pubDate' => gmdate('D, d M Y H:i:s \\G\\M\\T', $row['poster_time']), 'guid' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg']); // Add the poster name on if we are rss2 if ($xml_format == 'rss2') { $data[count($data) - 1]['dc:creator'] = $row['poster_name']; unset($data[count($data) - 1]['author']); } } elseif ($xml_format == 'rdf') { $data[] = array('title' => $row['subject'], 'link' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'], 'description' => cdata_parse($row['body'])); } elseif ($xml_format == 'atom') { $data[] = array('title' => $row['subject'], 'link' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'], 'summary' => cdata_parse($row['body']), 'category' => $row['bname'], 'author' => array('name' => $row['poster_name'], 'email' => in_array(showEmailAddress(!empty($row['hide_email']), $row['id_member']), array('yes', 'yes_permission_override')) ? $row['poster_email'] : null, 'uri' => !empty($row['id_member']) ? $scripturl . '?action=profile;u=' . $row['id_member'] : ''), 'published' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', $row['poster_time']), 'updated' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', empty($row['modified_time']) ? $row['poster_time'] : $row['modified_time']), 'id' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg']); } else { $data[] = array('time' => htmlspecialchars(strip_tags(standardTime($row['poster_time'])), ENT_COMPAT, 'UTF-8'), 'id' => $row['id_msg'], 'subject' => cdata_parse($row['subject']), 'body' => cdata_parse($row['body']), 'starter' => array('name' => cdata_parse($row['first_poster_name']), 'id' => $row['id_first_member'], 'link' => !empty($row['id_first_member']) ? $scripturl . '?action=profile;u=' . $row['id_first_member'] : ''), 'poster' => array('name' => cdata_parse($row['poster_name']), 'id' => $row['id_member'], 'link' => !empty($row['id_member']) ? $scripturl . '?action=profile;u=' . $row['id_member'] : ''), 'topic' => array('subject' => cdata_parse($row['first_subject']), 'id' => $row['id_topic'], 'link' => $scripturl . '?topic=' . $row['id_topic'] . '.new#new'), 'board' => array('name' => cdata_parse($row['bname']), 'id' => $row['id_board'], 'link' => $scripturl . '?board=' . $row['id_board'] . '.0'), 'link' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg']); } } return $data; }
/** * Loads in a group of post drafts for the user. * Loads a specific draft for current use in the postbox if selected. * Used in the posting screens to allow draft selection * Will load a draft if selected is supplied via post * * @param int $member_id * @param int|false $id_topic if set, load drafts for the specified topic * @return false|null */ private function _prepareDraftsContext($member_id, $id_topic = false) { global $scripturl, $context, $txt, $modSettings; $context['drafts'] = array(); // Need a member if (empty($member_id)) { return false; } // We haz drafts loadLanguage('Drafts'); require_once SUBSDIR . '/Drafts.subs.php'; // has a specific draft has been selected? Load it up if there is not already a message already in the editor if (isset($_REQUEST['id_draft']) && empty($_POST['subject']) && empty($_POST['message'])) { loadDraft((int) $_REQUEST['id_draft'], 0, true, true); } // load all the drafts for this user that meet the criteria $order = 'poster_time DESC'; $user_drafts = load_user_drafts($member_id, 0, $id_topic, $order); // Add them to the context draft array for template display foreach ($user_drafts as $draft) { $short_subject = empty($draft['subject']) ? $txt['drafts_none'] : Util::shorten_text(stripslashes($draft['subject']), !empty($modSettings['draft_subject_length']) ? $modSettings['draft_subject_length'] : 24); $context['drafts'][] = array('subject' => censorText($short_subject), 'poster_time' => standardTime($draft['poster_time']), 'link' => '<a href="' . $scripturl . '?action=post;board=' . $draft['id_board'] . ';' . (!empty($draft['id_topic']) ? 'topic=' . $draft['id_topic'] . '.0;' : '') . 'id_draft=' . $draft['id_draft'] . '">' . (!empty($draft['subject']) ? $draft['subject'] : $txt['drafts_none']) . '</a>'); } }
/** * Show the list of topics in this board, along with any sub-boards. * @uses MessageIndex template topic_listing sub template */ public function action_messageindex() { global $txt, $scripturl, $board, $modSettings, $context; global $options, $settings, $board_info, $user_info; // Fairly often, we'll work with boards. Current board, sub-boards. require_once SUBSDIR . '/Boards.subs.php'; // If this is a redirection board head off. if ($board_info['redirect']) { incrementBoard($board, 'num_posts'); redirectexit($board_info['redirect']); } loadTemplate('MessageIndex'); loadJavascriptFile('topic.js'); $context['name'] = $board_info['name']; $context['sub_template'] = 'topic_listing'; $context['description'] = $board_info['description']; $template_layers = Template_Layers::getInstance(); // How many topics do we have in total? $board_info['total_topics'] = allowedTo('approve_posts') ? $board_info['num_topics'] + $board_info['unapproved_topics'] : $board_info['num_topics'] + $board_info['unapproved_user_topics']; // View all the topics, or just a few? $context['topics_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['topics_per_page']) ? $options['topics_per_page'] : $modSettings['defaultMaxTopics']; $context['messages_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['messages_per_page']) ? $options['messages_per_page'] : $modSettings['defaultMaxMessages']; $maxindex = isset($_REQUEST['all']) && !empty($modSettings['enableAllMessages']) ? $board_info['total_topics'] : $context['topics_per_page']; // Right, let's only index normal stuff! if (count($_GET) > 1) { $session_name = session_name(); foreach ($_GET as $k => $v) { if (!in_array($k, array('board', 'start', $session_name))) { $context['robot_no_index'] = true; } } } if (!empty($_REQUEST['start']) && (!is_numeric($_REQUEST['start']) || $_REQUEST['start'] % $context['messages_per_page'] != 0)) { $context['robot_no_index'] = true; } // If we can view unapproved messages and there are some build up a list. if (allowedTo('approve_posts') && ($board_info['unapproved_topics'] || $board_info['unapproved_posts'])) { $untopics = $board_info['unapproved_topics'] ? '<a href="' . $scripturl . '?action=moderate;area=postmod;sa=topics;brd=' . $board . '">' . $board_info['unapproved_topics'] . '</a>' : 0; $unposts = $board_info['unapproved_posts'] ? '<a href="' . $scripturl . '?action=moderate;area=postmod;sa=posts;brd=' . $board . '">' . ($board_info['unapproved_posts'] - $board_info['unapproved_topics']) . '</a>' : 0; $context['unapproved_posts_message'] = sprintf($txt['there_are_unapproved_topics'], $untopics, $unposts, $scripturl . '?action=moderate;area=postmod;sa=' . ($board_info['unapproved_topics'] ? 'topics' : 'posts') . ';brd=' . $board); } // We only know these. if (isset($_REQUEST['sort']) && !in_array($_REQUEST['sort'], array('subject', 'starter', 'last_poster', 'replies', 'views', 'likes', 'first_post', 'last_post'))) { $_REQUEST['sort'] = 'last_post'; } // Make sure the starting place makes sense and construct the page index. if (isset($_REQUEST['sort'])) { $sort_string = ';sort=' . $_REQUEST['sort'] . (isset($_REQUEST['desc']) ? ';desc' : ''); } else { $sort_string = ''; } $context['page_index'] = constructPageIndex($scripturl . '?board=' . $board . '.%1$d' . $sort_string, $_REQUEST['start'], $board_info['total_topics'], $maxindex, true); $context['start'] =& $_REQUEST['start']; // Set a canonical URL for this page. $context['canonical_url'] = $scripturl . '?board=' . $board . '.' . $context['start']; $context['links'] += array('prev' => $_REQUEST['start'] >= $context['topics_per_page'] ? $scripturl . '?board=' . $board . '.' . ($_REQUEST['start'] - $context['topics_per_page']) : '', 'next' => $_REQUEST['start'] + $context['topics_per_page'] < $board_info['total_topics'] ? $scripturl . '?board=' . $board . '.' . ($_REQUEST['start'] + $context['topics_per_page']) : ''); $context['page_info'] = array('current_page' => $_REQUEST['start'] / $context['topics_per_page'] + 1, 'num_pages' => floor(($board_info['total_topics'] - 1) / $context['topics_per_page']) + 1); if (isset($_REQUEST['all']) && !empty($modSettings['enableAllMessages']) && $maxindex > $modSettings['enableAllMessages']) { $maxindex = $modSettings['enableAllMessages']; $_REQUEST['start'] = 0; } // Build a list of the board's moderators. $context['moderators'] =& $board_info['moderators']; $context['link_moderators'] = array(); if (!empty($board_info['moderators'])) { foreach ($board_info['moderators'] as $mod) { $context['link_moderators'][] = '<a href="' . $scripturl . '?action=profile;u=' . $mod['id'] . '" title="' . $txt['board_moderator'] . '">' . $mod['name'] . '</a>'; } } // Mark current and parent boards as seen. if (!$user_info['is_guest']) { // We can't know they read it if we allow prefetches. if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') { @ob_end_clean(); header('HTTP/1.1 403 Prefetch Forbidden'); die; } // Mark the board as read, and its parents. if (!empty($board_info['parent_boards'])) { $board_list = array_keys($board_info['parent_boards']); $board_list[] = $board; } else { $board_list = array($board); } // Mark boards as read. Boards alone, no need for topics. markBoardsRead($board_list, false, false); // Clear topicseen cache if (!empty($board_info['parent_boards'])) { // We've seen all these boards now! foreach ($board_info['parent_boards'] as $k => $dummy) { if (isset($_SESSION['topicseen_cache'][$k])) { unset($_SESSION['topicseen_cache'][$k]); } } } if (isset($_SESSION['topicseen_cache'][$board])) { unset($_SESSION['topicseen_cache'][$board]); } // From now on, they've seen it. So we reset notifications. $context['is_marked_notify'] = resetSentBoardNotification($user_info['id'], $board); } else { $context['is_marked_notify'] = false; } // 'Print' the header and board info. $context['page_title'] = strip_tags($board_info['name']); // Set the variables up for the template. $context['can_mark_notify'] = allowedTo('mark_notify') && !$user_info['is_guest']; $context['can_post_new'] = allowedTo('post_new') || $modSettings['postmod_active'] && allowedTo('post_unapproved_topics'); $context['can_post_poll'] = !empty($modSettings['pollMode']) && allowedTo('poll_post') && $context['can_post_new']; $context['can_moderate_forum'] = allowedTo('moderate_forum'); $context['can_approve_posts'] = allowedTo('approve_posts'); // Prepare sub-boards for display. require_once SUBSDIR . '/BoardsList.class.php'; $boardIndexOptions = array('include_categories' => false, 'base_level' => $board_info['child_level'] + 1, 'parent_id' => $board_info['id'], 'set_latest_post' => false, 'countChildPosts' => !empty($modSettings['countChildPosts'])); $boardlist = new Boards_List($boardIndexOptions); $context['boards'] = $boardlist->getBoards(); // Nosey, nosey - who's viewing this board? if (!empty($settings['display_who_viewing'])) { require_once SUBSDIR . '/Who.subs.php'; formatViewers($board, 'board'); } // And now, what we're here for: topics! require_once SUBSDIR . '/MessageIndex.subs.php'; // Known sort methods. $sort_methods = messageIndexSort(); // They didn't pick one, default to by last post descending. if (!isset($_REQUEST['sort']) || !isset($sort_methods[$_REQUEST['sort']])) { $context['sort_by'] = 'last_post'; $ascending = isset($_REQUEST['asc']); } else { $context['sort_by'] = $_REQUEST['sort']; $ascending = !isset($_REQUEST['desc']); } $sort_column = $sort_methods[$context['sort_by']]; $context['sort_direction'] = $ascending ? 'up' : 'down'; $context['sort_title'] = $ascending ? $txt['sort_desc'] : $txt['sort_asc']; // Trick $txt['starter'] = $txt['started_by']; foreach ($sort_methods as $key => $val) { $context['topics_headers'][$key] = array('url' => $scripturl . '?board=' . $context['current_board'] . '.' . $context['start'] . ';sort=' . $key . ($context['sort_by'] == $key && $context['sort_direction'] == 'up' ? ';desc' : ''), 'sort_dir_img' => $context['sort_by'] == $key ? '<img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" title="' . $context['sort_title'] . '" />' : ''); } // Calculate the fastest way to get the topics. $start = (int) $_REQUEST['start']; if ($start > ($board_info['total_topics'] - 1) / 2) { $ascending = !$ascending; $fake_ascending = true; $maxindex = $board_info['total_topics'] < $start + $maxindex + 1 ? $board_info['total_topics'] - $start : $maxindex; $start = $board_info['total_topics'] < $start + $maxindex + 1 ? 0 : $board_info['total_topics'] - $start - $maxindex; } else { $fake_ascending = false; } // Setup the default topic icons... $context['icon_sources'] = MessageTopicIcons(); $topic_ids = array(); $context['topics'] = array(); // Set up the query options $indexOptions = array('include_sticky' => !empty($modSettings['enableStickyTopics']), 'only_approved' => $modSettings['postmod_active'] && !allowedTo('approve_posts'), 'previews' => !empty($modSettings['message_index_preview']) ? empty($modSettings['preview_characters']) ? -1 : $modSettings['preview_characters'] : 0, 'include_avatars' => !empty($settings['avatars_on_indexes']), 'ascending' => $ascending, 'fake_ascending' => $fake_ascending); // Allow integration to modify / add to the $indexOptions call_integration_hook('integrate_messageindex_topics', array(&$sort_column, &$indexOptions)); $topics_info = messageIndexTopics($board, $user_info['id'], $start, $maxindex, $context['sort_by'], $sort_column, $indexOptions); // Prepare for links to guests (for search engines) $context['pageindex_multiplier'] = empty($modSettings['disableCustomPerPage']) && !empty($options['messages_per_page']) ? $options['messages_per_page'] : $modSettings['defaultMaxMessages']; // Begin 'printing' the message index for current board. foreach ($topics_info as $row) { $topic_ids[] = $row['id_topic']; // Do they want message previews? if (!empty($modSettings['message_index_preview'])) { // Limit them to $modSettings['preview_characters'] characters $row['first_body'] = strip_tags(strtr(parse_bbc($row['first_body'], false, $row['id_first_msg']), array('<br />' => "\n", ' ' => ' '))); $row['first_body'] = Util::shorten_text($row['first_body'], !empty($modSettings['preview_characters']) ? $modSettings['preview_characters'] : 128, true); // No reply then they are the same, no need to process it again if ($row['num_replies'] == 0) { $row['last_body'] == $row['first_body']; } else { $row['last_body'] = strip_tags(strtr(parse_bbc($row['last_body'], false, $row['id_last_msg']), array('<br />' => "\n", ' ' => ' '))); $row['last_body'] = Util::shorten_text($row['last_body'], !empty($modSettings['preview_characters']) ? $modSettings['preview_characters'] : 128, true); } // Censor the subject and message preview. censorText($row['first_subject']); censorText($row['first_body']); // Don't censor them twice! if ($row['id_first_msg'] == $row['id_last_msg']) { $row['last_subject'] = $row['first_subject']; $row['last_body'] = $row['first_body']; } else { censorText($row['last_subject']); censorText($row['last_body']); } } else { $row['first_body'] = ''; $row['last_body'] = ''; censorText($row['first_subject']); if ($row['id_first_msg'] == $row['id_last_msg']) { $row['last_subject'] = $row['first_subject']; } else { censorText($row['last_subject']); } } // Decide how many pages the topic should have. if ($row['num_replies'] + 1 > $context['messages_per_page']) { // We can't pass start by reference. $start = -1; $pages = constructPageIndex($scripturl . '?topic=' . $row['id_topic'] . '.%1$d', $start, $row['num_replies'] + 1, $context['messages_per_page'], true, array('prev_next' => false, 'all' => !empty($modSettings['enableAllMessages']) && $row['num_replies'] + 1 < $modSettings['enableAllMessages'])); } else { $pages = ''; } // We need to check the topic icons exist... if (!empty($modSettings['messageIconChecks_enable'])) { if (!isset($context['icon_sources'][$row['first_icon']])) { $context['icon_sources'][$row['first_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['first_icon'] . '.png') ? 'images_url' : 'default_images_url'; } if (!isset($context['icon_sources'][$row['last_icon']])) { $context['icon_sources'][$row['last_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['last_icon'] . '.png') ? 'images_url' : 'default_images_url'; } } else { if (!isset($context['icon_sources'][$row['first_icon']])) { $context['icon_sources'][$row['first_icon']] = 'images_url'; } if (!isset($context['icon_sources'][$row['last_icon']])) { $context['icon_sources'][$row['last_icon']] = 'images_url'; } } // 'Print' the topic info. $context['topics'][$row['id_topic']] = array('id' => $row['id_topic'], 'first_post' => array('id' => $row['id_first_msg'], 'member' => array('username' => $row['first_member_name'], 'name' => $row['first_display_name'], 'id' => $row['first_id_member'], 'href' => !empty($row['first_id_member']) ? $scripturl . '?action=profile;u=' . $row['first_id_member'] : '', 'link' => !empty($row['first_id_member']) ? '<a href="' . $scripturl . '?action=profile;u=' . $row['first_id_member'] . '" title="' . $txt['profile_of'] . ' ' . $row['first_display_name'] . '" class="preview">' . $row['first_display_name'] . '</a>' : $row['first_display_name']), 'time' => standardTime($row['first_poster_time']), 'html_time' => htmlTime($row['first_poster_time']), 'timestamp' => forum_time(true, $row['first_poster_time']), 'subject' => $row['first_subject'], 'preview' => trim($row['first_body']), 'icon' => $row['first_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['first_icon']]] . '/post/' . $row['first_icon'] . '.png', 'href' => $scripturl . '?topic=' . $row['id_topic'] . '.0', 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.0">' . $row['first_subject'] . '</a>'), 'last_post' => array('id' => $row['id_last_msg'], 'member' => array('username' => $row['last_member_name'], 'name' => $row['last_display_name'], 'id' => $row['last_id_member'], 'href' => !empty($row['last_id_member']) ? $scripturl . '?action=profile;u=' . $row['last_id_member'] : '', 'link' => !empty($row['last_id_member']) ? '<a href="' . $scripturl . '?action=profile;u=' . $row['last_id_member'] . '">' . $row['last_display_name'] . '</a>' : $row['last_display_name']), 'time' => standardTime($row['last_poster_time']), 'html_time' => htmlTime($row['last_poster_time']), 'timestamp' => forum_time(true, $row['last_poster_time']), 'subject' => $row['last_subject'], 'preview' => trim($row['last_body']), 'icon' => $row['last_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['last_icon']]] . '/post/' . $row['last_icon'] . '.png', 'href' => $scripturl . '?topic=' . $row['id_topic'] . ($user_info['is_guest'] ? '.' . (int) ($row['num_replies'] / $context['pageindex_multiplier']) * $context['pageindex_multiplier'] . '#msg' . $row['id_last_msg'] : ($row['num_replies'] == 0 ? '.0' : '.msg' . $row['id_last_msg']) . '#new'), 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . ($user_info['is_guest'] ? '.' . (int) ($row['num_replies'] / $context['pageindex_multiplier']) * $context['pageindex_multiplier'] . '#msg' . $row['id_last_msg'] : ($row['num_replies'] == 0 ? '.0' : '.msg' . $row['id_last_msg']) . '#new') . '" ' . ($row['num_replies'] == 0 ? '' : 'rel="nofollow"') . '>' . $row['last_subject'] . '</a>'), 'default_preview' => trim($row[!empty($modSettings['message_index_preview']) && $modSettings['message_index_preview'] == 2 ? 'last_body' : 'first_body']), 'is_sticky' => !empty($modSettings['enableStickyTopics']) && !empty($row['is_sticky']), 'is_locked' => !empty($row['locked']), 'is_poll' => !empty($modSettings['pollMode']) && $row['id_poll'] > 0, 'is_hot' => !empty($modSettings['useLikesNotViews']) ? $row['num_likes'] >= $modSettings['hotTopicPosts'] : $row['num_replies'] >= $modSettings['hotTopicPosts'], 'is_very_hot' => !empty($modSettings['useLikesNotViews']) ? $row['num_likes'] >= $modSettings['hotTopicVeryPosts'] : $row['num_replies'] >= $modSettings['hotTopicVeryPosts'], 'is_posted_in' => false, 'icon' => $row['first_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['first_icon']]] . '/post/' . $row['first_icon'] . '.png', 'subject' => $row['first_subject'], 'new' => $row['new_from'] <= $row['id_msg_modified'], 'new_from' => $row['new_from'], 'newtime' => $row['new_from'], 'new_href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['new_from'] . '#new', 'redir_href' => !empty($row['id_redirect_topic']) ? $scripturl . '?topic=' . $row['id_topic'] . '.0;noredir' : '', 'pages' => $pages, 'replies' => comma_format($row['num_replies']), 'views' => comma_format($row['num_views']), 'likes' => comma_format($row['num_likes']), 'approved' => $row['approved'], 'unapproved_posts' => $row['unapproved_posts']); if (!empty($settings['avatars_on_indexes'])) { $context['topics'][$row['id_topic']]['last_post']['member']['avatar'] = determineAvatar($row); } determineTopicClass($context['topics'][$row['id_topic']]); } // Allow addons to add to the $context['topics'] call_integration_hook('integrate_messageindex_listing', array($topics_info)); // Fix the sequence of topics if they were retrieved in the wrong order. (for speed reasons...) if ($fake_ascending) { $context['topics'] = array_reverse($context['topics'], true); } if (!empty($modSettings['enableParticipation']) && !$user_info['is_guest'] && !empty($topic_ids)) { $topics_participated_in = topicsParticipation($user_info['id'], $topic_ids); foreach ($topics_participated_in as $participated) { $context['topics'][$participated['id_topic']]['is_posted_in'] = true; $context['topics'][$participated['id_topic']]['class'] = 'my_' . $context['topics'][$participated['id_topic']]['class']; } } $context['jump_to'] = array('label' => addslashes(un_htmlspecialchars($txt['jump_to'])), 'board_name' => htmlspecialchars(strtr(strip_tags($board_info['name']), array('&' => '&')), ENT_COMPAT, 'UTF-8'), 'child_level' => $board_info['child_level']); // Is Quick Moderation active/needed? if (!empty($options['display_quick_mod']) && !empty($context['topics'])) { $context['can_markread'] = $context['user']['is_logged']; $context['can_lock'] = allowedTo('lock_any'); $context['can_sticky'] = allowedTo('make_sticky') && !empty($modSettings['enableStickyTopics']); $context['can_move'] = allowedTo('move_any'); $context['can_remove'] = allowedTo('remove_any'); $context['can_merge'] = allowedTo('merge_any'); // Ignore approving own topics as it's unlikely to come up... $context['can_approve'] = $modSettings['postmod_active'] && allowedTo('approve_posts') && !empty($board_info['unapproved_topics']); // Can we restore topics? $context['can_restore'] = allowedTo('move_any') && !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] == $board; // Set permissions for all the topics. foreach ($context['topics'] as $t => $topic) { $started = $topic['first_post']['member']['id'] == $user_info['id']; $context['topics'][$t]['quick_mod'] = array('lock' => allowedTo('lock_any') || $started && allowedTo('lock_own'), 'sticky' => allowedTo('make_sticky') && !empty($modSettings['enableStickyTopics']), 'move' => allowedTo('move_any') || $started && allowedTo('move_own'), 'modify' => allowedTo('modify_any') || $started && allowedTo('modify_own'), 'remove' => allowedTo('remove_any') || $started && allowedTo('remove_own'), 'approve' => $context['can_approve'] && $topic['unapproved_posts']); $context['can_lock'] |= $started && allowedTo('lock_own'); $context['can_move'] |= $started && allowedTo('move_own'); $context['can_remove'] |= $started && allowedTo('remove_own'); } // Can we use quick moderation checkboxes? if ($options['display_quick_mod'] == 1) { $context['can_quick_mod'] = $context['user']['is_logged'] || $context['can_approve'] || $context['can_remove'] || $context['can_lock'] || $context['can_sticky'] || $context['can_move'] || $context['can_merge'] || $context['can_restore']; } else { $context['can_quick_mod'] = $context['can_remove'] || $context['can_lock'] || $context['can_sticky'] || $context['can_move']; } } if (!empty($context['can_quick_mod']) && $options['display_quick_mod'] == 1) { $context['qmod_actions'] = array('approve', 'remove', 'lock', 'sticky', 'move', 'merge', 'restore', 'markread'); call_integration_hook('integrate_quick_mod_actions'); } if (!empty($context['boards']) && $context['start'] == 0) { $template_layers->add('display_child_boards'); } // If there are children, but no topics and no ability to post topics... $context['no_topic_listing'] = !empty($context['boards']) && empty($context['topics']) && !$context['can_post_new']; $template_layers->add('topic_listing'); addJavascriptVar(array('notification_board_notice' => $context['is_marked_notify'] ? $txt['notification_disable_board'] : $txt['notification_enable_board']), true); // Build the message index button array. $context['normal_buttons'] = array('new_topic' => array('test' => 'can_post_new', 'text' => 'new_topic', 'image' => 'new_topic.png', 'lang' => true, 'url' => $scripturl . '?action=post;board=' . $context['current_board'] . '.0', 'active' => true), 'notify' => array('test' => 'can_mark_notify', 'text' => $context['is_marked_notify'] ? 'unnotify' : 'notify', 'image' => ($context['is_marked_notify'] ? 'un' : '') . 'notify.png', 'lang' => true, 'custom' => 'onclick="return notifyboardButton(this);"', 'url' => $scripturl . '?action=notifyboard;sa=' . ($context['is_marked_notify'] ? 'off' : 'on') . ';board=' . $context['current_board'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id'])); // They can only mark read if they are logged in and it's enabled! if (!$user_info['is_guest'] && $settings['show_mark_read']) { $context['normal_buttons']['markread'] = array('text' => 'mark_read_short', 'image' => 'markread.png', 'lang' => true, 'url' => $scripturl . '?action=markasread;sa=board;board=' . $context['current_board'] . '.0;' . $context['session_var'] . '=' . $context['session_id'], 'custom' => 'onclick="return markboardreadButton(this);"'); } // Allow adding new buttons easily. call_integration_hook('integrate_messageindex_buttons'); }
/** * Find unread topics and replies. * Accessed by action=unread and action=unreadreplies */ public function action_unread() { global $board, $txt, $scripturl; global $user_info, $context, $settings, $modSettings, $options; $db = database(); // Guests can't have unread things, we don't know anything about them. is_not_guest(); // Prefetching + lots of MySQL work = bad mojo. if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') { @ob_end_clean(); header('HTTP/1.1 403 Forbidden'); die; } // We need... we need... I know! require_once SUBSDIR . '/Recent.subs.php'; require_once SUBSDIR . '/Boards.subs.php'; $context['showCheckboxes'] = !empty($options['display_quick_mod']) && $options['display_quick_mod'] == 1 && $settings['show_mark_read']; $context['showing_all_topics'] = isset($_GET['all']); $context['start'] = (int) $_REQUEST['start']; $context['topics_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['topics_per_page']) ? $options['topics_per_page'] : $modSettings['defaultMaxTopics']; if ($_REQUEST['action'] == 'unread') { $context['page_title'] = $context['showing_all_topics'] ? $txt['unread_topics_all'] : $txt['unread_topics_visit']; } else { $context['page_title'] = $txt['unread_replies']; } if ($context['showing_all_topics'] && !empty($modSettings['loadavg_allunread']) && $modSettings['current_load'] >= $modSettings['loadavg_allunread']) { fatal_lang_error('loadavg_allunread_disabled', false); } elseif ($_REQUEST['action'] != 'unread' && !empty($modSettings['loadavg_unreadreplies']) && $modSettings['current_load'] >= $modSettings['loadavg_unreadreplies']) { fatal_lang_error('loadavg_unreadreplies_disabled', false); } elseif (!$context['showing_all_topics'] && $_REQUEST['action'] == 'unread' && !empty($modSettings['loadavg_unread']) && $modSettings['current_load'] >= $modSettings['loadavg_unread']) { fatal_lang_error('loadavg_unread_disabled', false); } // Parameters for the main query. $query_parameters = array(); // Are we specifying any specific board? if (isset($_REQUEST['children']) && (!empty($board) || !empty($_REQUEST['boards']))) { $boards = array(); if (!empty($_REQUEST['boards'])) { $_REQUEST['boards'] = explode(',', $_REQUEST['boards']); foreach ($_REQUEST['boards'] as $b) { $boards[] = (int) $b; } } if (!empty($board)) { $boards[] = (int) $board; } // The easiest thing is to just get all the boards they can see, // but since we've specified the top of tree we ignore some of them addChildBoards($boards); if (empty($boards)) { fatal_lang_error('error_no_boards_selected'); } $query_this_board = 'id_board IN ({array_int:boards})'; $query_parameters['boards'] = $boards; $context['querystring_board_limits'] = ';boards=' . implode(',', $boards) . ';start=%d'; } elseif (!empty($board)) { $query_this_board = 'id_board = {int:board}'; $query_parameters['board'] = $board; $context['querystring_board_limits'] = ';board=' . $board . '.%1$d'; } elseif (!empty($_REQUEST['boards'])) { $selected_boards = array_map('intval', explode(',', $_REQUEST['boards'])); $boards = accessibleBoards($selected_boards); if (empty($boards)) { fatal_lang_error('error_no_boards_selected'); } $query_this_board = 'id_board IN ({array_int:boards})'; $query_parameters['boards'] = $boards; $context['querystring_board_limits'] = ';boards=' . implode(',', $boards) . ';start=%1$d'; } elseif (!empty($_REQUEST['c'])) { $categories = array_map('intval', explode(',', $_REQUEST['c'])); $boards = array_keys(boardsPosts(array(), $categories, isset($_REQUEST['action']) && $_REQUEST['action'] != 'unreadreplies')); if (empty($boards)) { fatal_lang_error('error_no_boards_selected'); } $query_this_board = 'id_board IN ({array_int:boards})'; $query_parameters['boards'] = $boards; $context['querystring_board_limits'] = ';c=' . $_REQUEST['c'] . ';start=%1$d'; } else { $see_board = isset($_REQUEST['action']) && $_REQUEST['action'] == 'unreadreplies' ? 'query_see_board' : 'query_wanna_see_board'; // Don't bother to show deleted posts! $boards = wantedBoards($see_board); if (empty($boards)) { fatal_lang_error('error_no_boards_selected'); } $query_this_board = 'id_board IN ({array_int:boards})'; $query_parameters['boards'] = $boards; $context['querystring_board_limits'] = ';start=%1$d'; $context['no_board_limits'] = true; } $sort_methods = array('subject' => 'ms.subject', 'starter' => 'IFNULL(mems.real_name, ms.poster_name)', 'replies' => 't.num_replies', 'views' => 't.num_views', 'first_post' => 't.id_topic', 'last_post' => 't.id_last_msg'); // The default is the most logical: newest first. if (!isset($_REQUEST['sort']) || !isset($sort_methods[$_REQUEST['sort']])) { $context['sort_by'] = 'last_post'; $ascending = isset($_REQUEST['asc']); $context['querystring_sort_limits'] = $ascending ? ';asc' : ''; } else { $context['sort_by'] = $_REQUEST['sort']; $ascending = !isset($_REQUEST['desc']); $context['querystring_sort_limits'] = ';sort=' . $context['sort_by'] . ($ascending ? '' : ';desc'); } $_REQUEST['sort'] = $sort_methods[$context['sort_by']]; $context['sort_direction'] = $ascending ? 'up' : 'down'; $context['sort_title'] = $ascending ? $txt['sort_desc'] : $txt['sort_asc']; // Trick $txt['starter'] = $txt['started_by']; foreach ($sort_methods as $key => $val) { $context['topics_headers'][$key] = array('url' => $scripturl . '?action=unread' . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start']) . ';sort=subject' . ($context['sort_by'] == 'subject' && $context['sort_direction'] == 'up' ? ';desc' : ''), 'sort_dir_img' => $context['sort_by'] == $key ? '<img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" title="' . $context['sort_title'] . '" />' : ''); } if (!empty($_REQUEST['c']) && is_array($_REQUEST['c']) && count($_REQUEST['c']) == 1) { $name = categoryName((int) $_REQUEST['c'][0]); $context['linktree'][] = array('url' => $scripturl . '#c' . (int) $_REQUEST['c'][0], 'name' => $name); } $context['linktree'][] = array('url' => $scripturl . '?action=' . $_REQUEST['action'] . sprintf($context['querystring_board_limits'], 0) . $context['querystring_sort_limits'], 'name' => $_REQUEST['action'] == 'unread' ? $txt['unread_topics_visit'] : $txt['unread_replies']); if ($context['showing_all_topics']) { $context['linktree'][] = array('url' => $scripturl . '?action=' . $_REQUEST['action'] . ';all' . sprintf($context['querystring_board_limits'], 0) . $context['querystring_sort_limits'], 'name' => $txt['unread_topics_all']); $txt['unread_topics_visit_none'] = str_replace('{unread_all_url}', $scripturl . '?action=unread;all', $txt['unread_topics_visit_none']); } else { $txt['unread_topics_visit_none'] = str_replace('{unread_all_url}', $scripturl . '?action=unread;all' . sprintf($context['querystring_board_limits'], 0) . $context['querystring_sort_limits'], $txt['unread_topics_visit_none']); } loadTemplate('Recent'); $context['sub_template'] = $_REQUEST['action'] == 'unread' ? 'unread' : 'replies'; // Setup the default topic icons... for checking they exist and the like ;) require_once SUBSDIR . '/MessageIndex.subs.php'; $context['icon_sources'] = MessageTopicIcons(); $is_topics = $_REQUEST['action'] == 'unread'; // If empty, no preview at all if (empty($modSettings['message_index_preview'])) { $preview_bodies = ''; } elseif (empty($modSettings['preview_characters'])) { $preview_bodies = 'ml.body AS last_body, ms.body AS first_body,'; } else { $preview_bodies = 'SUBSTRING(ml.body, 1, ' . ($modSettings['preview_characters'] + 256) . ') AS last_body, SUBSTRING(ms.body, 1, ' . ($modSettings['preview_characters'] + 256) . ') AS first_body,'; } // This part is the same for each query. $select_clause = ' ms.subject AS first_subject, ms.poster_time AS first_poster_time, ms.id_topic, t.id_board, b.name AS bname, t.num_replies, t.num_views, t.num_likes, ms.id_member AS id_first_member, ml.id_member AS id_last_member, ml.poster_time AS last_poster_time, IFNULL(mems.real_name, ms.poster_name) AS first_poster_name, IFNULL(meml.real_name, ml.poster_name) AS last_poster_name, ml.subject AS last_subject, ml.icon AS last_icon, ms.icon AS first_icon, t.id_poll, t.is_sticky, t.locked, ml.modified_time AS last_modified_time, IFNULL(lt.id_msg, IFNULL(lmr.id_msg, -1)) + 1 AS new_from, ' . $preview_bodies . ' ml.smileys_enabled AS last_smileys, ms.smileys_enabled AS first_smileys, t.id_first_msg, t.id_last_msg'; if ($context['showing_all_topics']) { $earliest_msg = earliest_msg(); } // @todo Add modified_time in for log_time check? if ($modSettings['totalMessages'] > 100000 && $context['showing_all_topics']) { $db->query('', ' DROP TABLE IF EXISTS {db_prefix}log_topics_unread', array()); // Let's copy things out of the log_topics table, to reduce searching. $have_temp_table = $db->query('', ' CREATE TEMPORARY TABLE {db_prefix}log_topics_unread ( PRIMARY KEY (id_topic) ) SELECT lt.id_topic, lt.id_msg, lt.unwatched FROM {db_prefix}topics AS t INNER JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic) WHERE lt.id_member = {int:current_member} AND t.' . $query_this_board . (empty($earliest_msg) ? '' : ' AND t.id_last_msg > {int:earliest_msg}') . ($modSettings['postmod_active'] ? ' AND t.approved = {int:is_approved}' : '') . ($modSettings['enable_unwatch'] ? ' AND lt.unwatched != 1' : ''), array_merge($query_parameters, array('current_member' => $user_info['id'], 'earliest_msg' => !empty($earliest_msg) ? $earliest_msg : 0, 'is_approved' => 1, 'db_error_skip' => true))) !== false; } else { $have_temp_table = false; } if ($context['showing_all_topics'] && $have_temp_table) { $request = $db->query('', ' SELECT COUNT(*), MIN(t.id_last_msg) FROM {db_prefix}topics AS t LEFT JOIN {db_prefix}log_topics_unread AS lt ON (lt.id_topic = t.id_topic) LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member}) WHERE t.' . $query_this_board . (!empty($earliest_msg) ? ' AND t.id_last_msg > {int:earliest_msg}' : '') . ' AND IFNULL(lt.id_msg, IFNULL(lmr.id_msg, 0)) < t.id_last_msg' . ($modSettings['postmod_active'] ? ' AND t.approved = {int:is_approved}' : '') . ($modSettings['enable_unwatch'] ? ' AND IFNULL(lt.unwatched, 0) != 1' : ''), array_merge($query_parameters, array('current_member' => $user_info['id'], 'earliest_msg' => !empty($earliest_msg) ? $earliest_msg : 0, 'is_approved' => 1))); list($num_topics, $min_message) = $db->fetch_row($request); $db->free_result($request); // Make sure the starting place makes sense and construct the page index. $context['page_index'] = constructPageIndex($scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . $context['querystring_board_limits'] . $context['querystring_sort_limits'], $_REQUEST['start'], $num_topics, $context['topics_per_page'], true); $context['current_page'] = (int) $_REQUEST['start'] / $context['topics_per_page']; $context['links'] += array('prev' => $_REQUEST['start'] >= $context['topics_per_page'] ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start'] - $context['topics_per_page']) . $context['querystring_sort_limits'] : '', 'next' => $_REQUEST['start'] + $context['topics_per_page'] < $num_topics ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start'] + $context['topics_per_page']) . $context['querystring_sort_limits'] : ''); $context['page_info'] = array('current_page' => $_REQUEST['start'] / $context['topics_per_page'] + 1, 'num_pages' => floor(($num_topics - 1) / $context['topics_per_page']) + 1); if ($num_topics == 0) { // Mark the boards as read if there are no unread topics! // @todo look at this... there are no more unread topics already. // If clearing of log_topics is still needed, perhaps do it separately. markBoardsRead(empty($boards) ? $board : $boards, false, true); $context['topics'] = array(); if ($context['querystring_board_limits'] == ';start=%1$d') { $context['querystring_board_limits'] = ''; } else { $context['querystring_board_limits'] = sprintf($context['querystring_board_limits'], $_REQUEST['start']); } return; } else { $min_message = (int) $min_message; } $request = $db->query('substring', ' SELECT ' . $select_clause . ' FROM {db_prefix}messages AS ms INNER JOIN {db_prefix}topics AS t ON (t.id_topic = ms.id_topic AND t.id_first_msg = ms.id_msg) INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg) LEFT JOIN {db_prefix}boards AS b ON (b.id_board = ms.id_board) LEFT JOIN {db_prefix}members AS mems ON (mems.id_member = ms.id_member) LEFT JOIN {db_prefix}members AS meml ON (meml.id_member = ml.id_member) LEFT JOIN {db_prefix}log_topics_unread AS lt ON (lt.id_topic = t.id_topic) LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member}) WHERE b.' . $query_this_board . ' AND t.id_last_msg >= {int:min_message} AND IFNULL(lt.id_msg, IFNULL(lmr.id_msg, 0)) < t.id_last_msg' . ($modSettings['postmod_active'] ? ' AND ms.approved = {int:is_approved}' : '') . ($modSettings['enable_unwatch'] ? ' AND IFNULL(lt.unwatched, 0) != 1' : '') . ' ORDER BY {raw:sort} LIMIT {int:offset}, {int:limit}', array_merge($query_parameters, array('current_member' => $user_info['id'], 'min_message' => $min_message, 'is_approved' => 1, 'sort' => $_REQUEST['sort'] . ($ascending ? '' : ' DESC'), 'offset' => $_REQUEST['start'], 'limit' => $context['topics_per_page']))); } elseif ($is_topics) { $request = $db->query('', ' SELECT COUNT(*), MIN(t.id_last_msg) FROM {db_prefix}topics AS t' . (!empty($have_temp_table) ? ' LEFT JOIN {db_prefix}log_topics_unread AS lt ON (lt.id_topic = t.id_topic)' : ' LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member})') . ' LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member}) WHERE t.' . $query_this_board . ($context['showing_all_topics'] && !empty($earliest_msg) ? ' AND t.id_last_msg > {int:earliest_msg}' : (!$context['showing_all_topics'] && empty($_SESSION['first_login']) ? ' AND t.id_last_msg > {int:id_msg_last_visit}' : '')) . ' AND IFNULL(lt.id_msg, IFNULL(lmr.id_msg, 0)) < t.id_last_msg' . ($modSettings['postmod_active'] ? ' AND t.approved = {int:is_approved}' : '') . ($modSettings['enable_unwatch'] ? ' AND IFNULL(lt.unwatched, 0) != 1' : ''), array_merge($query_parameters, array('current_member' => $user_info['id'], 'earliest_msg' => !empty($earliest_msg) ? $earliest_msg : 0, 'id_msg_last_visit' => $_SESSION['id_msg_last_visit'], 'is_approved' => 1))); list($num_topics, $min_message) = $db->fetch_row($request); $db->free_result($request); // Make sure the starting place makes sense and construct the page index. $context['page_index'] = constructPageIndex($scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . $context['querystring_board_limits'] . $context['querystring_sort_limits'], $_REQUEST['start'], $num_topics, $context['topics_per_page'], true); $context['current_page'] = (int) $_REQUEST['start'] / $context['topics_per_page']; $context['links'] += array('prev' => $_REQUEST['start'] >= $context['topics_per_page'] ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start'] - $context['topics_per_page']) . $context['querystring_sort_limits'] : '', 'next' => $_REQUEST['start'] + $context['topics_per_page'] < $num_topics ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start'] + $context['topics_per_page']) . $context['querystring_sort_limits'] : ''); $context['page_info'] = array('current_page' => $_REQUEST['start'] / $context['topics_per_page'] + 1, 'num_pages' => floor(($num_topics - 1) / $context['topics_per_page']) + 1); if ($num_topics == 0) { // Is this an all topics query? if ($context['showing_all_topics']) { // Since there are no unread topics, mark the boards as read! // @todo look at this... there are no more unread topics already. // If clearing of log_topics is still needed, perhaps do it separately. markBoardsRead(empty($boards) ? $board : $boards, false, true); } $context['topics'] = array(); if ($context['querystring_board_limits'] == ';start=%d') { $context['querystring_board_limits'] = ''; } else { $context['querystring_board_limits'] = sprintf($context['querystring_board_limits'], $_REQUEST['start']); } return; } else { $min_message = (int) $min_message; } $request = $db->query('substring', ' SELECT ' . $select_clause . ' FROM {db_prefix}messages AS ms INNER JOIN {db_prefix}topics AS t ON (t.id_topic = ms.id_topic AND t.id_first_msg = ms.id_msg) INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg) LEFT JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) LEFT JOIN {db_prefix}members AS mems ON (mems.id_member = ms.id_member) LEFT JOIN {db_prefix}members AS meml ON (meml.id_member = ml.id_member)' . (!empty($have_temp_table) ? ' LEFT JOIN {db_prefix}log_topics_unread AS lt ON (lt.id_topic = t.id_topic)' : ' LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member})') . ' LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member}) WHERE t.' . $query_this_board . ' AND t.id_last_msg >= {int:min_message} AND IFNULL(lt.id_msg, IFNULL(lmr.id_msg, 0)) < ml.id_msg' . ($modSettings['postmod_active'] ? ' AND ms.approved = {int:is_approved}' : '') . ($modSettings['enable_unwatch'] ? ' AND IFNULL(lt.unwatched, 0) != 1' : '') . ' ORDER BY {raw:order} LIMIT {int:offset}, {int:limit}', array_merge($query_parameters, array('current_member' => $user_info['id'], 'min_message' => $min_message, 'is_approved' => 1, 'order' => $_REQUEST['sort'] . ($ascending ? '' : ' DESC'), 'offset' => $_REQUEST['start'], 'limit' => $context['topics_per_page']))); } else { if ($modSettings['totalMessages'] > 100000) { $db->query('', ' DROP TABLE IF EXISTS {db_prefix}topics_posted_in', array()); $db->query('', ' DROP TABLE IF EXISTS {db_prefix}log_topics_posted_in', array()); $sortKey_joins = array('ms.subject' => ' INNER JOIN {db_prefix}messages AS ms ON (ms.id_msg = t.id_first_msg)', 'IFNULL(mems.real_name, ms.poster_name)' => ' INNER JOIN {db_prefix}messages AS ms ON (ms.id_msg = t.id_first_msg) LEFT JOIN {db_prefix}members AS mems ON (mems.id_member = ms.id_member)'); // The main benefit of this temporary table is not that it's faster; it's that it avoids locks later. $have_temp_table = $db->query('', ' CREATE TEMPORARY TABLE {db_prefix}topics_posted_in ( id_topic mediumint(8) unsigned NOT NULL default {string:string_zero}, id_board smallint(5) unsigned NOT NULL default {string:string_zero}, id_last_msg int(10) unsigned NOT NULL default {string:string_zero}, id_msg int(10) unsigned NOT NULL default {string:string_zero}, PRIMARY KEY (id_topic) ) SELECT t.id_topic, t.id_board, t.id_last_msg, IFNULL(lmr.id_msg, 0) AS id_msg' . (!in_array($_REQUEST['sort'], array('t.id_last_msg', 't.id_topic')) ? ', ' . $_REQUEST['sort'] . ' AS sort_key' : '') . ' FROM {db_prefix}messages AS m INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic)' . ($modSettings['enable_unwatch'] ? ' LEFT JOIN {db_prefix}log_topics AS lt ON (t.id_topic = lt.id_topic AND lt.id_member = {int:current_member})' : '') . ' LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member})' . (isset($sortKey_joins[$_REQUEST['sort']]) ? $sortKey_joins[$_REQUEST['sort']] : '') . ' WHERE m.id_member = {int:current_member}' . (!empty($board) ? ' AND t.id_board = {int:current_board}' : '') . ($modSettings['postmod_active'] ? ' AND t.approved = {int:is_approved}' : '') . ($modSettings['enable_unwatch'] ? ' AND IFNULL(lt.unwatched, 0) != 1' : '') . ' GROUP BY m.id_topic', array('current_board' => $board, 'current_member' => $user_info['id'], 'is_approved' => 1, 'string_zero' => '0', 'db_error_skip' => true)) !== false; // If that worked, create a sample of the log_topics table too. if ($have_temp_table) { $have_temp_table = $db->query('', ' CREATE TEMPORARY TABLE {db_prefix}log_topics_posted_in ( PRIMARY KEY (id_topic) ) SELECT lt.id_topic, lt.id_msg FROM {db_prefix}log_topics AS lt INNER JOIN {db_prefix}topics_posted_in AS pi ON (pi.id_topic = lt.id_topic) WHERE lt.id_member = {int:current_member}', array('current_member' => $user_info['id'], 'db_error_skip' => true)) !== false; } } if (!empty($have_temp_table)) { $request = $db->query('', ' SELECT COUNT(*) FROM {db_prefix}topics_posted_in AS pi LEFT JOIN {db_prefix}log_topics_posted_in AS lt ON (lt.id_topic = pi.id_topic) WHERE pi.' . $query_this_board . ' AND IFNULL(lt.id_msg, pi.id_msg) < pi.id_last_msg', array_merge($query_parameters, array())); list($num_topics) = $db->fetch_row($request); $db->free_result($request); $min_message = 0; } else { $request = $db->query('unread_fetch_topic_count', ' SELECT COUNT(DISTINCT t.id_topic), MIN(t.id_last_msg) FROM {db_prefix}topics AS t INNER JOIN {db_prefix}messages AS m ON (m.id_topic = t.id_topic) LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member}) LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member}) WHERE t.' . $query_this_board . ' AND m.id_member = {int:current_member} AND IFNULL(lt.id_msg, IFNULL(lmr.id_msg, 0)) < t.id_last_msg' . ($modSettings['postmod_active'] ? ' AND t.approved = {int:is_approved}' : '') . ($modSettings['enable_unwatch'] ? ' AND IFNULL(lt.unwatched, 0) != 1' : ''), array_merge($query_parameters, array('current_member' => $user_info['id'], 'is_approved' => 1))); list($num_topics, $min_message) = $db->fetch_row($request); $db->free_result($request); } // Make sure the starting place makes sense and construct the page index. $context['page_index'] = constructPageIndex($scripturl . '?action=' . $_REQUEST['action'] . $context['querystring_board_limits'] . $context['querystring_sort_limits'], $_REQUEST['start'], $num_topics, $context['topics_per_page'], true); $context['current_page'] = (int) $_REQUEST['start'] / $context['topics_per_page']; $context['links'] += array('first' => $_REQUEST['start'] >= $context['topics_per_page'] ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], 0) . $context['querystring_sort_limits'] : '', 'prev' => $_REQUEST['start'] >= $context['topics_per_page'] ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start'] - $context['topics_per_page']) . $context['querystring_sort_limits'] : '', 'next' => $_REQUEST['start'] + $context['topics_per_page'] < $num_topics ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start'] + $context['topics_per_page']) . $context['querystring_sort_limits'] : '', 'last' => $_REQUEST['start'] + $context['topics_per_page'] < $num_topics ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], floor(($num_topics - 1) / $context['topics_per_page']) * $context['topics_per_page']) . $context['querystring_sort_limits'] : '', 'up' => $scripturl); $context['page_info'] = array('current_page' => $_REQUEST['start'] / $context['topics_per_page'] + 1, 'num_pages' => floor(($num_topics - 1) / $context['topics_per_page']) + 1); if ($num_topics == 0) { $context['topics'] = array(); if ($context['querystring_board_limits'] == ';start=%d') { $context['querystring_board_limits'] = ''; } else { $context['querystring_board_limits'] = sprintf($context['querystring_board_limits'], $_REQUEST['start']); } return; } if (!empty($have_temp_table)) { $request = $db->query('', ' SELECT t.id_topic FROM {db_prefix}topics_posted_in AS t LEFT JOIN {db_prefix}log_topics_posted_in AS lt ON (lt.id_topic = t.id_topic) WHERE t.' . $query_this_board . ' AND IFNULL(lt.id_msg, t.id_msg) < t.id_last_msg ORDER BY {raw:order} LIMIT {int:offset}, {int:limit}', array_merge($query_parameters, array('order' => (in_array($_REQUEST['sort'], array('t.id_last_msg', 't.id_topic')) ? $_REQUEST['sort'] : 't.sort_key') . ($ascending ? '' : ' DESC'), 'offset' => $_REQUEST['start'], 'limit' => $context['topics_per_page']))); } else { $request = $db->query('unread_replies', ' SELECT DISTINCT t.id_topic FROM {db_prefix}topics AS t INNER JOIN {db_prefix}messages AS m ON (m.id_topic = t.id_topic AND m.id_member = {int:current_member})' . (strpos($_REQUEST['sort'], 'ms.') === false ? '' : ' INNER JOIN {db_prefix}messages AS ms ON (ms.id_msg = t.id_first_msg)') . (strpos($_REQUEST['sort'], 'mems.') === false ? '' : ' LEFT JOIN {db_prefix}members AS mems ON (mems.id_member = ms.id_member)') . ' LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member}) LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member}) WHERE t.' . $query_this_board . ' AND t.id_last_msg >= {int:min_message} AND (IFNULL(lt.id_msg, IFNULL(lmr.id_msg, 0))) < t.id_last_msg' . ($modSettings['postmod_active'] ? ' AND t.approved = {int:is_approved}' : '') . ($modSettings['enable_unwatch'] ? ' AND IFNULL(lt.unwatched, 0) != 1' : '') . ' ORDER BY {raw:order} LIMIT {int:offset}, {int:limit}', array_merge($query_parameters, array('current_member' => $user_info['id'], 'min_message' => (int) $min_message, 'is_approved' => 1, 'order' => $_REQUEST['sort'] . ($ascending ? '' : ' DESC'), 'offset' => $_REQUEST['start'], 'limit' => $context['topics_per_page'], 'sort' => $_REQUEST['sort']))); } $topics = array(); while ($row = $db->fetch_assoc($request)) { $topics[] = $row['id_topic']; } $db->free_result($request); // Sanity... where have you gone? if (empty($topics)) { $context['topics'] = array(); if ($context['querystring_board_limits'] == ';start=%d') { $context['querystring_board_limits'] = ''; } else { $context['querystring_board_limits'] = sprintf($context['querystring_board_limits'], $_REQUEST['start']); } return; } $request = $db->query('substring', ' SELECT ' . $select_clause . ' FROM {db_prefix}topics AS t INNER JOIN {db_prefix}messages AS ms ON (ms.id_topic = t.id_topic AND ms.id_msg = t.id_first_msg) INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg) INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) LEFT JOIN {db_prefix}members AS mems ON (mems.id_member = ms.id_member) LEFT JOIN {db_prefix}members AS meml ON (meml.id_member = ml.id_member) LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member}) LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member}) WHERE t.id_topic IN ({array_int:topic_list}) ORDER BY ' . $_REQUEST['sort'] . ($ascending ? '' : ' DESC') . ' LIMIT ' . count($topics), array('current_member' => $user_info['id'], 'topic_list' => $topics)); } $context['topics'] = array(); $topic_ids = array(); while ($row = $db->fetch_assoc($request)) { $topic_ids[] = $row['id_topic']; if (!empty($modSettings['message_index_preview'])) { // Limit them to 128 characters - do this FIRST because it's a lot of wasted censoring otherwise. $row['first_body'] = strip_tags(strtr(parse_bbc($row['first_body'], false, $row['id_first_msg']), array('<br />' => "\n", ' ' => ' '))); $row['first_body'] = Util::shorten_text($row['first_body'], !empty($modSettings['preview_characters']) ? $modSettings['preview_characters'] : 128, true); // No reply then they are the same, no need to process it again if ($row['num_replies'] == 0) { $row['last_body'] == $row['first_body']; } else { $row['last_body'] = strip_tags(strtr(parse_bbc($row['last_body'], false, $row['id_last_msg']), array('<br />' => "\n", ' ' => ' '))); $row['last_body'] = Util::shorten_text($row['last_body'], !empty($modSettings['preview_characters']) ? $modSettings['preview_characters'] : 128, true); } // Censor the subject and message preview. censorText($row['first_subject']); censorText($row['first_body']); // Don't censor them twice! if ($row['id_first_msg'] == $row['id_last_msg']) { $row['last_subject'] = $row['first_subject']; $row['last_body'] = $row['first_body']; } else { censorText($row['last_subject']); censorText($row['last_body']); } } else { $row['first_body'] = ''; $row['last_body'] = ''; censorText($row['first_subject']); if ($row['id_first_msg'] == $row['id_last_msg']) { $row['last_subject'] = $row['first_subject']; } else { censorText($row['last_subject']); } } // Decide how many pages the topic should have. $topic_length = $row['num_replies'] + 1; $messages_per_page = empty($modSettings['disableCustomPerPage']) && !empty($options['messages_per_page']) ? $options['messages_per_page'] : $modSettings['defaultMaxMessages']; if ($topic_length > $messages_per_page) { $start = -1; $pages = constructPageIndex($scripturl . '?topic=' . $row['id_topic'] . '.%1$d;topicseen', $start, $topic_length, $messages_per_page, true, array('prev_next' => false, 'all' => !empty($modSettings['enableAllMessages']) && $topic_length < $modSettings['enableAllMessages'])); } else { $pages = ''; } // We need to check the topic icons exist... you can never be too sure! if (!empty($modSettings['messageIconChecks_enable'])) { // First icon first... as you'd expect. if (!isset($context['icon_sources'][$row['first_icon']])) { $context['icon_sources'][$row['first_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['first_icon'] . '.png') ? 'images_url' : 'default_images_url'; } // Last icon... last... duh. if (!isset($context['icon_sources'][$row['last_icon']])) { $context['icon_sources'][$row['last_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['last_icon'] . '.png') ? 'images_url' : 'default_images_url'; } } // And build the array. $context['topics'][$row['id_topic']] = array('id' => $row['id_topic'], 'first_post' => array('id' => $row['id_first_msg'], 'member' => array('name' => $row['first_poster_name'], 'id' => $row['id_first_member'], 'href' => $scripturl . '?action=profile;u=' . $row['id_first_member'], 'link' => !empty($row['id_first_member']) ? '<a class="preview" href="' . $scripturl . '?action=profile;u=' . $row['id_first_member'] . '" title="' . $txt['profile_of'] . ' ' . $row['first_poster_name'] . '">' . $row['first_poster_name'] . '</a>' : $row['first_poster_name']), 'time' => standardTime($row['first_poster_time']), 'html_time' => htmlTime($row['first_poster_time']), 'timestamp' => forum_time(true, $row['first_poster_time']), 'subject' => $row['first_subject'], 'preview' => $row['first_body'], 'icon' => $row['first_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['first_icon']]] . '/post/' . $row['first_icon'] . '.png', 'href' => $scripturl . '?topic=' . $row['id_topic'] . '.0;topicseen', 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.0;topicseen">' . $row['first_subject'] . '</a>'), 'last_post' => array('id' => $row['id_last_msg'], 'member' => array('name' => $row['last_poster_name'], 'id' => $row['id_last_member'], 'href' => $scripturl . '?action=profile;u=' . $row['id_last_member'], 'link' => !empty($row['id_last_member']) ? '<a href="' . $scripturl . '?action=profile;u=' . $row['id_last_member'] . '">' . $row['last_poster_name'] . '</a>' : $row['last_poster_name']), 'time' => standardTime($row['last_poster_time']), 'html_time' => htmlTime($row['last_poster_time']), 'timestamp' => forum_time(true, $row['last_poster_time']), 'subject' => $row['last_subject'], 'preview' => $row['last_body'], 'icon' => $row['last_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['last_icon']]] . '/post/' . $row['last_icon'] . '.png', 'href' => $scripturl . '?topic=' . $row['id_topic'] . ($row['num_replies'] == 0 ? '.0' : '.msg' . $row['id_last_msg']) . ';topicseen#msg' . $row['id_last_msg'], 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . ($row['num_replies'] == 0 ? '.0' : '.msg' . $row['id_last_msg']) . ';topicseen#msg' . $row['id_last_msg'] . '" rel="nofollow">' . $row['last_subject'] . '</a>'), 'default_preview' => trim($row[!empty($modSettings['message_index_preview']) && $modSettings['message_index_preview'] == 2 ? 'last_body' : 'first_body']), 'new_from' => $row['new_from'], 'new_href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['new_from'] . ';topicseen#new', 'href' => $scripturl . '?topic=' . $row['id_topic'] . ($row['num_replies'] == 0 ? '.0' : '.msg' . $row['new_from']) . ';topicseen' . ($row['num_replies'] == 0 ? '' : 'new'), 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . ($row['num_replies'] == 0 ? '.0' : '.msg' . $row['new_from']) . ';topicseen#msg' . $row['new_from'] . '" rel="nofollow">' . $row['first_subject'] . '</a>', 'is_sticky' => !empty($modSettings['enableStickyTopics']) && !empty($row['is_sticky']), 'is_locked' => !empty($row['locked']), 'is_poll' => !empty($modSettings['pollMode']) && $row['id_poll'] > 0, 'is_hot' => !empty($modSettings['useLikesNotViews']) ? $row['num_likes'] >= $modSettings['hotTopicPosts'] : $row['num_replies'] >= $modSettings['hotTopicPosts'], 'is_very_hot' => !empty($modSettings['useLikesNotViews']) ? $row['num_likes'] >= $modSettings['hotTopicVeryPosts'] : $row['num_replies'] >= $modSettings['hotTopicVeryPosts'], 'is_posted_in' => false, 'icon' => $row['first_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['first_icon']]] . '/post/' . $row['first_icon'] . '.png', 'subject' => $row['first_subject'], 'pages' => $pages, 'replies' => comma_format($row['num_replies']), 'views' => comma_format($row['num_views']), 'likes' => comma_format($row['num_likes']), 'board' => array('id' => $row['id_board'], 'name' => $row['bname'], 'href' => $scripturl . '?board=' . $row['id_board'] . '.0', 'link' => '<a href="' . $scripturl . '?board=' . $row['id_board'] . '.0">' . $row['bname'] . '</a>')); $context['topics'][$row['id_topic']]['first_post']['started_by'] = sprintf($txt['topic_started_by_in'], '<strong>' . $context['topics'][$row['id_topic']]['first_post']['member']['link'] . '</strong>', '<em>' . $context['topics'][$row['id_topic']]['board']['link'] . '</em>'); determineTopicClass($context['topics'][$row['id_topic']]); } $db->free_result($request); if ($is_topics && !empty($modSettings['enableParticipation']) && !empty($topic_ids)) { require_once SUBSDIR . '/MessageIndex.subs.php'; $topics_participated_in = topicsParticipation($user_info['id'], $topic_ids); foreach ($topics_participated_in as $topic) { if (empty($context['topics'][$topic['id_topic']]['is_posted_in'])) { $context['topics'][$topic['id_topic']]['is_posted_in'] = true; $context['topics'][$topic['id_topic']]['class'] = 'my_' . $context['topics'][$topic['id_topic']]['class']; } } } $context['querystring_board_limits'] = sprintf($context['querystring_board_limits'], $_REQUEST['start']); $context['topics_to_mark'] = implode('-', $topic_ids); if ($settings['show_mark_read']) { // Build the recent button array. if ($is_topics) { $context['recent_buttons'] = array('markread' => array('text' => !empty($context['no_board_limits']) ? 'mark_as_read' : 'mark_read_short', 'image' => 'markread.png', 'lang' => true, 'custom' => 'onclick="return markunreadButton(this);"', 'url' => $scripturl . '?action=markasread;sa=' . (!empty($context['no_board_limits']) ? 'all' : 'board' . $context['querystring_board_limits']) . ';' . $context['session_var'] . '=' . $context['session_id'])); if ($context['showCheckboxes']) { $context['recent_buttons']['markselectread'] = array('text' => 'quick_mod_markread', 'image' => 'markselectedread.png', 'lang' => true, 'url' => 'javascript:document.quickModForm.submit();'); } if (!empty($context['topics']) && !$context['showing_all_topics']) { $context['recent_buttons']['readall'] = array('text' => 'unread_topics_all', 'image' => 'markreadall.png', 'lang' => true, 'url' => $scripturl . '?action=unread;all' . $context['querystring_board_limits'], 'active' => true); } } elseif (!$is_topics && isset($context['topics_to_mark'])) { $context['recent_buttons'] = array('markread' => array('text' => 'mark_as_read', 'image' => 'markread.png', 'lang' => true, 'url' => $scripturl . '?action=markasread;sa=unreadreplies;topics=' . $context['topics_to_mark'] . ';' . $context['session_var'] . '=' . $context['session_id'])); if ($context['showCheckboxes']) { $context['recent_buttons']['markselectread'] = array('text' => 'quick_mod_markread', 'image' => 'markselectedread.png', 'lang' => true, 'url' => 'javascript:document.quickModForm.submit();'); } } // Allow mods to add additional buttons here call_integration_hook('integrate_recent_buttons'); } // Allow helpdesks and bug trackers and what not to add their own unread data (just add a template_layer to show custom stuff in the template!) call_integration_hook('integrate_unread_list'); }