function template_ticket_do_replies() { global $context, $settings, $txt, $scripturl, $options, $modSettings, $reply_request; echo ' <div class="tborder"> <div class="title_bar"> <h3 class="titlebg"> <img src="', $settings['default_images_url'], '/simpledesk/replies.png" alt="x" /> ', $txt['shd_ticket_replies'], ' </h3> </div> <div class="roundframe" id="replies"> <div class="content">'; if (!empty($reply_request)) { while ($reply = $context['get_replies']()) { echo ' <div class="description shd_reply" id="reply', $reply['id'], '"> <span class="floatleft shd_posterinfo"> <strong class="shd_postername"> ', $reply['member']['link'], ' </strong> <br /> ', $reply['member']['group'], '<br class="shd_groupmargin" />'; if (!empty($modSettings['shd_display_avatar']) && empty($options['show_no_avatars']) && !empty($reply['member']['avatar']['image'])) { echo ' ', shd_profile_link($reply['member']['avatar']['image'], $reply['member']['id']); } if ($modSettings['shd_staff_badge'] == (!empty($reply['is_staff']) ? 'staffbadge' : 'userbadge') || $modSettings['shd_staff_badge'] == 'bothbadge') { echo '<br /> ', $reply['member']['group_stars']; } elseif (!empty($reply['is_staff']) && $modSettings['shd_staff_badge'] == 'nobadge') { echo '<br /> <img src="', $settings['default_images_url'] . '/simpledesk/staff.png" class="shd_smallicon" title="', $txt['shd_ticket_staff'], '" alt="', $txt['shd_ticket_staff'], '" />'; } echo ' </span> <div class="shd_replyarea"> <div class="smalltext"> <span class="floatright shd_ticketlinks">'; if ($context['can_quote']) { echo ' <img src="', $settings['default_images_url'], '/simpledesk/quote.png" class="shd_smallicon" alt="*" /><a onclick="return oQuickReply.quote(', $reply['id'], ', \'', $context['session_id'], '\', \'', $context['session_var'], '\', true);" href="', $scripturl, '?action=helpdesk;sa=reply;ticket=', $context['ticket_id'], ';quote=', $reply['id'], ';', $context['session_var'], '=', $context['session_id'], '">', $txt['shd_ticket_quote_short'], '</a>'; } echo ' </span> ', sprintf($txt['shd_reply_written'], $reply['time']), ' </div> <hr class="clearfix" /> ', $reply['body'], ' <br /><br />'; if (!empty($settings['show_modify']) && !empty($reply['modified'])) { echo ' <div class="smalltext shd_modified" style="margin-top:20px;"> « <em>', $txt['last_edit'], ': ', $reply['modified']['time'], ' ', $txt['by'], ' ', $reply['modified']['link'], '</em> » </div>'; } if (!empty($context['ticket_attach']['reply'][$reply['id']])) { echo ' <div class="smalltext"> <strong>', $txt['shd_ticket_attachments'], '</strong><br /> <ul class="shd_replyattachments">'; foreach ($context['ticket_attach']['reply'][$reply['id']] as $attach) { echo ' <li>', $attach['link'], '</li>'; } echo ' </ul> </div>'; } echo ' </div>'; if (!empty($context['can_see_ip']) && !empty($reply['ip_address'])) { echo ' <span class="floatright"><img src="', $settings['default_images_url'], '/simpledesk/ip.png" alt="" class="shd_smallicon" /> ', $txt['shd_ticket_ip'], ': ', $reply['ip_address'], '</span>'; } echo ' <br class="clear" /> </div>'; } } echo ' </div> </div> <span class="lowerframe"><span></span></span> </div>'; }
function shd_profile_show_notify_override($memID) { global $txt, $user_info, $scripturl, $modSettings, $smcFunc, $board, $user_profile, $context; $context['notify_type'] = $_GET['sa']; // We already checked it's monitor or ignore, if we didn't, we wouldn't be here! $context['page_title'] = $txt['shd_profile_show_' . $context['notify_type'] . '_title'] . ' - ' . $user_profile[$memID]['real_name']; $context['sub_template'] = 'shd_profile_show_notify_override'; // The active button. $context['show_tickets_navigation'][$context['notify_type']]['active'] = true; // Having got the general stuff out the way, let's do the specifics. // Ticket, Name, Started By, Replies, Status, Urgency, Updated (+ Updated By?) $context['tickets'] = array(); $query = shd_db_query('', ' SELECT hdt.id_ticket, hdt.subject, IFNULL(mem.id_member, 0) AS starter_id, IFNULL(mem.real_name, hdtr.poster_name) AS starter_name, hdt.num_replies, hdt.status, hdt.urgency, hdt.last_updated FROM {db_prefix}helpdesk_notify_override AS hdno INNER JOIN {db_prefix}helpdesk_tickets AS hdt ON (hdno.id_ticket = hdt.id_ticket) INNER JOIN {db_prefix}helpdesk_ticket_replies AS hdtr ON (hdt.id_first_msg = hdtr.id_msg) LEFT JOIN {db_prefix}members AS mem ON (hdt.id_member_started = mem.id_member) WHERE {query_see_ticket} AND hdno.id_member = {int:user} AND hdno.notify_state = {int:notify} ORDER BY last_updated DESC', array('user' => $memID, 'notify' => $context['notify_type'] == 'monitor' ? NOTIFY_ALWAYS : NOTIFY_NEVER)); while ($row = $smcFunc['db_fetch_assoc']($query)) { $row += array('id_ticket_display' => str_pad($row['id_ticket'], $modSettings['shd_zerofill'], '0', STR_PAD_LEFT), 'updated' => timeformat($row['last_updated']), 'ticket_starter' => shd_profile_link($row['starter_name'], $row['starter_id'])); $context['tickets'][] = $row; } }
/** * Handles fetching the information for the helpdesk display within the unread and unread replies pages. * * The content is 'appended' below the unread posts information by way of a template layer. * * @since 2.0 */ function shd_unread_posts() { global $smcFunc, $context, $user_info, $sourcedir, $txt, $scripturl, $user_profile, $modSettings; // Are we using Dragooon's very swish mobile theme, or other wireless? If so, disable this. if (WIRELESS || isset($_REQUEST['thememode']) && $_REQUEST['thememode'] == 'mobile' || isset($_COOKIE['smf4m_cookie']) && $_COOKIE['smf4m_cookie'] == 'mobile') { $modSettings['shd_disable_unread'] = true; } // We're only displaying this to staff. We didn't do this check on bootstrapping, no sense doing it every page load. if (shd_allowed_to('shd_staff', 0) && empty($modSettings['shd_disable_unread'])) { // Get the data $context['shd_preferences'] = shd_load_user_prefs(); $context['shd_unread_info'] = array(); if (empty($context['shd_preferences']['display_unread_type']) || $context['shd_preferences']['display_unread_type'] == 'outstanding') { // Get all the outstanding tickets $context['block_title'] = $txt['shd_tickets_open']; $request = shd_db_query('', ' SELECT hdt.id_ticket, hdt.subject, hdt.id_ticket, hdt.num_replies, hdt.last_updated, hdtr_first.poster_name, hdt.urgency, hdt.status, hdt.id_member_started, hdt.id_member_assigned, hdt.id_last_msg AS log_read FROM {db_prefix}helpdesk_tickets AS hdt INNER JOIN {db_prefix}helpdesk_ticket_replies AS hdtr_first ON (hdt.id_first_msg = hdtr_first.id_msg) INNER JOIN {db_prefix}helpdesk_ticket_replies AS hdtr_last ON (hdt.id_last_msg = hdtr_last.id_msg) WHERE {query_see_ticket} AND hdt.status IN ({array_int:status}) ORDER BY hdt.urgency DESC, hdt.last_updated', array('status' => array(TICKET_STATUS_NEW, TICKET_STATUS_PENDING_STAFF))); } elseif ($context['shd_preferences']['display_unread_type'] == 'unread') { // Only unread ones $context['block_title'] = $txt['shd_unread_tickets']; $request = shd_db_query('', ' SELECT hdt.id_ticket, hdt.subject, hdt.id_ticket, hdt.num_replies, hdt.last_updated, hdtr_first.poster_name, hdt.urgency, hdt.status, hdt.id_member_started, hdt.id_member_assigned, IFNULL(hdlr.id_msg, 0) AS log_read FROM {db_prefix}helpdesk_tickets AS hdt INNER JOIN {db_prefix}helpdesk_ticket_replies AS hdtr_first ON (hdt.id_first_msg = hdtr_first.id_msg) INNER JOIN {db_prefix}helpdesk_ticket_replies AS hdtr_last ON (hdt.id_last_msg = hdtr_last.id_msg) LEFT JOIN {db_prefix}helpdesk_log_read AS hdlr ON (hdt.id_ticket = hdlr.id_ticket AND hdlr.id_member = {int:user}) WHERE {query_see_ticket} AND hdt.status IN ({array_int:status}) AND (hdlr.id_msg IS NULL OR hdlr.id_msg < hdt.id_last_msg) ORDER BY hdt.urgency DESC, hdt.last_updated', array('user' => $context['user']['id'], 'status' => array(TICKET_STATUS_NEW, TICKET_STATUS_PENDING_STAFF))); } if (!empty($request)) { $members = array(); while ($row = $smcFunc['db_fetch_assoc']($request)) { $row['id_ticket_display'] = str_pad($row['id_ticket'], $modSettings['shd_zerofill'], '0', STR_PAD_LEFT); $row['updated'] = timeformat($row['last_updated']); $context['shd_unread_info'][] = $row; if ($row['id_member_started'] != 0) { $members[] = $row['id_member_started']; } if ($row['id_member_assigned'] != 0) { $members[] = $row['id_member_assigned']; } } loadMemberData(array_unique($members)); foreach ($context['shd_unread_info'] as $key => $ticket) { if (!empty($user_profile[$ticket['id_member_started']])) { $context['shd_unread_info'][$key]['ticket_starter'] = shd_profile_link($user_profile[$ticket['id_member_started']]['member_name'], $ticket['id_member_started']); } else { $context['shd_unread_info'][$key]['ticket_starter'] = $ticket['poster_name']; } if (!empty($user_profile[$ticket['id_member_assigned']])) { $context['shd_unread_info'][$key]['ticket_assigned'] = shd_profile_link($user_profile[$ticket['id_member_assigned']]['member_name'], $ticket['id_member_assigned']); } else { $context['shd_unread_info'][$key]['ticket_assigned'] = '<span class="error">' . $txt['shd_unassigned'] . '</span>'; } } // And set up the template too. loadTemplate('sd_template/SimpleDesk-Unread', 'helpdesk'); $context['template_layers'][] = 'shd_unread'; } } // OK, time to get out of here. If we're here, it's because we have a $_REQUEST['action'] of 'unread' or 'unreadreplies', both of which // are defined in $context['shd_unread_actions'] thanks to shd_init_actions back in Subs-SimpleDesk.php. require_once $sourcedir . '/' . $context['shd_unread_actions'][$_REQUEST['action']][0]; $context['shd_unread_actions'][$_REQUEST['action']][1](); }
function shd_prepare_reply_context() { global $settings, $txt, $modSettings, $scripturl, $options, $user_info, $smcFunc; global $memberContext, $context, $reply_request; if (empty($reply_request)) { return false; } $message = $smcFunc['db_fetch_assoc']($reply_request); if (!$message) { $smcFunc['db_free_result']($reply_request); return false; } if (!loadMemberContext($message['id_member'], true)) { // Notice this information isn't used anywhere else.... $memberContext[$message['id_member']]['name'] = $message['poster_name']; $memberContext[$message['id_member']]['id'] = 0; $memberContext[$message['id_member']]['group'] = $txt['guest_title']; $memberContext[$message['id_member']]['link'] = $message['poster_name']; $memberContext[$message['id_member']]['email'] = $message['poster_email']; $memberContext[$message['id_member']]['show_email'] = showEmailAddress(true, 0); $memberContext[$message['id_member']]['is_guest'] = true; $memberContext[$message['id_member']]['group_stars'] = ''; } $memberContext[$message['id_member']]['ip'] = $message['poster_ip']; censorText($message['body']); $message['body'] = shd_format_text($message['body'], $message['smileys_enabled'], 'shd_reply_' . $message['id_msg']); $output = array('id' => $message['id_msg'], 'member' => &$memberContext[$message['id_member']], 'time' => timeformat($message['poster_time']), 'timestamp' => forum_time(true, $message['poster_time']), 'body' => $message['body'], 'is_staff' => !empty($context['shd_is_staff'][$message['id_member']]), 'can_edit' => shd_allowed_to('shd_edit_reply_any', $context['ticket_form']['dept']) || $message['id_member'] == $user_info['id'] && shd_allowed_to('shd_edit_reply_own', $context['ticket_form']['dept']), 'ip_address' => $message['poster_ip']); if (!empty($message['modified_time'])) { $output['modified'] = array('time' => timeformat($message['modified_time']), 'timestamp' => forum_time(true, $message['modified_time']), 'id' => !empty($user_profile[$message['modified_member']]) ? $message['modified_member'] : 0, 'name' => !empty($user_profile[$message['modified_member']]) ? $user_profile[$message['modified_member']]['real_name'] : $message['modified_name']); $output['modified']['link'] = shd_profile_link($output['modified']['name'], $output['modified']['id']); } return $output; }
/** * Gather the data and prepare to display the ticket blocks. * * Actually performs the queries to get data for each block, subject to the parameters specified by the calling functions. * * It also sets up per-block pagination links, collects a variety of data (enough to populate all the columns as listed in shd_main_helpdesk, * even if not entirely applicable, and populates it all into $context['ticket_blocks']['tickets'], extending the array that was * already there. * * @see shd_main_helpdesk() * @see shd_closed_tickets() * @see shd_recycle_bin() * @since 1.0 */ function shd_helpdesk_listing() { global $context, $txt, $smcFunc, $user_profile, $scripturl, $settings, $user_info, $modSettings, $language; if (!empty($context['shd_permission'])) { shd_is_allowed_to($context['shd_permission']); } $block_list = array_keys($context['ticket_blocks']); $primary_url = '?action=helpdesk;sa=' . $_REQUEST['sa']; // First figure out the start positions of each item and sanitise them foreach ($context['ticket_blocks'] as $block_key => $block) { if (empty($block['viewing_as_block'])) { $num_per_page = !empty($context['shd_preferences']['blocks_' . $block_key . '_count']) ? $context['shd_preferences']['blocks_' . $block_key . '_count'] : $context['items_per_page']; $start = empty($_REQUEST['st_' . $block_key]) ? 0 : (int) $_REQUEST['st_' . $block_key]; $max_value = $block['count']; // easier to read } else { $num_per_page = $context['items_per_page']; $max_value = $context['items_per_page']; $start = 0; } if ($start < 0) { $start = 0; } elseif ($start >= $max_value) { $start = max(0, (int) $max_value - ((int) $max_value % (int) $num_per_page == 0 ? $num_per_page : (int) $max_value % (int) $num_per_page)); } else { $start = max(0, (int) $start - (int) $start % (int) $num_per_page); } $context['ticket_blocks'][$block_key]['start'] = $start; $context['ticket_blocks'][$block_key]['num_per_page'] = $num_per_page; if ($start != 0) { $_REQUEST['st_' . $block_key] = $start; } elseif (isset($_REQUEST['st_' . $block_key])) { unset($_REQUEST['st_' . $block_key]); } } // Now ordering the columns, separate loop for breaking the two processes apart $sort_methods = array('ticketid' => array('sql' => 'hdt.id_ticket'), 'ticketname' => array('sql' => 'hdt.subject'), 'replies' => array('sql' => 'hdt.num_replies'), 'allreplies' => array('sql' => '(hdt.num_replies + hdt.deleted_replies)'), 'urgency' => array('sql' => 'hdt.urgency'), 'updated' => array('sql' => 'hdt.last_updated'), 'assigned' => array('sql' => 'assigned_name', 'sql_select' => 'IFNULL(mem.real_name, 0) AS assigned_name', 'sql_join' => 'LEFT JOIN {db_prefix}members AS mem ON (hdt.id_member_assigned = mem.id_member)'), 'status' => array('sql' => 'hdt.status'), 'starter' => array('sql' => 'starter_name', 'sql_select' => 'IFNULL(mem.real_name, 0) AS starter_name', 'sql_join' => 'LEFT JOIN {db_prefix}members AS mem ON (hdt.id_member_started = mem.id_member)'), 'lastreply' => array('sql' => 'last_reply', 'sql_select' => 'IFNULL(mem.real_name, 0) AS last_reply', 'sql_join' => 'LEFT JOIN {db_prefix}members AS mem ON (hdtr_last.id_member = mem.id_member)')); foreach ($context['ticket_blocks'] as $block_key => $block) { $sort = isset($_REQUEST['so_' . $block_key]) ? $_REQUEST['so_' . $block_key] : (!empty($context['shd_preferences']['block_order_' . $block_key . '_block']) ? $context['shd_preferences']['block_order_' . $block_key . '_block'] : ''); if (strpos($sort, '_') > 0 && substr_count($sort, '_') == 1) { list($sort_item, $sort_dir) = explode('_', $sort); if (empty($sort_methods[$sort_item])) { $sort_item = 'updated'; $sort = ''; } if (!in_array($sort_dir, array('asc', 'desc'))) { $sort = ''; $sort_dir = 'asc'; } } else { $sort = ''; $sort_item = 'updated'; $sort_dir = $_REQUEST['sa'] == 'closedtickets' || $_REQUEST['sa'] == 'recyclebin' ? 'desc' : 'asc'; // default to newest first if on recyclebin or closed tickets, otherwise oldest first } if ($sort != '') { $_REQUEST['so_' . $block_key] = $sort; } elseif (isset($_REQUEST['so_' . $block_key])) { unset($_REQUEST['so_' . $block_key]); } $context['ticket_blocks'][$block_key]['sort'] = array('item' => $sort_item, 'direction' => $sort_dir, 'add_link' => $sort != '', 'sql' => array('select' => !empty($sort_methods[$sort_item]['sql_select']) ? $sort_methods[$sort_item]['sql_select'] : '', 'join' => !empty($sort_methods[$sort_item]['sql_join']) ? $sort_methods[$sort_item]['sql_join'] : '', 'sort' => $sort_methods[$sort_item]['sql'] . ' ' . strtoupper($sort_dir)), 'link_bits' => array()); } // Having got all that, step through the blocks again to determine the full URL fragments foreach ($context['ticket_blocks'] as $block_key => $block) { foreach ($sort_methods as $method => $sort_details) { $context['ticket_blocks'][$block_key]['sort']['link_bits'][$method] = ';so_' . $block_key . '=' . $method . '_' . $block['sort']['direction']; } } // Figure out if the user is filtering on anything, and if so, set up containers for the extra joins, selects, pagination link fragments, etc $_REQUEST['field'] = isset($_REQUEST['field']) ? (int) $_REQUEST['field'] : 0; $_REQUEST['filter'] = isset($_REQUEST['filter']) ? (int) $_REQUEST['filter'] : 0; if ($_REQUEST['field'] > 0 && $_REQUEST['filter'] > 0) { $context['filter_fragment'] = ';field=' . $_REQUEST['field'] . ';filter=' . $_REQUEST['filter']; $context['filter_join'] = ' INNER JOIN {db_prefix}helpdesk_custom_fields_values AS hdcfv ON (hdcfv.id_post = hdt.id_ticket AND hdcfv.id_field = {int:field} AND hdcfv.post_type = {int:type_ticket}) INNER JOIN {db_prefix}helpdesk_custom_fields AS hdcf ON (hdcf.id_field = hdcfv.id_field AND hdcf.active = {int:active})'; $context['filter_where'] = ' AND hdcfv.value = {string:filter}'; } else { $context['filter_fragment'] = ''; $context['filter_join'] = ''; $context['filter_where'] = ''; } // Now go actually do the whole block thang, setting up space for a list of users and tickets as we go along $users = array(); $tickets = array(); foreach ($context['ticket_blocks'] as $block_key => $block) { if (empty($block['display']) || !empty($block['collapsed'])) { continue; } $context['ticket_blocks'][$block_key]['tickets'] = array(); // If we're filtering, we have to query it first to figure out how many rows there are in this block. It's not pretty. if (!empty($context['filter_join'])) { $query = shd_db_query('', ' SELECT COUNT(hdt.id_ticket) FROM {db_prefix}helpdesk_tickets AS hdt INNER JOIN {db_prefix}helpdesk_ticket_replies AS hdtr_first ON (hdt.id_first_msg = hdtr_first.id_msg) INNER JOIN {db_prefix}helpdesk_ticket_replies AS hdtr_last ON (hdt.id_last_msg = hdtr_last.id_msg) INNER JOIN {db_prefix}helpdesk_depts AS hdd ON (hdt.id_dept = hdd.id_dept) ' . (!empty($block['sort']['sql']['join']) ? $block['sort']['sql']['join'] : '') . $context['filter_join'] . ' WHERE {query_see_ticket}' . (!empty($block['where']) ? ' AND ' . $block['where'] : '') . (!empty($context['shd_department']) ? ' AND hdt.id_dept = {int:dept}' : '') . $context['filter_where'], array('dept' => $context['shd_department'], 'user' => $context['user']['id'], 'field' => $_REQUEST['field'], 'filter' => $_REQUEST['filter'], 'type_ticket' => CFIELD_TICKET, 'active' => 1)); list($context['ticket_blocks'][$block_key]['count']) = $smcFunc['db_fetch_row']($query); $block['count'] = $context['ticket_blocks'][$block_key]['count']; $smcFunc['db_free_result']($query); if ($block['start'] >= $block['count']) { $context['ticket_blocks'][$block_key]['start'] = max(0, (int) $block['count'] - ((int) $block['count'] % (int) $block['num_per_page'] == 0 ? $block['num_per_page'] : (int) $block['count'] % (int) $block['num_per_page'])); $block['start'] = $context['ticket_blocks'][$block_key]['start']; } } $query = shd_db_query('', ' SELECT hdt.id_ticket, hdt.id_dept, hdd.dept_name, hdt.id_last_msg, hdt.id_member_started, hdt.id_member_updated, hdt.id_member_assigned, hdt.subject, hdt.status, hdt.num_replies, hdt.deleted_replies, hdt.private, hdt.urgency, hdt.last_updated, hdtr_first.poster_name AS ticket_opener, hdtr_last.poster_name AS respondent, hdtr_last.poster_time, IFNULL(hdlr.id_msg, 0) AS log_read' . (!empty($block['sort']['sql']['select']) ? ', ' . $block['sort']['sql']['select'] : '') . ' FROM {db_prefix}helpdesk_tickets AS hdt INNER JOIN {db_prefix}helpdesk_ticket_replies AS hdtr_first ON (hdt.id_first_msg = hdtr_first.id_msg) INNER JOIN {db_prefix}helpdesk_ticket_replies AS hdtr_last ON (hdt.id_last_msg = hdtr_last.id_msg) INNER JOIN {db_prefix}helpdesk_depts AS hdd ON (hdt.id_dept = hdd.id_dept) LEFT JOIN {db_prefix}helpdesk_log_read AS hdlr ON (hdt.id_ticket = hdlr.id_ticket AND hdlr.id_member = {int:user}) ' . (!empty($block['sort']['sql']['join']) ? $block['sort']['sql']['join'] : '') . $context['filter_join'] . ' WHERE {query_see_ticket}' . (!empty($block['where']) ? ' AND ' . $block['where'] : '') . (!empty($context['shd_department']) ? ' AND hdt.id_dept = {int:dept}' : '') . $context['filter_where'] . ' ORDER BY ' . (!empty($block['sort']['sql']['sort']) ? $block['sort']['sql']['sort'] : 'hdt.id_last_msg ASC') . ' LIMIT {int:start}, {int:items_per_page}', array('dept' => $context['shd_department'], 'user' => $context['user']['id'], 'start' => $block['start'], 'items_per_page' => $block['num_per_page'], 'field' => $_REQUEST['field'], 'filter' => $_REQUEST['filter'], 'type_ticket' => CFIELD_TICKET, 'active' => 1)); while ($row = $smcFunc['db_fetch_assoc']($query)) { $is_own = $user_info['id'] == $row['id_member_started']; censorText($row['subject']); $new_block = array('id' => $row['id_ticket'], 'display_id' => str_pad($row['id_ticket'], $modSettings['shd_zerofill'], '0', STR_PAD_LEFT), 'dept_link' => empty($context['shd_department']) && $context['shd_multi_dept'] ? '[<a href="' . $scripturl . '?' . $context['shd_home'] . ';dept=' . $row['id_dept'] . '">' . $row['dept_name'] . '</a>] ' : '', 'link' => '<a href="' . $scripturl . '?action=helpdesk;sa=ticket;ticket=' . $row['id_ticket'] . ($_REQUEST['sa'] == 'recyclebin' ? ';recycle' : '') . '">' . $row['subject'] . '</a>', 'subject' => $row['subject'], 'status' => array('level' => $row['status'], 'label' => $txt['shd_status_' . $row['status']]), 'starter' => array('id' => $row['id_member_started'], 'name' => $row['ticket_opener']), 'last_update' => timeformat($row['last_updated']), 'assigned' => array('id' => $row['id_member_assigned']), 'respondent' => array('id' => $row['id_member_updated'], 'name' => $row['respondent']), 'urgency' => array('level' => $row['urgency'], 'label' => $row['urgency'] > TICKET_URGENCY_HIGH ? '<span class="error">' . $txt['shd_urgency_' . $row['urgency']] . '</span>' : $txt['shd_urgency_' . $row['urgency']]), 'is_unread' => $row['id_last_msg'] > $row['log_read'], 'new_href' => $row['id_last_msg'] <= $row['log_read'] ? '' : $scripturl . '?action=helpdesk;sa=ticket;ticket=' . $row['id_ticket'] . '.new' . ($_REQUEST['sa'] == 'recyclebin' ? ';recycle' : '') . '#new', 'private' => $row['private'], 'actions' => array('movedept' => !empty($context['shd_multi_dept']) && (shd_allowed_to('shd_move_dept_any', $context['shd_department']) || $is_own && shd_allowed_to('shd_move_dept_own', $context['shd_department'])) ? '<a href="' . $scripturl . '?action=helpdesk;sa=movedept;ticket=' . $row['id_ticket'] . ';home;' . $context['session_var'] . '=' . $context['session_id'] . '" title="' . $txt['shd_move_dept'] . '"><img src="' . $settings['default_images_url'] . '/simpledesk/movedept.png" alt="' . $txt['shd_move_dept'] . '" /></a>' : ''), 'num_replies' => $row['num_replies'], 'replies_href' => $scripturl . '?action=helpdesk;sa=ticket;ticket=' . $row['id_ticket'] . '.msg' . $row['id_last_msg'] . '#msg' . $row['id_last_msg'] . ($_REQUEST['sa'] == 'recyclebin' ? ';recycle' : ''), 'all_replies' => (int) $row['num_replies'] + (int) $row['deleted_replies']); if ($row['status'] == TICKET_STATUS_CLOSED) { $new_block['actions'] += array('resolve' => shd_allowed_to('shd_unresolve_ticket_any', $context['shd_department']) || $is_own && shd_allowed_to('shd_unresolve_ticket_own', $context['shd_department']) ? '<a href="' . $scripturl . '?action=helpdesk;sa=resolveticket;ticket=' . $row['id_ticket'] . ';home;' . $context['shd_dept_link'] . $context['session_var'] . '=' . $context['session_id'] . '" title="' . $txt['shd_ticket_unresolved'] . '"><img src="' . $settings['default_images_url'] . '/simpledesk/unresolved.png" alt="' . $txt['shd_ticket_unresolved'] . '" /></a>' : ''); } elseif ($row['status'] == TICKET_STATUS_DELETED) { $new_block['actions'] += array('restore' => shd_allowed_to('shd_restore_ticket_any', $context['shd_department']) || $is_own && shd_allowed_to('shd_restore_ticket_own', $context['shd_department']) ? '<a href="' . $scripturl . '?action=helpdesk;sa=restoreticket;ticket=' . $row['id_ticket'] . ';home;' . $context['shd_dept_link'] . $context['session_var'] . '=' . $context['session_id'] . '" title="' . $txt['shd_ticket_restore'] . '"><img src="' . $settings['default_images_url'] . '/simpledesk/restore.png" alt="' . $txt['shd_ticket_restore'] . '" /></a>' : '', 'permadelete' => shd_allowed_to('shd_delete_recycling', $context['shd_department']) ? '<a href="' . $scripturl . '?action=helpdesk;sa=permadelete;ticket=' . $row['id_ticket'] . ';' . $context['session_var'] . '=' . $context['session_id'] . '" title="' . $txt['shd_delete_permanently'] . '" onclick="return confirm(' . JavaScriptEscape($txt['shd_delete_permanently_confirm']) . ');"><img src="' . $settings['default_images_url'] . '/simpledesk/delete.png" alt="' . $txt['shd_delete_permanently'] . '" /></a>' : ''); } else { $langstring = ''; if (shd_allowed_to('shd_assign_ticket_any', $context['shd_department'])) { $langstring = empty($row['id_member_assigned']) ? $txt['shd_ticket_assign'] : $txt['shd_ticket_reassign']; } elseif (shd_allowed_to('shd_assign_ticket_own', $context['shd_department']) && (empty($row['id_member_assigned']) || $row['id_member_assigned'] == $context['user']['id'])) { $langstring = $row['id_member_assigned'] == $context['user']['id'] ? $txt['shd_ticket_unassign'] : $txt['shd_ticket_assign_self']; } if (!empty($langstring)) { $new_block['actions']['assign'] = '<a href="' . $scripturl . '?action=helpdesk;sa=assign;ticket=' . $row['id_ticket'] . ';home;' . $context['session_var'] . '=' . $context['session_id'] . '" title="' . $langstring . '"><img src="' . $settings['default_images_url'] . '/simpledesk/assign.png" alt="' . $langstring . '" /></a>'; } $new_block['actions'] += array('resolve' => shd_allowed_to('shd_resolve_ticket_any', $context['shd_department']) || $is_own && shd_allowed_to('shd_resolve_ticket_own', $context['shd_department']) ? '<a href="' . $scripturl . '?action=helpdesk;sa=resolveticket;ticket=' . $row['id_ticket'] . ';home;' . $context['shd_dept_link'] . $context['session_var'] . '=' . $context['session_id'] . '" title="' . $txt['shd_ticket_resolved'] . '"><img src="' . $settings['default_images_url'] . '/simpledesk/resolved.png" alt="' . $txt['shd_ticket_resolved'] . '" /></a>' : '', 'tickettotopic' => empty($modSettings['shd_helpdesk_only']) && shd_allowed_to('shd_ticket_to_topic', $context['shd_department']) && ($row['deleted_replies'] == 0 || shd_allowed_to('shd_access_recyclebin')) ? '<a href="' . $scripturl . '?action=helpdesk;sa=tickettotopic;ticket=' . $row['id_ticket'] . ';' . $context['shd_dept_link'] . $context['session_var'] . '=' . $context['session_id'] . '" title="' . $txt['shd_ticket_move_to_topic'] . '"><img src="' . $settings['default_images_url'] . '/simpledesk/tickettotopic.png" alt="' . $txt['shd_ticket_move_to_topic'] . '" /></a>' : '', 'delete' => shd_allowed_to('shd_delete_ticket_any', $context['shd_department']) || $is_own && shd_allowed_to('shd_delete_ticket_own') ? '<a href="' . $scripturl . '?action=helpdesk;sa=deleteticket;ticket=' . $row['id_ticket'] . ';' . $context['shd_dept_link'] . ';' . $context['session_var'] . '=' . $context['session_id'] . '" title="' . $txt['shd_ticket_delete'] . '" onclick="return confirm(' . JavaScriptEscape($txt['shd_delete_confirm']) . ');"><img src="' . $settings['default_images_url'] . '/simpledesk/delete.png" alt="' . $txt['shd_ticket_delete'] . '" /></a>' : ''); } $context['ticket_blocks'][$block_key]['tickets'][$row['id_ticket']] = $new_block; $users[] = $row['id_member_started']; $users[] = $row['id_member_updated']; $users[] = $row['id_member_assigned']; $tickets[$row['id_ticket']] = array(); } $smcFunc['db_free_result']($query); } $users = array_unique($users); if (!empty($users)) { loadMemberData($users, false, 'minimal'); } foreach ($context['ticket_blocks'] as $block_id => $block) { if (empty($block['tickets'])) { continue; } foreach ($block['tickets'] as $tid => $ticket) { // Set up names and profile links for topic starter if (!empty($user_profile[$ticket['starter']['id']])) { // We found the name, so let's use their current name and profile link $context['ticket_blocks'][$block_id]['tickets'][$tid]['starter']['name'] = $user_profile[$ticket['starter']['id']]['real_name']; $context['ticket_blocks'][$block_id]['tickets'][$tid]['starter']['link'] = shd_profile_link($user_profile[$ticket['starter']['id']]['real_name'], $ticket['starter']['id']); } else { // We didn't, so keep using the name we found previously and don't make an actual link $context['ticket_blocks'][$block_id]['tickets'][$tid]['starter']['link'] = $context['ticket_blocks'][$block_id]['tickets'][$tid]['starter']['name']; } // Set up names and profile links for assigned user if ($ticket['assigned']['id'] == 0 || empty($user_profile[$ticket['assigned']['id']])) { $context['ticket_blocks'][$block_id]['tickets'][$tid]['assigned']['name'] = $txt['shd_unassigned']; $context['ticket_blocks'][$block_id]['tickets'][$tid]['assigned']['link'] = '<span class="error">' . $txt['shd_unassigned'] . '</span>'; } else { $context['ticket_blocks'][$block_id]['tickets'][$tid]['assigned']['name'] = $user_profile[$ticket['assigned']['id']]['real_name']; $context['ticket_blocks'][$block_id]['tickets'][$tid]['assigned']['link'] = shd_profile_link($user_profile[$ticket['assigned']['id']]['real_name'], $ticket['assigned']['id']); } // And last respondent if ($ticket['respondent']['id'] == 0 || empty($user_profile[$ticket['respondent']['id']])) { // Didn't find the name, so reuse what we have $context['ticket_blocks'][$block_id]['tickets'][$tid]['respondent']['link'] = $context['ticket_blocks'][$block_id]['tickets'][$tid]['respondent']['name']; } else { $context['ticket_blocks'][$block_id]['tickets'][$tid]['respondent']['name'] = $user_profile[$ticket['respondent']['id']]['real_name']; $context['ticket_blocks'][$block_id]['tickets'][$tid]['respondent']['link'] = shd_profile_link($user_profile[$ticket['respondent']['id']]['real_name'], $ticket['respondent']['id']); } } } foreach ($context['ticket_blocks'] as $block_id => $block) { if (empty($block['display']) || empty($block['count']) && !$block['required'] && empty($block['collapsed'])) { unset($context['ticket_blocks'][$block_id]); } } $base_url = ''; foreach ($context['ticket_blocks'] as $block_id => $block) { if ($block['sort']['add_link']) { $base_url .= $block['sort']['link_bits'][$block['sort']['item']]; } } if ($_REQUEST['sa'] != 'viewblock') { foreach ($context['ticket_blocks'] as $block_id => $block) { $num_per_page = !empty($context['shd_preferences']['blocks_' . $block_key . '_count']) ? $context['shd_preferences']['blocks_' . $block_key . '_count'] : $context['items_per_page']; $url_fragment = $base_url; foreach ($block_list as $block_item) { if ($block_item == $block_id) { $url_fragment .= ';st_' . $block_item . '=%1$d'; } elseif (!empty($context['ticket_blocks'][$block_item]['start'])) { $url_fragment .= ';st_' . $block_item . '=' . $context['ticket_blocks'][$block_item]['start']; } } $context['start'] = $context['ticket_blocks'][$block_id]['start']; $context['ticket_blocks'][$block_id]['page_index'] = shd_no_expand_pageindex($scripturl . $primary_url . $url_fragment . $context['shd_dept_link'] . $context['filter_fragment'] . '#shd_block_' . $block_id, $context['start'], $block['count'], $block['num_per_page'], true); } } // Just need to deal with those pesky prefix fields, if there are any. if (empty($tickets)) { return; } // We're all done here. // 1. Figure out if there are any custom fields that apply to us or not. if ($context['shd_multi_dept'] && empty($context['shd_department'])) { $dept_list = shd_allowed_to('access_helpdesk', false); } else { $dept_list = array($context['shd_department']); } $fields = array(); $query = $smcFunc['db_query']('', ' SELECT hdcf.id_field, can_see, field_type, field_options, placement, field_name FROM {db_prefix}helpdesk_custom_fields AS hdcf INNER JOIN {db_prefix}helpdesk_custom_fields_depts AS hdcfd ON (hdcfd.id_field = hdcf.id_field) WHERE placement IN ({array_int:placement_prefix}) AND field_loc IN ({array_int:locations}) AND hdcfd.id_dept IN ({array_int:dept_list}) AND active = {int:active} GROUP BY hdcf.id_field ORDER BY field_order', array('locations' => array(CFIELD_TICKET, CFIELD_TICKET | CFIELD_REPLY), 'placement_prefix' => array(CFIELD_PLACE_PREFIX, CFIELD_PLACE_PREFIXFILTER), 'active' => 1, 'dept_list' => $dept_list)); $is_staff = shd_allowed_to('shd_staff', $context['shd_department']); $is_admin = $context['user']['is_admin'] || shd_allowed_to('admin_helpdesk', $context['shd_department']); $context['shd_filter_fields'] = array(); while ($row = $smcFunc['db_fetch_assoc']($query)) { list($user_see, $staff_see) = explode(',', $row['can_see']); if ($is_admin || $is_staff && $staff_see == '1' || !$is_staff && $user_see == '1') { if (!empty($row['field_options'])) { $row['field_options'] = unserialize($row['field_options']); if (isset($row['field_options']['inactive'])) { unset($row['field_options']['inactive']); } foreach ($row['field_options'] as $k => $v) { if (strpos($v, '[') !== false) { $row['field_options'][$k] = parse_bbc($v); } } } $fields[$row['id_field']] = $row; if ($row['placement'] == CFIELD_PLACE_PREFIXFILTER) { $context['shd_filter_fields'][$row['id_field']] = array('name' => $row['field_name'], 'options' => $row['field_options'], 'in_use' => array()); } } } $smcFunc['db_free_result']($query); if (empty($fields)) { return; } // No fields to process, time to go. // 2. Get the relevant values. $query = $smcFunc['db_query']('', ' SELECT id_post, id_field, value FROM {db_prefix}helpdesk_custom_fields_values WHERE id_post IN ({array_int:tickets}) AND id_field IN ({array_int:fields}) AND post_type = {int:ticket}', array('tickets' => array_keys($tickets), 'fields' => array_keys($fields), 'ticket' => CFIELD_TICKET)); while ($row = $smcFunc['db_fetch_assoc']($query)) { $tickets[$row['id_post']][$row['id_field']] = $row['value']; } // 3. Apply the values into the tickets. if ($_REQUEST['sa'] == 'closedtickets') { $context['filterbase'] = $scripturl . '?action=helpdesk;sa=closedtickets'; } elseif ($_REQUEST['sa'] == 'recyclebin') { $context['filterbase'] = $scripturl . '?action=helpdesk;sa=recyclebin'; } else { $context['filterbase'] = $scripturl . '?' . $context['shd_home']; } foreach ($context['ticket_blocks'] as $block_id => $block) { if (empty($block['tickets'])) { continue; } foreach ($block['tickets'] as $ticket_id => $ticket) { if (isset($tickets[$ticket_id])) { $prefix_filter = ''; $prefix = ''; foreach ($fields as $field_id => $field) { if (empty($tickets[$ticket_id][$field_id])) { continue; } if ($field['placement'] == CFIELD_PLACE_PREFIXFILTER) { if (!isset($field['field_options'][$tickets[$ticket_id][$field_id]])) { continue; } $prefix_filter .= '[<a href="' . $context['filterbase'] . $context['shd_dept_link'] . ';field=' . $field_id . ';filter=' . $tickets[$ticket_id][$field_id] . '">' . $field['field_options'][$tickets[$ticket_id][$field_id]] . '</a>] '; } else { if ($field['field_type'] == CFIELD_TYPE_CHECKBOX) { $prefix .= !empty($tickets[$ticket_id][$field_id]) ? $txt['yes'] . ' ' : $txt['no'] . ' '; } elseif ($field['field_type'] == CFIELD_TYPE_SELECT || $field['field_type'] == CFIELD_TYPE_RADIO) { $prefix .= $field['field_options'][$tickets[$ticket_id][$field_id]] . ' '; } elseif ($field['field_type'] == CFIELD_TYPE_MULTI) { $values = explode(',', $tickets[$ticket_id][$field_id]); foreach ($values as $value) { $prefix .= $field['field_options'][$value] . ' '; } } else { $prefix .= $tickets[$ticket_id][$field_id] . ' '; } } } // First, set aside the subject, and if there is a non category prefix, strip links from it. $subject = $ticket['subject']; if (!empty($prefix)) { $prefix = '[' . trim(preg_replace('~<a (.*?)</a>~is', '', $prefix)) . '] '; } // Then, if we have a category prefix, prepend that to any other prefix we have. if (!empty($prefix_filter)) { $prefix = $prefix_filter . $prefix; } // Lastly, if we have some kind of prefix to put in front of this ticket, do so. if (!empty($prefix)) { $context['ticket_blocks'][$block_id]['tickets'][$ticket_id]['subject'] = $prefix . $subject; $context['ticket_blocks'][$block_id]['tickets'][$ticket_id]['link'] = $prefix . '<a href="' . $scripturl . '?action=helpdesk;sa=ticket;ticket=' . $ticket_id . ($_REQUEST['sa'] == 'recyclebin' ? ';recycle' : '') . '">' . $subject . '</a>'; } } } } // 4. We've collected the list of prefix-filter fields in use, now establish which values are actually in use. if (!empty($context['shd_filter_fields'])) { $query = $smcFunc['db_query']('', ' SELECT id_field, value FROM {db_prefix}helpdesk_custom_fields_values WHERE id_field IN ({array_int:fields})', array('fields' => array_keys($context['shd_filter_fields']))); while ($row = $smcFunc['db_fetch_assoc']($query)) { $context['shd_filter_fields'][$row['id_field']]['in_use'][$row['value']] = true; } $smcFunc['db_free_result']($query); foreach ($context['shd_filter_fields'] as $id_field => $field) { if (empty($field['in_use'])) { unset($context['shd_filter_fields'][$id_field]); } else { foreach ($field['options'] as $k => $v) { if (!isset($field['in_use'][$k])) { unset($context['shd_filter_fields'][$id_field]['options'][$k]); } } if (empty($context['shd_filter_fields'][$id_field]['options'])) { unset($context['shd_filter_fields'][$id_field]); } } } } }
/** * Gets tickets based on supplied criteria; this is a helper function not really intended to be called directly. * * @todo Finish writing and documenting this function. * @param string $query_where SQL clauses to be supplied to the query in addition to {query_see_ticket} - note 'AND' is not required at the start. * @param array $query_where_params Key/value associative array to be injected into the query, related to $query_where. * @param int $query_limit Number of items to limit the query to. * @param string $query_order The clause to order tickets by, defaults to tickets by order of creation. * @return array An array of arrays, each primary item containing the following: * <ul> * <li>id: Main ticket id</li> * <li>display_id: Formatted ticket id in [0000x] format</li> * <li>subject: Ticket subject</li> * <li>short_subject: Shortened version of ticket subject</li> * <li>href: Ticket href</li> * <li>opener: array of details about the ticket starter: * <ul> * <li>id: user id of the person who opened the ticket</li> * <li>name: username of the person who opened the ticket</li> * <li>link: link to the profile of the person who opened the ticket</li> * </ul> * </li> * <li>replier: array of details about the last person to reply to the ticket: * <ul> * <li>id: user id of the last person to reply to the ticket</li> * <li>name: username of the last person to reply to the ticket</li> * <li>link: link to the profile of the last person to reply to the ticket</li> * </ul> * </li> * <li>assigned: array of details about the person who the ticket is assigned to: * <ul> * <li>id: user id of the person who the ticket is assigned to</li> * <li>name: username of the person who the ticket is assigned to or 'Unassigned' otherwise</li> * <li>link: link to the profile of the person who the ticket is assigned to or 'Unassigned' otherwise</li> * </ul> * </li> * <li>num_replies: Number of replies in the ticket</li> * <li>start_time: Formatted string of time the ticket was opened</li> * <li>start_timestamp: Raw timestamp (adjusted for timezones) of ticket being opened</li> * <li>last_time: Formatted string of time the ticket was last replied to</li> * <li>last_timestamp: Raw timestamp (adjusted for timezones) of ticket's last reply</li> * <li>private: Whether the ticket is private or not</li> * <li>urgency_id: Number representing ticket urgency</li> * <li>urgency_string: String representing ticket urgency</li> * <li>status_id: Number representing ticket status</li> * <li>status_text: String representing ticket status</li> * <li>department: Number representing ticket department ID</li> * </ul> * @since 2.0 */ function ssi_getSDTickets($query_where, $query_where_params = array(), $query_limit = 0, $query_order = 'hdt.id_ticket ASC', $output_method = 'echo') { global $smcFunc, $scripturl, $txt, $modSettings; $query_limit = (int) $query_limit; $query = shd_db_query('', ' SELECT hdt.id_ticket, hdt.subject, hdt.num_replies, hdt.private, hdt.urgency, hdt.status, hdt.dept, hdtr_first.poster_time AS start_time, hdt.last_updated AS last_time, IFNULL(mem.real_name, hdtr_first.poster_name) AS starter_name, IFNULL(mem.id_member, 0) AS starter_id, IFNULL(ma.real_name, 0) AS assigned_name, IFNULL(ma.id_member, 0) AS assigned_id, IFNULL(mm.real_name, hdtr_last.modified_name) AS modified_name, IFNULL(mm.id_member, 0) AS modified_id FROM {db_prefix}helpdesk_tickets AS hdt INNER JOIN {db_prefix}helpdesk_ticket_replies AS hdtr_first ON (hdt.id_first_msg = hdtr_first.id_msg) INNER JOIN {db_prefix}helpdesk_ticket_replies AS hdtr_last ON (hdt.id_last_msg = hdtr_last.id_msg) LEFT JOIN {db_prefix}members AS mem ON (hdt.id_member_started = mem.id_member) LEFT JOIN {db_prefix}members AS ma ON (hdt.id_member_assigned = ma.id_member) LEFT JOIN {db_prefix}members AS mm ON (hdt.id_member_updated = mm.id_member) WHERE {query_see_ticket} AND ' . $query_where . ' ORDER BY ' . $query_order . ' ' . ($query_limit == 0 ? '' : 'LIMIT ' . $query_limit), array_merge($query_where_params, array())); $tickets = array(); while ($row = $smcFunc['db_fetch_assoc']($query)) { censorText($row['subject']); $tickets[] = array('id' => $row['id_ticket'], 'display_id' => str_pad($row['id_ticket'], $modSettings['shd_zerofill'], '0', STR_PAD_LEFT), 'subject' => $row['subject'], 'short_subject' => shorten_subject($row['subject'], 25), 'href' => $scripturl . '?action=helpdesk;sa=ticket;ticket=' . $row['id_ticket'], 'opener' => array('id' => $row['starter_id'], 'name' => $row['starter_name'], 'link' => shd_profile_link($row['starter_name'], $row['starter_id'])), 'replier' => array('id' => $row['modified_id'], 'name' => $row['modified_name'], 'link' => shd_profile_link($row['modified_name'], $row['modified_id'])), 'assigned' => array('id' => $row['assigned_id'], 'name' => empty($row['assigned_name']) ? $txt['shd_unassigned'] : $row['assigned_name'], 'link' => empty($row['assigned_name']) ? '<span class="error">' . $txt['shd_unassigned'] . '</span>' : shd_profile_link($row['assigned_name'], $row['assigned_id'])), 'start_time' => timeformat($row['start_time']), 'start_timestamp' => forum_time(true, $row['start_time']), 'last_time' => timeformat($row['last_time']), 'last_timestamp' => forum_time(true, $row['last_time']), 'num_replies' => $row['num_replies'], 'private' => !empty($row['private']), 'urgency_id' => $row['urgency'], 'urgency_string' => $txt['shd_urgency_' . $row['urgency']], 'status_id' => $row['status'], 'status_text' => $txt['shd_status_' . $row['status']], 'department' => $row['dept']); } $smcFunc['db_free_result']($query); if (empty($tickets) || $output_method != 'echo') { return $tickets; } // output this stuff echo ' <table border="0" class="ssi_table">'; foreach ($tickets as $ticket) { echo ' <tr> <td align="right" valign="top" nowrap="nowrap"> [', $ticket['status_text'], '] </td> <td valign="top"> <a href="', $ticket['href'], '">', $ticket['subject'], '</a> ', $txt['by'], ' ', $ticket['replier']['link'], ' </td> <td align="right" nowrap="nowrap"> ', $ticket['last_time'], ' </td> </tr>'; } echo ' </table>'; }
function shd_format_notify_name(&$user_name, $user_id, $ticket_starter) { global $txt; $user_name = shd_profile_link($user_name, $user_id) . ($user_id == $ticket_starter ? $txt['shd_is_ticket_opener'] : ''); }
function template_search_results() { global $context, $txt, $scripturl, $settings, $modSettings, $smcFunc; // Back to the helpdesk. echo ' <div class="floatleft"> ', template_button_strip(array($context['navigation']['back'], $context['navigation']['search']), 'bottom'), ' </div><br class="clear" /><br />'; echo ' <div class="cat_bar"> <h3 class="catbg"> <img src="', $settings['default_images_url'], '/simpledesk/search.png" alt="*" /> ', $txt['shd_search_results'], ' </h3> </div>'; // Page navigation. It's not your usual page index, and with good reason: we can't use regular links here without risking server hammering. $num_pages = ceil($context['num_results'] / $context['search_params']['limit']); $pages = array(); for ($page = $context['numpage'] - 2; $page <= $context['numpage'] + 2; $page++) { $pages[] = $page; } // The rest of it would go here, in a nice form that carried everything through for next time, with a button named page whose value would be the page number for each page (plus prev/next) you wanted to display // Search criteria template_search_criteria(); // And finally, the results themselves. $use_bg2 = false; foreach ($context['search_results'] as $index => $result) { echo ' <div class="search_results_posts"> <div class="windowbg', $use_bg2 ? '2' : '', ' core_posts"> <span class="topslice"><span></span></span> <div class="content flow_auto"> <div class="topic_details floatleft" style="width: 94%"> <div class="counter">', $result['result'], '</div> <h5>', $result['dept_link'], '<a href="', $scripturl, '?action=helpdesk;sa=ticket;ticket=', $result['id_ticket'], '">', sprintf($result['is_ticket'] ? $txt['shd_search_result_ticket'] : $txt['shd_search_result_reply'], $result['display_id']), '</a> - ', $result['subject'], ' (', $txt['shd_search_last_updated'], ' ', timeformat($result['last_updated']), ')</h5> <span class="smalltext">« <strong>', $result['is_ticket'] ? $txt['shd_search_ticket_opened_by'] : $txt['shd_search_ticket_replied_by'], ' ', shd_profile_link($result['poster_name'], $result['id_member']), '</strong> ', $txt['on'], ' <em>', timeformat($result['poster_time']), '</em> »</span> </div> <br class="clear"> <div class="list_posts double_height">', $result['body'], '</div> </div> <span class="botslice"><span></span></span> </div> </div>'; $use_bg2 = !$use_bg2; } }
function shd_list_get_ip_messages($start, $items_per_page, $sort, $where, $where_vars = array()) { global $smcFunc, $txt, $scripturl; $query = shd_db_query('', ' SELECT hdtr.id_msg, hdtr.poster_ip, IFNULL(mem.real_name, hdtr.poster_name) AS display_name, mem.id_member, hdt.subject, hdtr.poster_time, hdt.id_ticket, hdt.id_first_msg FROM {db_prefix}helpdesk_ticket_replies AS hdtr INNER JOIN {db_prefix}helpdesk_tickets AS hdt ON (hdtr.id_ticket = hdt.id_ticket) LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = hdtr.id_member) WHERE {query_see_ticket} AND ' . $where . ' ORDER BY ' . $sort . ' LIMIT ' . $start . ', ' . $items_per_page, array_merge($where_vars, array())); $messages = array(); while ($row = $smcFunc['db_fetch_assoc']($query)) { $messages[] = array('ip' => $row['poster_ip'], 'member_link' => shd_profile_link($row['display_name'], $row['id_member']), 'ticket' => $row['id_ticket'], 'id' => $row['id_msg'], 'subject' => $row['subject'], 'time' => timeformat($row['poster_time']), 'timestamp' => forum_time(true, $row['poster_time']), 'additional' => $row['id_first_msg'] == $row['id_msg'] ? $txt['shd_is_ticket_opener'] : ''); } $smcFunc['db_free_result']($query); return $messages; }
/** * Display all the replies to a ticket. * * This function deals simply with viewing of replies in a ticket, including deleted replies, which is initialised in {@link shd_view_ticket()} * and data gathered through the {@link shd_prepare_ticket_context()} call back, which simply deals with a single reply at a time. * * @see shd_view_ticket() * @see template_viewticket() * @since 1.0 */ function template_viewreplies() { global $context, $settings, $txt, $scripturl, $options, $modSettings, $reply_request; echo ' <div class="tborder"> <div class="title_bar grid_header"> <h3 class="titlebg"> <span class="floatright smalltext">', $txt['pages'], ': ', $context['page_index'], '</span> <img src="', $settings['default_images_url'], '/simpledesk/replies.png" alt="x" /> ', $txt['shd_ticket_replies'], ' </h3> </div> <div class="roundframe" id="replies"> <div class="content">'; if (empty($reply_request)) { echo $txt['shd_no_replies']; } else { while ($reply = $context['get_replies']()) { if (!empty($reply['is_new'])) { echo ' <a id="new"></a>'; } echo ' <div class="description shd_reply', !empty($context['ticket']['display_recycle']) && $reply['message_status'] == MSG_STATUS_DELETED ? ' errorbox' : '', '" id="msg', $reply['id'], '"> <span class="floatleft shd_posterinfo"> <strong class="shd_postername"> ', $reply['member']['link'], ' </strong> <br /> ', $reply['member']['group'], '<br class="shd_groupmargin" />'; if (!empty($modSettings['shd_display_avatar']) && empty($options['show_no_avatars']) && !empty($reply['member']['avatar']['image'])) { echo ' <span class="shd_posteravatar"> ', shd_profile_link($reply['member']['avatar']['image'], $reply['member']['id']), ' </span>'; } if ($modSettings['shd_staff_badge'] == (!empty($reply['is_staff']) ? 'staffbadge' : 'userbadge') || $modSettings['shd_staff_badge'] == 'bothbadge') { echo '<br /> ', $reply['member']['group_stars']; } elseif (!empty($reply['is_staff']) && $modSettings['shd_staff_badge'] == 'nobadge') { echo '<br /> <img src="', $settings['default_images_url'] . '/simpledesk/staff.png" class="shd_smallicon" title="', $txt['shd_ticket_staff'], '" alt="', $txt['shd_ticket_staff'], '" />'; } echo ' </span> <div class="shd_replyarea"> <div class="smalltext"> <span class="floatright shd_ticketlinks">'; if ($context['can_quote']) { echo ' <img src="', $settings['default_images_url'], '/simpledesk/quote.png" class="shd_smallicon" alt="*" /><a onclick="return oQuickReply.quote(', $reply['id'], ', \'', $context['session_id'], '\', \'', $context['session_var'], '\', true);" href="', $scripturl, '?action=helpdesk;sa=reply;ticket=', $context['ticket_id'], ';quote=', $reply['id'], ';', $context['session_var'], '=', $context['session_id'], '">', $txt['shd_ticket_quote_short'], '</a>'; } if ($reply['can_edit']) { echo ' <img src="', $settings['default_images_url'], '/simpledesk/edit.png" class="shd_smallicon" alt="*" /><a href="', $scripturl, '?action=helpdesk;sa=editreply;ticket=', $context['ticket_id'], ';msg=', $reply['id'], ';', $context['session_var'], '=', $context['session_id'], '">', $txt['shd_ticket_edit'], '</a>'; } if ($reply['can_delete']) { echo ' <img src="', $settings['default_images_url'], '/simpledesk/delete.png" class="shd_smallicon" alt="*" /><a href="', $scripturl, '?action=helpdesk;sa=deletereply;reply=', $reply['id'], ';ticket=', $context['ticket']['id'], ';', $context['session_var'], '=', $context['session_id'], '" onclick="return confirm(', JavaScriptEscape($txt['shd_delete_reply_confirm']), ');">', $txt['shd_ticket_delete'], '</a>'; } if ($reply['can_restore']) { echo ' <img src="', $settings['default_images_url'], '/simpledesk/restore.png" class="shd_smallicon" alt="*" /><a href="', $scripturl, '?action=helpdesk;sa=restorereply;reply=', $reply['id'], ';ticket=', $context['ticket']['id'], ';', $context['session_var'], '=', $context['session_id'], '">', $txt['shd_ticket_restore'], '</a>'; } if ($reply['can_permadelete']) { echo ' <img src="', $settings['default_images_url'], '/simpledesk/delete.png" class="shd_smallicon" alt="*" /><a href="', $scripturl, '?action=helpdesk;sa=permadelete;reply=', $reply['id'], ';ticket=', $context['ticket']['id'], ';', $context['session_var'], '=', $context['session_id'], '" onclick="return confirm(', JavaScriptEscape($txt['shd_delete_permanently_confirm']), ');">', $txt['shd_delete_permanently'], '</a>'; } echo ' </span> <a href="', $reply['link'], '">', sprintf($txt['shd_reply_written'], $reply['time']), '</a> </div> <hr /> ', $reply['body'], ' <br /><br />'; // Custom fields for replies! if (!empty($context['custom_fields_replies'][$reply['id']])) { echo ' <hr />'; foreach ($context['custom_fields_replies'][$reply['id']] as $field) { if ($field['display_empty'] || !empty($field['value']) || $field['type'] == CFIELD_TYPE_CHECKBOX) { echo ' ', !empty($field['icon']) ? '<img src="' . $settings['default_images_url'] . '/simpledesk/cf/' . $field['icon'] . '" alt="" class="shd_smallicon" />' : '', ' <strong>', $field['name'], ': </strong>'; if ($field['type'] == CFIELD_TYPE_CHECKBOX) { echo !empty($field['value']) ? $txt['yes'] : $txt['no'], '<br /><br />'; } elseif (empty($field['value']) && $field['display_empty']) { echo $txt['shd_ticket_empty_field'], '<br /><br />'; } else { if ($field['type'] == CFIELD_TYPE_SELECT || $field['type'] == CFIELD_TYPE_RADIO) { echo $field['options'][$field['value']], '<br /><br />'; } elseif ($field['type'] == CFIELD_TYPE_MULTI) { $values = explode(',', $field['value']); $string = ''; foreach ($values as $value) { $string .= $field['options'][$value] . ' '; } echo trim($string), '<br /><br />'; } else { echo $field['value'], '<br /><br />'; } } } } } if ($settings['show_modify'] && !empty($reply['modified'])) { echo ' <div class="smalltext shd_modified" style="margin-top:20px;"> « <em>', $txt['last_edit'], ': ', $reply['modified']['time'], ' ', $txt['by'], ' ', $reply['modified']['link'], '</em> » </div>'; } template_inline_attachments($reply['id']); echo ' </div>'; if (!empty($reply['ip_address'])) { echo ' <span class="floatright"><img src="', $settings['default_images_url'], '/simpledesk/ip.png" alt="" class="shd_smallicon" /> ', $txt['shd_ticket_ip'], ': ', $reply['ip_address'], '</span>'; } echo ' <br class="clear" /> </div>'; } } echo ' </div> <span class="floatleft shd_nowrap"><a href="#replies" title="', $txt['shd_go_to_replies_start'], '"><img src="', $settings['default_images_url'], '/simpledesk/move_up.png" alt="" /><img src="', $settings['default_images_url'], '/simpledesk/replies.png" alt="" /></a></span> <span class="floatright smalltext">', $txt['pages'], ': ', $context['page_index'], '</span> <br class="clear" /> </div> <span class="lowerframe"><span></span></span> </div>'; }
/** * Load the items from the helpdesk action log * * It is subject to given parameters (start, number of items, order/sorting), parses the language strings and adds the * parameter information provided. * * @param int $start Number of items into the log to start (for pagination). If -1, return everything. If nothing is given, fall back to 0, i.e the first log item. * @param int $items_per_page How many items to load. Default to 10 items. * @param string $sort SQL clause to state which column(s) to order the data by. By default it orders by log_time. * @param string $order SQL clause to state whether the order is ascending or descending. Defaults to descending. * @param string $clause An SQL fragment that forms a WHERE clause to limit log items, e.g. to load a specific ticket or specific member's log items. * * @return array A hash array of the log items, with the auto-incremented id being the key: * <ul> * <li>id: Numeric identifier of the log item</li> * <li>time: Formatted time of the event (as per usual for SMF, formatted for user's timezone)</li> * <li>member: hash array: * <ul> * <li>id: Id of the user that committed the action</li> * <li>name: Name of the user</li> * <li>link: Link to the profile of the user that committed the action</li> * <li>ip: User IP address recorded when the action was carried out</li> * <li>group: Name of the group of the user (uses primary group, failing that post count group)</li> * </ul> * </li> * <li>action: Raw name of the action (for use with collecting the image later)</li> * <li>id_ticket: Numeric id of the ticket this action refers to</li> * <li>id_msg: Numeric id of the individual reply this action refers to</li> * <li>extra: Array of extra parameters for the log action</li> * <li>action_text: Formatted text of the log item (parsed with parameters)</li> * </ul> * * @see shd_log_action() * @see shd_count_action_log_entries() * @since 1.0 */ function shd_load_action_log_entries($start = 0, $items_per_page = 10, $sort = 'la.log_time', $order = 'DESC', $clause = '') { global $smcFunc, $txt, $scripturl, $context, $user_info, $user_profile; // Load languages incase they aren't there (Read: ticket-specific logs) shd_load_language('sd_language/SimpleDeskAdmin'); shd_load_language('sd_language/SimpleDeskLogAction'); shd_load_language('sd_language/SimpleDeskNotifications'); $loaded_users = array(); // We may have to exclude some items from this depending on who the user is or is not. Forum/HD admins can always see everything. $exclude = shd_action_log_exclusions(); if (!empty($exclude)) { if (empty($clause)) { $clause = 'la.action NOT IN ({array_string:exclude})'; } else { $clause .= ' AND la.action NOT IN ({array_string:exclude})'; } } // Without further screaming and waving, fetch the actions. $request = shd_db_query('', ' SELECT la.id_action, la.log_time, la.ip, la.action, la.id_ticket, la.id_msg, la.extra, IFNULL(mem.id_member, 0) AS id_member, IFNULL(mem.real_name, {string:blank}) AS real_name, IFNULL(mg.group_name, {string:na}) AS group_name FROM {db_prefix}helpdesk_log_action AS la LEFT JOIN {db_prefix}members AS mem ON(mem.id_member = la.id_member) LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = CASE WHEN mem.id_group = {int:reg_group_id} THEN mem.id_post_group ELSE mem.id_group END)' . (empty($clause) ? '' : ' WHERE ' . $clause) . ' ORDER BY ' . ($sort != '' ? '{raw:sort} {raw:order}' : 'la.log_time DESC') . ' ' . ($start != -1 ? 'LIMIT {int:start}, {int:items_per_page}' : ''), array('reg_group_id' => 0, 'sort' => $sort, 'start' => $start, 'items_per_page' => $items_per_page, 'order' => $order, 'na' => $txt['not_applicable'], 'blank' => '', 'exclude' => $exclude)); $actions = array(); $notify_members = array(); while ($row = $smcFunc['db_fetch_assoc']($request)) { $row['extra'] = @unserialize($row['extra']); $row['extra'] = is_array($row['extra']) ? $row['extra'] : array(); // Uhoh, we don't know who this is! Check it's not automatically by the system. If it is... mark it so. if (empty($row['id_member'])) { if (isset($row['extra']['auto']) && $row['extra']['auto'] === true) { $row['real_name'] = $txt['shd_helpdesk']; } else { $row['real_name'] = $txt['shd_admin_actionlog_unknown']; } } $actions[$row['id_action']] = array('id' => $row['id_action'], 'time' => timeformat($row['log_time']), 'member' => array('id' => $row['id_member'], 'name' => $row['real_name'], 'link' => shd_profile_link($row['real_name'], $row['id_member']), 'group' => $row['group_name']), 'action' => $row['action'], 'id_ticket' => $row['id_ticket'], 'id_msg' => $row['id_msg'], 'extra' => $row['extra'], 'action_text' => '', 'action_icon' => 'log_' . $row['action'] . '.png', 'can_remove' => empty($context['waittime']) ? false : $row['log_time'] < $context['waittime']); // We want to use a generic icon for custom fields changes. if (strpos($row['action'], 'cf_') === 0) { $actions[$row['id_action']]['action_icon'] = 'log_cfchange.png'; } if (shd_allowed_to('shd_view_ip_any', 0) || $row['id_member'] == $user_info['id'] && shd_allowed_to('shd_view_ip_own', 0)) { $actions[$row['id_action']]['member']['ip'] = !empty($row['ip']) ? $row['ip'] : $txt['shd_admin_actionlog_unknown']; } // Notifications require us to collate all the user ids as we go along. if ($row['action'] == 'notify' && !empty($row['extra']['emails'])) { foreach ($row['extra']['emails'] as $email_type => $recipients) { if (!empty($recipients['u'])) { $notify_members = array_merge($notify_members, explode(',', $recipients['u'])); } } } } $smcFunc['db_free_result']($request); if (!empty($notify_members)) { $notify_members = loadMemberData(array_unique($notify_members)); } // Do some formatting of the action string. foreach ($actions as $k => $action) { if (empty($actions[$k]['action_text'])) { $actions[$k]['action_text'] = isset($txt['shd_log_' . $action['action']]) ? $txt['shd_log_' . $action['action']] : $action['action']; } $actions[$k]['action_text'] = str_replace('{scripturl}', $scripturl, $actions[$k]['action_text']); $actions[$k]['action_text'] = str_replace('{shd_home}', $context['shd_home'], $actions[$k]['action_text']); if (isset($action['extra']['subject'])) { $actions[$k]['action_text'] = str_replace('{ticket}', $actions[$k]['id_ticket'], $actions[$k]['action_text']); $actions[$k]['action_text'] = str_replace('{msg}', $actions[$k]['id_msg'], $actions[$k]['action_text']); if (isset($actions[$k]['extra']['subject'])) { $actions[$k]['action_text'] = str_replace('{subject}', $actions[$k]['extra']['subject'], $actions[$k]['action_text']); } if (isset($actions[$k]['extra']['urgency'])) { $actions[$k]['action_text'] = str_replace('{urgency}', $txt['shd_urgency_' . $actions[$k]['extra']['urgency']], $actions[$k]['action_text']); } } // Notifications are pretty tricky. So let's take care of all of it at once, and skip the rest if we're doing that. if ($action['action'] == 'notify' && isset($action['extra']['emails'])) { // Because this could be a lot of people etc., we compact its storage heavily compared to a conventional serialize(). // See shd_notify_users in SimpleDesk-Notifications.php for what this is. // Now we have all the usernames for this instance, let's go and build this entry. $content = ''; foreach ($action['extra']['emails'] as $email_type => $recipients) { $this_content = '<br /><a href="' . $scripturl . '?action=helpdesk;sa=emaillog;log=' . $action['id'] . ';template=' . $email_type . '" onclick="return reqWin(this.href);">' . $txt['template_log_notify_' . $email_type] . '</a> - '; $new_content = ''; if (!empty($recipients['u'])) { $first = true; $users = explode(',', $recipients['u']); $unknown_users = 0; foreach ($users as $user) { if (empty($user_profile[$user])) { $unknown_users++; continue; } $new_content .= ($first ? $txt['shd_log_notify_users'] . ': ' : ', ') . shd_profile_link($user_profile[$user]['real_name'], $user); $first = false; } if ($unknown_users > 0) { $new_content .= ($first ? $txt['shd_log_notify_users'] . ': ' : ', ') . ($unknown_users == 1 ? $txt['shd_log_unknown_user_1'] : sprintf($txt['shd_log_unknown_user_n'], $unknown_users)); } } if (!empty($new_content)) { $content .= $this_content . $new_content; } } if (!empty($content)) { $actions[$k]['action_text'] .= $txt['shd_log_notify_to'] . $content; } continue; } if (isset($action['extra']['user_name'])) { $actions[$k]['action_text'] = str_replace('{profile_link}', shd_profile_link($actions[$k]['extra']['user_name'], isset($actions[$k]['extra']['user_id']) ? $actions[$k]['extra']['user_id'] : 0), $actions[$k]['action_text']); $actions[$k]['action_text'] = str_replace('{user_name}', $actions[$k]['extra']['user_name'], $actions[$k]['action_text']); } if (isset($action['extra']['user_id'])) { $actions[$k]['action_text'] = str_replace('{user_id}', $actions[$k]['extra']['user_id'], $actions[$k]['action_text']); } if (isset($actions[$k]['extra']['board_name'])) { $actions[$k]['action_text'] = str_replace('{board_name}', $actions[$k]['extra']['board_name'], $actions[$k]['action_text']); } if (isset($actions[$k]['extra']['board_id'])) { $actions[$k]['action_text'] = str_replace('{board_id}', $actions[$k]['extra']['board_id'], $actions[$k]['action_text']); } if (isset($action['extra']['othersubject'])) { $actions[$k]['action_text'] = str_replace('{othersubject}', $actions[$k]['extra']['othersubject'], $actions[$k]['action_text']); $actions[$k]['action_text'] = str_replace('{otherticket}', $actions[$k]['extra']['otherticket'], $actions[$k]['action_text']); } if (isset($action['extra']['old_dept_id'])) { $replace = array('{old_dept_id}' => $action['extra']['old_dept_id'], '{old_dept_name}' => $action['extra']['old_dept_name'], '{new_dept_id}' => $action['extra']['new_dept_id'], '{new_dept_name}' => $action['extra']['new_dept_name']); $actions[$k]['action_text'] = str_replace(array_keys($replace), array_values($replace), $actions[$k]['action_text']); } // Custom fields? if (isset($action['extra']['fieldname'])) { if ($action['extra']['fieldtype'] == CFIELD_TYPE_CHECKBOX) { $action['extra']['oldvalue'] = !empty($action['extra']['oldvalue']) ? $txt['yes'] : $txt['no']; $action['extra']['newvalue'] = !empty($action['extra']['newvalue']) ? $txt['yes'] : $txt['no']; } elseif ($action['extra']['fieldtype'] == CFIELD_TYPE_RADIO || $action['extra']['fieldtype'] == CFIELD_TYPE_SELECT || $action['extra']['fieldtype'] == CFIELD_TYPE_MULTI) { if (empty($action['extra']['oldvalue'])) { $action['extra']['oldvalue'] = $txt['shd_none_selected']; } if (empty($action['extra']['newvalue'])) { $action['extra']['newvalue'] = $txt['shd_none_selected']; } } else { if (empty($action['extra']['oldvalue'])) { $action['extra']['oldvalue'] = $txt['shd_empty_item']; } if (empty($action['extra']['newvalue'])) { $action['extra']['newvalue'] = $txt['shd_empty_item']; } } $actions[$k]['action_text'] = str_replace('{fieldname}', $action['extra']['fieldname'], $actions[$k]['action_text']); $actions[$k]['action_text'] = str_replace('{oldvalue}', $action['extra']['oldvalue'], $actions[$k]['action_text']); $actions[$k]['action_text'] = str_replace('{newvalue}', $action['extra']['newvalue'], $actions[$k]['action_text']); } // This should be the last pair of ops - always. if (isset($action['extra']['att_added'])) { $actions[$k]['action_text'] .= ' ' . $txt['shd_logpart_att_added'] . ': ' . implode(', ', $action['extra']['att_added']); } if (isset($action['extra']['att_removed'])) { $actions[$k]['action_text'] .= ' ' . $txt['shd_logpart_att_removed'] . ': ' . implode(', ', $action['extra']['att_removed']); } } return $actions; }
/** * Display the notice of email. * * @todo Finish documenting * @since 2.0 */ function shd_notify_popup() { global $txt, $context, $settings, $modSettings, $smcFunc, $user_profile, $user_info, $scripturl; // First, verify we got a log entry, that the log entry is right, and it points to a ticket we can actually see. $_GET['log'] = isset($_GET['log']) ? (int) $_GET['log'] : 0; $email_type = isset($_GET['template']) ? preg_replace('~[^a-z_]~', '', $_GET['template']) : ''; if (empty($modSettings['shd_display_ticket_logs']) || empty($_GET['log']) || empty($email_type)) { fatal_lang_error('no_access', false); } $query = $smcFunc['db_query']('', ' SELECT hdla.id_member, hdla.id_ticket, hdla.id_msg, hdla.extra, IFNULL(hdtr.body, {string:empty}) AS body, IFNULL(mem.real_name, hdtr.poster_name) AS poster_name FROM {db_prefix}helpdesk_log_action AS hdla LEFT JOIN {db_prefix}helpdesk_ticket_replies AS hdtr ON (hdla.id_msg = hdtr.id_msg) LEFT JOIN {db_prefix}members AS mem ON (hdtr.id_member = mem.id_member) WHERE id_action = {int:log} AND action = {string:notify}', array('log' => $_GET['log'], 'notify' => 'notify', 'empty' => '')); if ($smcFunc['db_num_rows']($query) == 0) { $smcFunc['db_free_result']($query); fatal_lang_error('no_access'); } $row = $smcFunc['db_fetch_assoc']($query); $smcFunc['db_free_result']($query); $row['extra'] = unserialize($row['extra']); // Just check we did actually log an email of that type. if (empty($row['extra']['emails'][$_GET['template']])) { fatal_lang_error('no_access', false); } $ticketinfo = shd_load_ticket($row['id_ticket']); // OK, if we're here, we can see the ticket. Can we actually see the email log at this point? if (!shd_allowed_to('shd_view_ticket_logs_any', $ticketinfo['dept']) && (!shd_allowed_to('shd_view_ticket_logs_own', $ticketinfo['dept']) || !$ticketinfo['is_own'])) { fatal_lang_error('no_access', false); } // We're reusing the Help template, need its language file. loadLanguage('Help'); shd_load_language('sd_language/SimpleDeskAdmin'); shd_load_language('sd_language/SimpleDeskLogAction'); shd_load_language('sd_language/SimpleDeskNotifications'); // Set the page up loadTemplate('Help'); $context['page_title'] = $context['forum_name'] . ' - ' . $txt['shd_log_notifications']; $context['template_layers'] = array(); $context['sub_template'] = 'popup'; $users = array(); // First, get the list of users, and load their username etc if we haven't already attempted it before. if (isset($row['extra']['emails'][$email_type]['u'])) { $users = array_merge($users, explode(',', $row['extra']['emails'][$email_type]['u'])); } if (!empty($users)) { $users = array_unique($users); if (!empty($users)) { loadMemberData($users, false, 'minimal'); } } // Now we have all the usernames for this instance, let's go and build this entry. $context['help_text'] = $txt['shd_log_notify_to'] . '<br />'; $new_content = ''; if (!empty($users)) { $first = true; foreach ($users as $user) { if (empty($user_profile[$user])) { continue; } $new_content .= ($first ? '<img src="' . shd_image_url('user.png') . '" alt="" /> ' : ', ') . shd_profile_link($user_profile[$user]['real_name'], $user); $first = false; } } if (!empty($row['extra']['emails'][$email_type]['e'])) { $emails = explode(',', $row['extra']['emails'][$email_type]['e']); // Admins can see the actual emails. if (shd_allowed_to('admin_helpdesk', 0) || $user_info['is_admin']) { foreach ($emails as $key => $value) { $emails[$key] = '<a href="mailto:' . $value . '">' . $value . '</a>'; } $new_content .= '<img src="' . shd_image_url('log_notify.png') . '" alt="" /> ' . implode(', ', $emails); } else { $new_content .= '<img src="' . shd_image_url('log_notify.png') . '" alt="" /> ' . (count($emails) == 1 ? $txt['shd_log_notify_hiddenemail_1'] : sprintf($txt['shd_log_notify_hiddenemail'], count($emails))); } } if (!empty($new_content)) { $context['help_text'] .= $new_content; } $context['help_text'] .= '<hr />'; // So the general prep is done. Now let's rebuild the email contents. if (empty($row['extra']['withbody']) || empty($row['body'])) { $body = ''; } else { $body = trim(un_htmlspecialchars(strip_tags(strtr(shd_format_text($row['body'], false), array('<br />' => "\n", '</div>' => "\n", '</li>' => "\n", '[' => '[', ']' => ']'))))); } $replacements = array("\n" => '<br />', '{ticket_id}' => str_pad($row['id_ticket'], $modSettings['shd_zerofill'], '0', STR_PAD_LEFT), '{subject}' => empty($row['extra']['subject']) ? $txt['no_subject'] : $row['extra']['subject'], '{ticketlink}' => $scripturl . '?action=helpdesk;sa=ticket;ticket=' . $row['id_ticket'] . (empty($row['id_msg']) ? '.0' : '.msg' . $row['id_msg'] . '#msg' . $row['id_msg']), '{body}' => $body, '{poster_name}' => $row['poster_name']); $email_subject = str_replace(array_keys($replacements), array_values($replacements), $txt['template_subject_notify_' . $email_type]); $email_body = str_replace(array_keys($replacements), array_values($replacements), $txt['template_' . (empty($row['extra']['withbody']) || empty($row['body']) ? 'body' : 'bodyfull') . '_notify_' . $email_type]); $context['help_text'] .= '<strong>' . $txt['subject'] . ':</strong> ' . $email_subject . '<br /><br />' . $email_body; }
/** * Callback function for the template to load messages. * * The process set up by shd_view_ticket() and invoked within template_view_replies() is reasonably complex. * {@link shd_view_ticket()} identifies what messages should be displayed on the current page of the ticket, and performs a query * to load the ticket data. Instead, however, of retrieving every row directly into memory before passing to the template, * it passes the query result, and the name of a handler function into $context, so the template can call to get an * individual row at a time, which saves memory amongst other things. * * With respect to {@link shd_view_ticket()}, the relevant items are $reply_request being defined and $context['get_replies'] * being defined as the name of this function, and in {@link template_view_replies()}, the reference is $reply = $context['get_replies']() * * @return mixed The function returns the "next" message reply's details, or simply false if no replies were available, or no further replies are available. Assuming a reply can be returned, it will be a hash array in the following format: * <ul> * <li>id: numeric message id</li> * <li>member: hash array containing details of the poster; normally the return value from SMF's loadMemberContext() function. A minimal set of details is prepared if the poster holds no current SMF account. Common values: * <ul> * <li>name: User's name (falls back to the poster name specified in the replies table)</li> * <li>id: User's id</li> * <li>group: Name of the assigned group/post count group of the user</li> * <li>link: HTML for a hyperlink to their profile</li> * <li>email: Email address of the poster</li> * <li>ip: IP address of the poster</li> * </ul> * </li> * <li>body: censored, parsed for smileys and bbcode (in {@link shd_format_text()})</li> * <li>time: string of the time the reply was posted</li> * <li>timestamp: internal stored timestamp attached to the reply</li> * <li>is_staff: boolean value of whether the posting member is currently helpdesk staff</li> * <li>can_edit: boolean value reflecting if this reply can be edited</li> * <li>can_delete: boolean value reflecting if this reply can be deleted</li> * <li>can_restore: boolean value reflecting if this reply can be restored</li> * <li>ip_address: IP address used to post the message (not necessarily the user's normal IP address); if the user has moderate_forum_members permission, this returns a link to the track IP area, with the IP address as the link text, alternatively simply the IP address if not (is only displayed to helpdesk staff)</li> * <li>modified: may not be declared, if it is, the message was modified some time after posting, and the following data items are in the hash array within: * <ul> * <li>id: user id who edited the reply (not always available)</li> * <li>time: formatted string of the time the post was edited</li> * <li>timestamp: raw timestamp of the time the post was edited</li> * <li>name: user name of the editing user; if we have a definite user id, this should contain the current name, falling back to the previously stored name</li> * <li>link: if we have a known, valid user id for the post's editor, this will contain a link to their profile, with the link text using their current display name; alternatively it will contain a regular string which is the username stored with the edit.</li> * </ul> * </li> * </ul> * * @see shd_view_ticket() * @since 1.0 */ function shd_prepare_ticket_context() { global $settings, $txt, $modSettings, $scripturl, $options, $user_info, $smcFunc; global $memberContext, $context, $reply_request, $user_profile; if (empty($reply_request)) { return false; } $message = $smcFunc['db_fetch_assoc']($reply_request); if (!$message) { $smcFunc['db_free_result']($reply_request); return false; } if (!loadMemberContext($message['id_member'], true)) { // Notice this information isn't used anywhere else.... $memberContext[$message['id_member']]['name'] = $message['poster_name']; $memberContext[$message['id_member']]['id'] = 0; $memberContext[$message['id_member']]['group'] = $txt['guest_title']; $memberContext[$message['id_member']]['link'] = $message['poster_name']; $memberContext[$message['id_member']]['email'] = $message['poster_email']; $memberContext[$message['id_member']]['show_email'] = showEmailAddress(true, 0); $memberContext[$message['id_member']]['is_guest'] = true; $memberContext[$message['id_member']]['group_stars'] = ''; } $memberContext[$message['id_member']]['ip'] = $message['poster_ip']; censorText($message['body']); $message['body'] = shd_format_text($message['body'], $message['smileys_enabled'], 'shd_reply_' . $message['id_msg']); $output = array('id' => $message['id_msg'], 'member' => &$memberContext[$message['id_member']], 'time' => timeformat($message['poster_time']), 'timestamp' => forum_time(true, $message['poster_time']), 'body' => $message['body'], 'is_staff' => !empty($context['shd_is_staff'][$message['id_member']]), 'can_edit' => $message['message_status'] != MSG_STATUS_DELETED && !$context['ticket']['closed'] && !$context['ticket']['deleted'] && (shd_allowed_to('shd_edit_reply_any', $context['ticket']['dept']) || $message['id_member'] == $user_info['id'] && shd_allowed_to('shd_edit_reply_own', $context['ticket']['dept'])), 'can_delete' => $message['message_status'] != MSG_STATUS_DELETED && !$context['ticket']['closed'] && !$context['ticket']['deleted'] && (shd_allowed_to('shd_delete_reply_any', $context['ticket']['dept']) || $message['id_member'] == $user_info['id'] && shd_allowed_to('shd_delete_reply_own', $context['ticket']['dept'])), 'can_restore' => $message['message_status'] == MSG_STATUS_DELETED && !$context['ticket']['closed'] && !$context['ticket']['deleted'] && (shd_allowed_to('shd_restore_reply_any', $context['ticket']['dept']) || $message['id_member'] == $user_info['id'] && shd_allowed_to('shd_restore_reply_own', $context['ticket']['dept'])), 'can_permadelete' => $message['message_status'] == MSG_STATUS_DELETED && !$context['ticket']['closed'] && !$context['ticket']['deleted'] && shd_allowed_to('shd_delete_recycling', $context['ticket']['dept']), 'message_status' => $message['message_status'], 'link' => $scripturl . '?action=helpdesk;sa=ticket;ticket=' . $context['ticket_id'] . '.msg' . $message['id_msg'] . '#msg' . $message['id_msg']); if (shd_allowed_to('shd_view_ip_any', $context['ticket']['dept']) || $message['id_member'] == $user_info['id'] && shd_allowed_to('shd_view_ip_own', $context['ticket']['dept'])) { $output['ip_address'] = $context['link_ip_address'] ? '<a href="' . $scripturl . '?action=trackip;searchip=' . $message['poster_ip'] . '">' . $message['poster_ip'] . '</a>' : $message['poster_ip']; } if (!empty($message['modified_time'])) { $output['modified'] = array('time' => timeformat($message['modified_time']), 'timestamp' => forum_time(true, $message['modified_time']), 'id' => !empty($user_profile[$message['modified_member']]) ? $message['modified_member'] : 0, 'name' => !empty($user_profile[$message['modified_member']]) ? $user_profile[$message['modified_member']]['real_name'] : $message['modified_name']); $output['modified']['link'] = shd_profile_link($output['modified']['name'], $output['modified']['id']); } if (!empty($context['ticket_start_newfrom']) && $context['ticket_start_newfrom'] == $message['id_msg']) { $output['is_new'] = true; } return $output; }
/** * Loads the main SimpleDesk information page for forum administrators. * * This function is the main focus point for information about SimpleDesk in the admin panel, primarily it collects the following for the template: * <ul> * <li>list of helpdesk staff</li> * <li>totals of tickets in the system (open/closed/deleted)</li> * <li>credits</li> * <li>also, in the template, whether this is a current or outdated version of SimpleDesk</li> * </ul> * * Since 1.1, it also receives the requests for subactions for action log and support page (since these are sub menu items) but simply directs them onward. * * @see shd_admin_action_log() * @see shd_admin_support() * * @since 1.0 */ function shd_admin_info() { global $context, $settings, $scripturl, $txt, $sourcedir, $smcFunc; $subactions = array('main' => array('function' => false, 'icon' => 'simpledesk.png', 'title' => $txt['shd_admin_info']), 'actionlog' => array('function' => 'shd_admin_action_log', 'icon' => 'log.png', 'title' => $txt['shd_admin_actionlog_title']), 'support' => array('function' => 'shd_admin_support', 'icon' => 'support.png', 'title' => $txt['shd_admin_support'])); $context[$context['admin_menu_name']]['tab_data'] = array('description' => $txt['shd_admin_options_desc'], 'tabs' => array('main' => array('description' => '<strong>' . $txt['hello_guest'] . ' ' . $context['user']['name'] . '!</strong><br />' . $txt['shd_admin_info_desc']), 'actionlog' => array('description' => $txt['shd_admin_actionlog_desc'] . '<br />' . (!empty($modSettings['shd_disable_action_log']) ? '<span class="smalltext">' . $txt['shd_action_log_disabled'] . '</span>' : '')), 'support' => array('description' => $txt['shd_admin_support_desc']))); call_integration_hook('shd_hook_hdadmininfo', array(&$subactions)); $_REQUEST['sa'] = isset($_REQUEST['sa']) && isset($subactions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : 'main'; // Now that we have validated the subaction. $context[$context['admin_menu_name']]['tab_data']['title'] = '<img src="' . $settings['images_url'] . '/admin/shd/' . $subactions[$_REQUEST['sa']]['icon'] . '" class="icon" alt="*" />' . $subactions[$_REQUEST['sa']]['title']; // Are we doing the main page, or leaving here? if (!empty($subactions[$_REQUEST['sa']]['function'])) { $subactions[$_REQUEST['sa']]['function'](); return; } // Get a list of the staff members of the helpdesk. $members = shd_members_allowed_to('shd_staff'); $query = shd_db_query('', ' SELECT id_member, real_name FROM {db_prefix}members WHERE id_member IN ({array_int:members}) ORDER BY real_name', array('members' => $members)); // Note this just gets everyone, doesn't worry about limiting it - IMO that's something for the template to decide. $context['staff'] = array(); while ($row = $smcFunc['db_fetch_assoc']($query)) { $context['staff'][] = shd_profile_link($row['real_name'], $row['id_member']); } $smcFunc['db_free_result']($query); // Make we sure give these slackers some credit. After all, they made sumfin fer ya! shd_credits(); $context['total_tickets'] = shd_count_helpdesk_tickets(); $context['open_tickets'] = shd_count_helpdesk_tickets('open'); $context['closed_tickets'] = shd_count_helpdesk_tickets('closed'); $context['recycled_tickets'] = shd_count_helpdesk_tickets('recycled'); // Final stuff before we go. $context['page_title'] = $txt['shd_admin_title']; $context['sub_template'] = 'shd_admin'; }