function shd_profile_show_tickets($memID) { global $txt, $user_info, $scripturl, $modSettings, $smcFunc, $board, $user_profile, $context; // Navigation $context['show_tickets_navigation'] = array('tickets' => array('text' => 'shd_profile_show_tickets', 'lang' => true, 'url' => $scripturl . '?action=profile;u=' . $memID . ';area=hd_showtickets;sa=tickets'), 'replies' => array('text' => 'shd_profile_show_replies', 'lang' => true, 'url' => $scripturl . '?action=profile;u=' . $memID . ';area=hd_showtickets;sa=replies')); // We might be adding the monitor/ignore lists, but we're only interested in those if we're actually on our own page. if ($memID == $user_info['id']) { if (shd_allowed_to('shd_monitor_ticket_any') || shd_allowed_to('shd_monitor_ticket_own')) { $context['show_tickets_navigation']['monitor'] = array('text' => 'shd_profile_show_monitor', 'lang' => true, 'url' => $scripturl . '?action=profile;u=' . $memID . ';area=hd_showtickets;sa=monitor'); } if (shd_allowed_to('shd_ignore_ticket_any') || shd_allowed_to('shd_ignore_ticket_own')) { $context['show_tickets_navigation']['ignore'] = array('text' => 'shd_profile_show_ignore', 'lang' => true, 'url' => $scripturl . '?action=profile;u=' . $memID . ';area=hd_showtickets;sa=ignore'); } // We have the monitor and ignore lists in this area but this code can't deal with it, so we need to go somewhere else with it. if (isset($_GET['sa']) && ($_GET['sa'] == 'monitor' || $_GET['sa'] == 'ignore')) { return shd_profile_show_notify_override($memID); } } $context['page_title'] = $txt['shd_profile_show_tickets'] . ' - ' . $user_profile[$memID]['real_name']; $context['sub_template'] = 'shd_profile_show_tickets'; $context['start'] = (int) $_REQUEST['start']; // The time has come to choose: Tickets, or just replies? $context['can_haz_replies'] = isset($_GET['sa']) && $_GET['sa'] == 'replies' ? true : false; // The active button. $context['show_tickets_navigation'][$context['can_haz_replies'] ? 'replies' : 'tickets']['active'] = true; // "That still only counts as one!" if ($context['can_haz_replies']) { $request = shd_db_query('', ' SELECT COUNT(hdtr.id_msg) FROM {db_prefix}helpdesk_ticket_replies AS hdtr LEFT JOIN {db_prefix}helpdesk_tickets AS hdt ON(hdtr.id_ticket = hdt.id_ticket) WHERE hdtr.id_member = {int:user} AND {query_see_ticket}', array('user' => $memID)); } else { $request = shd_db_query('', ' SELECT COUNT(hdt.id_ticket) FROM {db_prefix}helpdesk_tickets AS hdt WHERE hdt.id_member_started = {int:user} AND {query_see_ticket}', array('user' => $memID)); } list($item_count) = $smcFunc['db_fetch_row']($request); $smcFunc['db_free_result']($request); // Max? Max? Where are you? $request = shd_db_query('', ' SELECT MIN(hdtr.id_msg), MAX(hdtr.id_msg) FROM {db_prefix}helpdesk_ticket_replies AS hdtr LEFT JOIN {db_prefix}helpdesk_tickets AS hdt ON(hdtr.id_ticket = hdt.id_ticket) WHERE hdtr.id_member = {int:user} AND {query_see_ticket}', array('user' => $memID)); list($min_msg_member, $max_msg_member) = $smcFunc['db_fetch_row']($request); $smcFunc['db_free_result']($request); $reverse = false; $max_index = (int) $modSettings['defaultMaxMessages']; // A little page index to help us along the way! $context['page_index'] = shd_no_expand_pageindex($scripturl . '?action=profile;u=' . $memID . ';area=hd_showtickets' . ($context['can_haz_replies'] ? ';sa=replies' : ''), $context['start'], $item_count, $max_index); $context['current_page'] = $context['start'] / $max_index; // Reverse the query if we're past 50% of the pages for better performance. $start = $context['start']; $reverse = $_REQUEST['start'] > $item_count / 2; if ($reverse) { $max_index = $item_count < $context['start'] + $modSettings['defaultMaxMessages'] + 1 && $item_count > $context['start'] ? $item_count - $context['start'] : (int) $modSettings['defaultMaxMessages']; $start = $item_count < $context['start'] + $modSettings['defaultMaxMessages'] + 1 || $item_count < $context['start'] + $modSettings['defaultMaxMessages'] ? 0 : $item_count - $context['start'] - $modSettings['defaultMaxMessages']; } // Bring 'em to me! $looped = false; while (true) { if ($context['can_haz_replies']) { $request = shd_db_query('', ' SELECT hdtr.id_member, hdt.subject, hdt.id_first_msg, hdtr.body, hdtr.smileys_enabled, hdtr.poster_time, hdtr.id_ticket, hdtr.id_msg FROM {db_prefix}helpdesk_ticket_replies AS hdtr INNER JOIN {db_prefix}helpdesk_tickets AS hdt ON (hdt.id_ticket = hdtr.id_ticket) WHERE hdtr.id_member = {int:user} AND {query_see_ticket} ORDER BY hdtr.id_msg ' . ($reverse ? 'ASC' : 'DESC') . ' LIMIT ' . $start . ', ' . $max_index, array('user' => $memID)); } else { $request = shd_db_query('', ' SELECT hdt.id_member_started, hdt.id_first_msg, hdt.id_last_msg, hdt.subject, hdtr.body, hdtr.smileys_enabled, hdtr.poster_time, hdtr.id_ticket, hdtr.id_msg FROM {db_prefix}helpdesk_tickets AS hdt INNER JOIN {db_prefix}helpdesk_ticket_replies AS hdtr ON (hdtr.id_msg = hdt.id_first_msg) WHERE hdt.id_member_started = {int:user} AND {query_see_ticket} ORDER BY hdt.id_first_msg ' . ($reverse ? 'ASC' : 'DESC') . ' LIMIT ' . $start . ', ' . $max_index, array('user' => $memID)); } // Hold it! if ($smcFunc['db_num_rows']($request) === $max_index || $looped) { break; } $looped = true; } // Start counting at the number of the first message displayed. $counter = $reverse ? $context['start'] + $max_index + 1 : $context['start']; $context['items'] = array(); while ($row = $smcFunc['db_fetch_assoc']($request)) { // Censor the content censorText($row['body']); censorText($row['subject']); // Do the parsing dance! Eh... $row['body'] = shd_format_text($row['body'], $row['smileys_enabled'], 'shd_reply_' . $row['id_msg']); // And finally, store the load of cr--... the results! $context['items'][$counter += $reverse ? -1 : 1] = array('body' => $row['body'], 'counter' => $counter, 'alternate' => $counter % 2, 'ticket' => $row['id_ticket'], 'subject' => $row['subject'], 'start' => 'msg' . $row['id_msg'], 'time' => timeformat($row['poster_time']), 'timestamp' => forum_time(true, $row['poster_time']), 'msg' => $row['id_msg'], 'is_ticket' => empty($context['can_haz_replies']) ? true : $row['id_msg'] == $row['id_first_msg']); } // Freedom. $smcFunc['db_free_result']($request); // Head's up, feet's down. if ($reverse) { $context['items'] = array_reverse($context['items'], true); } }
/** * Loads all the data and sets all the options for displaying a ticket. * * This function does a lot of work in setting up a ticket to be displayed: * <ul> * <li>Invokes shd_load_ticket() to get the principle data</li> * <li>Creates $context['ticket'] to hold the data block, some of which is derived from the return of shd_load_ticket(): * <ul> * <li>id: regular numeric ticket id</li> * <li>display_id: zero padded ticket id (e.g. 00001)</li> * <li>subject: censored version of the subject</li> * <li>first_msg: id of the opening post that forms the ticket body</li> * <li>body: formatted (parsed for smileys and bbcode) version of the ticket post</li> * <li>id_member: user id of the ticket's poster</li> * <li>id_member_assigned: user id of the ticket's assigned user</li> * <li>member: hash array of the ticket poster's details: * <ul> * <li>id: their user id</li> * <li>name: the name stated in the ticket post for that use</li> * <li>link: link to the profile of the user</li> * </ul> * </li> * <li>assigned: hash array of the assignee of the ticket: * <ul> * <li>id: their user id</li> * <li>name: name of the assignee, or 'Unassigned'</li> * <li>link: a full HTML link to their profile, or 'Unassigned' in red text</li> * </ul> * </li> * <li>assigned_self: boolean, whether the ticket is assigned to the current user or not</li> * <li>ticket_opener: boolean, whether the current user is the user who opened this ticket</li> * <li>urgency: hash array * <ul> * <li>level: numeric identifier of current ticket urgency</li> * <li>label: the HTML label of the urgency, including being in red for "Very High" or above</li> * <li>increase: Boolean, whether the current ticket urgency can be increased given the current ticket state and user permissions</li> * <li>decrease: Boolean, whether the current ticket urgency can be increased given the current ticket state and user permissions</li> * </ul> * </li> * <li>status: hash array * <ul> * <li>level: numeric, current status identifier</li> * <li>label: string representing the current status</li> * </ul> * <li>num_replies: the number of replies to the ticket so far</li> * <li>deleted_replies: how many deleted replies in this ticket</li> * <li>poster_time: formatted string containing the time the ticket was opened</li> * <li>privacy: hash array * <ul> * <li>label: current label to be used with the privacy item</li> * <li>can_change: Boolean, whether the user's permission with this ticket allows us to edit the ticket privacy</li> * </ul> * </li> * <li>closed: Boolean, represents whether this ticket is closed (used a lot with the navigation menu)</li> * <li>deleted: Boolean, represents whether this ticket is deleted (used a lot with the navigation menu)</li> * <li>ip_address: IP address logged at the time the ticket was opened; if moderate_forum_members permission is available, this will be a link to the track IP area</li> * <li>modified: if the ticket has been modified, also get the modified details: * <ul> * <li>id: user id who edited the ticket (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> * <li>display_recycle: Either holds the $txt identifier of the message to apply as a warning, or false if displaying of recycling stuff in this ticket isn't appropriate (either for permissions or just because of no deleted replies, or we're just in regular ticket view)</li> * </ul> * </li> * <li>define the page index with SMF's constructPageIndex</li> * <li>query for all the ids of messages we might display, followed by querying for the message details themselves, pushing that query resource to $reply_request so we can use it in shd_view_replies() later</li> * <li>load details of all the users applicable for posts in this page</li> * <li>request all the visible attachments from {@link shd_display_load_attachments()}</li> * <li>since we are viewing this ticket, mark it read</li> * <li>set up the breadcrumb trail</li> * <li>set up the ticket navigation menu</li> * <li>call in the editor component from SimpleDesk-Post.php and friends, ready for Quick Reply</li> * <li>invoke the different Javascript objects that are applicable on the page: * <ul> * <li>privacy changer</li> * <li>urgency changer</li> * <li>quick reply / quote / go advanced</li> * </ul> * </li> * </ul> * * @see shd_prepare_ticket_context() * @since 1.0 */ function shd_view_ticket() { global $context, $txt, $scripturl, $settings, $reply_request, $smcFunc, $modSettings, $memberContext, $sourcedir, $user_info, $options; loadTemplate('sd_template/SimpleDesk-Display'); $context['template_layers'][] = 'shd_display_nojs'; $ticketinfo = shd_load_ticket(); // How much are we sticking on each page? $context['messages_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['messages_per_page']) && !WIRELESS ? $options['messages_per_page'] : $modSettings['defaultMaxMessages']; censorText($ticketinfo['subject']); censorText($ticketinfo['body']); $context['user_list'] = array(); // as we go along, build a list of users who are relevant $context['ticket'] = array('id' => $context['ticket_id'], 'dept' => $ticketinfo['dept'], 'dept_name' => $ticketinfo['dept_name'], 'display_id' => str_pad($context['ticket_id'], $modSettings['shd_zerofill'], '0', STR_PAD_LEFT), 'subject' => $ticketinfo['subject'], 'first_msg' => $ticketinfo['id_first_msg'], 'body' => shd_format_text($ticketinfo['body'], $ticketinfo['smileys_enabled'], 'shd_reply_' . $ticketinfo['id_first_msg']), 'id_member' => $ticketinfo['id_member'], 'id_member_assigned' => $ticketinfo['assigned_id'], 'member' => array('id' => $ticketinfo['starter_id'], 'name' => $ticketinfo['starter_name'], 'link' => shd_profile_link($ticketinfo['starter_name'], $ticketinfo['starter_id'])), 'assigned' => array('id' => $ticketinfo['assigned_id'], 'name' => $ticketinfo['assigned_id'] > 0 ? $ticketinfo['assigned_name'] : $txt['shd_unassigned'], 'link' => $ticketinfo['assigned_id'] > 0 ? shd_profile_link($ticketinfo['assigned_name'], $ticketinfo['assigned_id']) : '<span class="error">' . $txt['shd_unassigned'] . '</span>'), 'assigned_self' => $ticketinfo['assigned_id'] == $user_info['id'], 'ticket_opener' => $ticketinfo['starter_id'] == $user_info['id'], 'urgency' => array('level' => $ticketinfo['urgency'], 'label' => $ticketinfo['urgency'] > TICKET_URGENCY_HIGH ? '<span class="error">' . $txt['shd_urgency_' . $ticketinfo['urgency']] . '</span>' : $txt['shd_urgency_' . $ticketinfo['urgency']]), 'status' => array('level' => $ticketinfo['status'], 'label' => $txt['shd_status_' . $ticketinfo['status']]), 'num_replies' => $ticketinfo['num_replies'], 'deleted_replies' => $ticketinfo['deleted_replies'], 'poster_time' => timeformat($ticketinfo['poster_time']), 'privacy' => array('label' => $ticketinfo['private'] ? $txt['shd_ticket_private'] : $txt['shd_ticket_notprivate'], 'can_change' => shd_allowed_to('shd_alter_privacy_any', $ticketinfo['dept']) || shd_allowed_to('shd_alter_privacy_own', $ticketinfo['dept']) && $ticketinfo['id_member'] == $user_info['id']), 'closed' => $ticketinfo['closed'], 'deleted' => $ticketinfo['deleted']); // Fix the departmental link since we know we're inside a department now. if ($context['shd_multi_dept']) { $context['shd_department'] = $context['ticket']['dept']; $context['shd_dept_link'] = ';dept=' . $context['ticket']['dept']; } // IP address next $context['link_ip_address'] = allowedTo('moderate_forum'); // for trackip access if (shd_allowed_to('shd_view_ip_any', $context['ticket']['dept']) || $context['ticket']['ticket_opener'] && shd_allowed_to('shd_view_ip_own', $context['ticket']['dept'])) { $context['ticket']['ip_address'] = $context['link_ip_address'] ? '<a href="' . $scripturl . '?action=trackip;searchip=' . $ticketinfo['starter_ip'] . '">' . $ticketinfo['starter_ip'] . '</a>' : $ticketinfo['starter_ip']; } // Stuff concerning whether the ticket is deleted or not // Display recycling stuff if: ticket is deleted (if we can see it, we can see the bin) OR ticket has deleted replies and we can see the bin and we requested to see them $context['ticket']['display_recycle_replies'] = true; if ($context['ticket']['deleted']) { $context['ticket']['display_recycle'] = $txt['shd_ticket_has_been_deleted']; } elseif ($context['ticket']['deleted_replies'] > 0) { if (shd_allowed_to('shd_access_recyclebin', $context['ticket']['dept'])) { $context['ticket']['display_recycle'] = $txt['shd_ticket_replies_deleted']; $ticketlink = $scripturl . '?action=helpdesk;sa=ticket;ticket=' . $context['ticket_id'] . (isset($_REQUEST['recycle']) ? '' : ';recycle'); $context['ticket']['display_recycle'] .= ' ' . sprintf(isset($_REQUEST['recycle']) ? $txt['shd_ticket_replies_deleted_view'] : $txt['shd_ticket_replies_deleted_link'], $ticketlink); $context['ticket']['display_recycle_replies'] = isset($_REQUEST['recycle']); } else { $context['ticket']['display_recycle_replies'] = false; } } else { $context['ticket']['display_recycle'] = false; $context['ticket']['display_recycle_replies'] = false; } // Ticket privacy $context['ticket']['privacy']['can_change'] = $context['ticket']['privacy']['can_change'] && (!$context['ticket']['closed'] && !$context['ticket']['deleted']); if (empty($modSettings['shd_privacy_display']) || $modSettings['shd_privacy_display'] == 'smart') { $context['display_private'] = shd_allowed_to('shd_view_ticket_private_any', $context['ticket']['dept']) || shd_allowed_to(array('shd_alter_privacy_own', 'shd_alter_privacy_any'), $context['ticket']['dept']) || $ticketinfo['private']; } else { $context['display_private'] = true; } if ($ticketinfo['modified_time'] > 0) { $context['ticket']['modified'] = array('id' => $ticketinfo['modified_id'], 'name' => $ticketinfo['modified_name'], 'link' => shd_profile_link($ticketinfo['modified_name'], $ticketinfo['modified_id']), 'timestamp' => $ticketinfo['modified_time'], 'time' => timeformat($ticketinfo['modified_time'])); } $context['ticket']['urgency'] += shd_can_alter_urgency($ticketinfo['urgency'], $ticketinfo['starter_id'], $ticketinfo['closed'], $ticketinfo['deleted'], $context['ticket']['dept']); $context['total_visible_posts'] = empty($context['display_recycle']) ? $context['ticket']['num_replies'] : (int) $context['ticket']['num_replies'] + (int) $context['ticket']['deleted_replies']; // OK, before we go crazy, we might need to alter the ticket start. If we're in descending order (non default), we need to reverse it. if (!empty($context['shd_preferences']['display_order']) && $context['shd_preferences']['display_order'] == 'desc') { if (empty($context['ticket_start_natural'])) { $context['ticket_start_from'] = $context['total_visible_posts'] - (empty($context['ticket_start']) ? $context['total_visible_posts'] : $context['ticket_start']); } else { $context['ticket_start_from'] = $context['ticket_start']; } $context['ticket_sort'] = 'DESC'; } else { $context['ticket_start_from'] = $context['ticket_start']; $context['ticket_sort'] = 'ASC'; } $context['page_index'] = shd_no_expand_pageindex($scripturl . '?action=helpdesk;sa=ticket;ticket=' . $context['ticket_id'] . '.%1$d' . (isset($_REQUEST['recycle']) ? ';recycle' : '') . '#replies', $context['ticket_start_from'], $context['total_visible_posts'], $context['messages_per_page'], true); $context['get_replies'] = 'shd_prepare_ticket_context'; $query = shd_db_query('', ' SELECT id_msg, id_member, modified_member FROM {db_prefix}helpdesk_ticket_replies WHERE id_ticket = {int:ticket} AND id_msg > {int:first_msg}' . (!empty($context['ticket']['display_recycle_replies']) ? '' : ' AND message_status = {int:msg_status}') . ' ORDER BY id_msg {raw:sort}' . ($context['messages_per_page'] == -1 ? '' : ' LIMIT ' . $context['ticket_start_from'] . ', ' . $context['messages_per_page']), array('ticket' => $context['ticket_id'], 'first_msg' => $ticketinfo['id_first_msg'], 'msg_status' => MSG_STATUS_NORMAL, 'sort' => $context['ticket_sort'])); $context['ticket_messages'] = array(); $posters = array(); while ($row = $smcFunc['db_fetch_assoc']($query)) { if (!empty($row['id_member'])) { $posters[] = $row['id_member']; } if (!empty($row['modified_member'])) { $posters[] = $row['modified_member']; } $context['ticket_messages'][] = $row['id_msg']; } $smcFunc['db_free_result']($query); // We might want the OP's avatar, add 'em to the list -- just in case. $posters[] = $context['ticket']['id_member']; $posters = array_unique($posters); $context['shd_is_staff'] = array(); // Get the poster data if (!empty($posters)) { loadMemberData($posters); // Are they current team members? $team = array_intersect($posters, shd_members_allowed_to('shd_staff', $context['ticket']['dept'])); foreach ($team as $member) { $context['shd_is_staff'][$member] = true; } } if (!empty($context['ticket_messages'])) { $reply_request = shd_db_query('', ' SELECT id_msg, poster_time, poster_ip, id_member, modified_time, modified_name, modified_member, body, smileys_enabled, poster_name, poster_email, message_status FROM {db_prefix}helpdesk_ticket_replies WHERE id_msg IN ({array_int:message_list})' . (!empty($context['ticket']['display_recycle']) ? '' : ' AND message_status IN ({array_int:msg_normal})') . ' ORDER BY id_msg {raw:sort}', array('message_list' => $context['ticket_messages'], 'msg_normal' => array(MSG_STATUS_NORMAL), 'sort' => $context['ticket_sort'])); } else { $reply_request = false; $context['first_message'] = 0; $context['first_new_message'] = false; } // Load all the custom fields // First, get all the values that could apply to the current context. We'll deal with what's active/inactive and where it all goes shortly. $query = shd_db_query('', ' SELECT cfv.id_post, cfv.id_field, cfv.value, cfv.post_type FROM {db_prefix}helpdesk_custom_fields_values AS cfv WHERE (cfv.id_post = {int:ticket} AND cfv.post_type = 1)' . (!empty($context['ticket_messages']) ? ' OR (cfv.id_post IN ({array_int:msgs}) AND cfv.post_type = 2)' : ''), array('ticket' => $context['ticket_id'], 'msgs' => $context['ticket_messages'])); $field_values = array(); while ($row = $smcFunc['db_fetch_assoc']($query)) { $field_values[$row['post_type'] == CFIELD_TICKET ? 'ticket' : $row['id_post']][$row['id_field']] = $row; } $smcFunc['db_free_result']($query); // Set up the storage. $context['custom_fields_replies'] = array(); $context['ticket']['custom_fields'] = array('details' => array(), 'information' => array(), 'prefix' => array(), 'prefixfilter' => array()); $context['ticket_form']['custom_fields_context'] = 'reply'; $context['ticket_form']['custom_fields'] = array(); $query = shd_db_query('', ' SELECT cf.id_field, cf.active, cf.field_order, cf.field_name, cf.field_desc, cf.field_loc, cf.icon, cf.field_type, cf.default_value, cf.bbc, cf.can_see, cf.can_edit, cf.field_length, cf.field_options, cf.display_empty, cfd.required, cf.placement FROM {db_prefix}helpdesk_custom_fields AS cf INNER JOIN {db_prefix}helpdesk_custom_fields_depts AS cfd ON (cf.id_field = cfd.id_field AND cfd.id_dept = {int:dept}) WHERE cf.active = 1 ORDER BY cf.field_order', array('dept' => $context['ticket']['dept'])); // Loop through all fields and figure out where they should be. $is_staff = shd_allowed_to('shd_staff', $context['ticket']['dept']); $is_admin = shd_allowed_to('admin_helpdesk', $context['ticket']['dept']); // this includes forum admins $placements = array(CFIELD_PLACE_DETAILS => 'details', CFIELD_PLACE_INFO => 'information', CFIELD_PLACE_PREFIX => 'prefix', CFIELD_PLACE_PREFIXFILTER => 'prefixfilter'); while ($row = $smcFunc['db_fetch_assoc']($query)) { list($user_see, $staff_see) = explode(',', $row['can_see']); list($user_edit, $staff_edit) = explode(',', $row['can_edit']); if ($is_admin) { $editable = true; } elseif ($is_staff) { if ($staff_see == 0) { continue; } $editable = $staff_edit == 1; } elseif ($user_see == 1) { $editable = $user_edit == 1; } else { continue; } // If this is going to be displayed for the individual ticket, we need to figure out where it should go. if ($row['field_loc'] & CFIELD_TICKET) { $pos = $placements[$row['placement']]; } $field = array('id' => $row['id_field'], 'name' => $row['field_name'], 'desc' => parse_bbc($row['field_desc'], false), 'icon' => $row['icon'], 'type' => $row['field_type'], 'default_value' => $row['field_type'] == CFIELD_TYPE_LARGETEXT ? explode(',', $row['default_value']) : $row['default_value'], 'options' => !empty($row['field_options']) ? unserialize($row['field_options']) : array(), 'display_empty' => !empty($row['required']) ? true : !empty($row['display_empty']), 'bbc' => !empty($row['bbc']) && ($row['field_type'] == CFIELD_TYPE_TEXT || $row['field_type'] == CFIELD_TYPE_LARGETEXT) && $row['placement'] != CFIELD_PLACE_PREFIX, 'editable' => !empty($editable)); if (!empty($field['options']) && empty($field['options']['inactive'])) { $field['options']['inactive'] = array(); } if (in_array($field['type'], array(CFIELD_TYPE_RADIO, CFIELD_TYPE_SELECT, CFIELD_TYPE_MULTI))) { foreach ($field['options'] as $k => $v) { if ($k != 'inactive' && strpos($v, '[') !== false) { $field['options'][$k] = parse_bbc($v, false); } } } if ($row['field_loc'] & CFIELD_REPLY && $field['editable']) { $context['ticket_form']['custom_fields']['reply'][$field['id']] = $field; } // Add fields to the master list, getting any values as we go. if ($row['field_loc'] & CFIELD_TICKET && (!empty($field_values['ticket'][$row['id_field']]['post_type']) && $field_values['ticket'][$row['id_field']]['post_type'] == CFIELD_TICKET || $field['display_empty'])) { if (isset($field_values['ticket'][$row['id_field']])) { $field['value'] = $field['bbc'] ? shd_format_text($field_values['ticket'][$row['id_field']]['value']) : $field_values['ticket'][$row['id_field']]['value']; } $context['ticket']['custom_fields'][$pos][$row['id_field']] = $field; } if ($row['field_loc'] & CFIELD_REPLY) { foreach ($field_values as $dest => $field_details) { unset($field['value']); if ($dest == 'ticket' || !isset($field_details[$row['id_field']]) || $field_details[$row['id_field']]['post_type'] != CFIELD_REPLY) { continue; } $field['value'] = $field['bbc'] ? shd_format_text($field_details[$row['id_field']]['value']) : $field_details[$row['id_field']]['value']; $context['custom_fields_replies'][$dest][$row['id_field']] = $field; } // We also need to attach the field to replies didn't get the field added, in the event that the field should be displayed by default. if ($field['display_empty']) { foreach ($context['ticket_messages'] as $msg) { if (!isset($context['custom_fields_replies'][$msg][$row['id_field']])) { $field['value'] = ''; $context['custom_fields_replies'][$msg][$row['id_field']] = $field; } } } } } $smcFunc['db_free_result']($query); // Grab the avatar for the poster $context['ticket']['poster_avatar'] = empty($context['ticket']['member']['id']) ? array() : (loadMemberContext($context['ticket']['id_member']) ? $memberContext[$context['ticket']['id_member']]['avatar'] : array()); // Before we grab attachments, also make sure we get any from the first msg (i.e. the ticket) $context['ticket_messages'][] = $context['ticket']['first_msg']; shd_display_load_attachments(); // Mark read goes here if (!empty($user_info['id'])) { $smcFunc['db_insert']('replace', '{db_prefix}helpdesk_log_read', array('id_ticket' => 'int', 'id_member' => 'int', 'id_msg' => 'int'), array($context['ticket_id'], $user_info['id'], $ticketinfo['id_last_msg']), array('id_member', 'id_topic')); } // Template stuff $context['sub_template'] = 'viewticket'; $ticketname = ''; if (!empty($context['ticket']['custom_fields']['prefix'])) { $ticketname = '[' . $context['ticket']['display_id'] . '] '; $fields = ''; foreach ($context['ticket']['custom_fields']['prefix'] as $field) { if (empty($field['value'])) { continue; } if ($field['type'] == CFIELD_TYPE_CHECKBOX) { $fields .= !empty($field['value']) ? $txt['yes'] . ' ' : $txt['no'] . ' '; } elseif ($field['type'] == CFIELD_TYPE_SELECT || $field['type'] == CFIELD_TYPE_RADIO) { $fields .= trim(strip_tags($field['options'][$field['value']])) . ' '; } elseif ($field['type'] == CFIELD_TYPE_MULTI) { $values = explode(',', $field['value']); foreach ($values as $value) { $fields .= trim(strip_tags($field['options'][$value])) . ' '; } } else { $fields .= $field['value'] . ' '; } } $fields = trim($fields); $ticketname .= (!empty($fields) ? '[' . trim($fields) . '] ' : '') . $context['ticket']['subject']; } else { $ticketname = '[' . $context['ticket']['display_id'] . '] ' . $context['ticket']['subject']; } $context['page_title'] = $txt['shd_helpdesk'] . ' ' . $ticketname; // If we're in a department, display that. if ($context['shd_multi_dept']) { $context['linktree'][] = array('url' => $scripturl . '?' . $context['shd_home'] . $context['shd_dept_link'], 'name' => $context['ticket']['dept_name']); } // Build the link tree. If the ticket is recycled, display 'Recycle bin'. if ($context['ticket']['status']['level'] == TICKET_STATUS_DELETED) { $context['linktree'][] = array('url' => $scripturl . '?action=helpdesk;sa=recyclebin' . $context['shd_dept_link'], 'name' => $txt['shd_recycle_bin']); } elseif ($context['ticket']['status']['level'] == TICKET_STATUS_CLOSED) { $context['linktree'][] = array('url' => $scripturl . '?action=helpdesk;sa=closedtickets' . $context['shd_dept_link'], 'name' => $txt['shd_tickets_closed']); } // Lastly add the ticket name and link to the linktree. $context['linktree'][] = array('url' => $scripturl . '?action=helpdesk;sa=ticket;ticket=' . $context['ticket_id'], 'name' => $ticketname); // Ticket navigation / permission $context['can_move_dept'] = !empty($context['shd_multi_dept']) && (shd_allowed_to('shd_move_dept_any', $context['ticket']['dept']) || $context['ticket']['ticket_opener'] && shd_allowed_to('shd_move_dept_own', $context['ticket']['dept'])); $context['can_reply'] = !$context['ticket']['closed'] && !$context['ticket']['deleted'] && (shd_allowed_to('shd_reply_ticket_any', $context['ticket']['dept']) || $context['ticket']['ticket_opener'] && shd_allowed_to('shd_reply_ticket_own', $context['ticket']['dept'])); // needs perms - calc'd here because we use it in display template too $context['can_quote'] = $context['can_reply'] && !empty($modSettings['shd_allow_ticket_bbc']); $context['can_go_advanced'] = !empty($modSettings['shd_allow_ticket_bbc']) || !empty($modSettings['allow_ticket_smileys']) || shd_allowed_to('shd_post_attachment', $context['ticket']['dept']); $context['shd_can_move_to_topic'] = empty($modSettings['shd_disable_tickettotopic']) && shd_allowed_to('shd_ticket_to_topic', $context['ticket']['dept']) && empty($modSettings['shd_helpdesk_only']); $context['can_solve'] = !$context['ticket']['closed'] && !$context['ticket']['deleted'] && (shd_allowed_to('shd_resolve_ticket_any', $context['ticket']['dept']) || shd_allowed_to('shd_resolve_ticket_own', $context['ticket']['dept']) && $context['ticket']['ticket_opener']); $context['can_unsolve'] = $context['ticket']['closed'] && (shd_allowed_to('shd_unresolve_ticket_any', $context['ticket']['dept']) || shd_allowed_to('shd_unresolve_ticket_own', $context['ticket']['dept']) && $context['ticket']['ticket_opener']); $context['can_silent_update'] = $context['can_reply'] && shd_allowed_to('shd_silent_update', $context['ticket']['dept']); // And off we go $context['ticket_navigation'] = array(); $context['ticket_navigation'][] = array('url' => $scripturl . '?action=helpdesk;sa=editticket;ticket=' . $context['ticket']['id'] . ';' . $context['session_var'] . '=' . $context['session_id'], 'icon' => 'edit', 'alt' => '*', 'display' => !$context['ticket']['closed'] && !$context['ticket']['deleted'] && (shd_allowed_to('shd_edit_ticket_any', $context['ticket']['dept']) || $context['ticket']['ticket_opener'] && shd_allowed_to('shd_edit_ticket_own', $context['ticket']['dept'])), 'text' => 'shd_ticket_edit'); $context['ticket_navigation'][] = array('url' => $scripturl . '?action=helpdesk;sa=markunread;ticket=' . $context['ticket']['id'] . ';' . $context['session_var'] . '=' . $context['session_id'], 'icon' => 'unread', 'alt' => '*', 'display' => !$context['ticket']['closed'] && !$context['ticket']['deleted'], 'text' => 'shd_ticket_markunread'); $context['ticket_navigation'][] = array('url' => $scripturl . '?action=helpdesk;sa=resolveticket;ticket=' . $context['ticket']['id'] . ';' . $context['session_var'] . '=' . $context['session_id'], 'icon' => 'resolved', 'alt' => '*', 'display' => $context['can_solve'], 'text' => 'shd_ticket_resolved'); $context['ticket_navigation'][] = array('url' => $scripturl . '?action=helpdesk;sa=resolveticket;ticket=' . $context['ticket']['id'] . ';' . $context['session_var'] . '=' . $context['session_id'], 'icon' => 'unresolved', 'alt' => '*', 'display' => $context['can_unsolve'], 'text' => 'shd_ticket_unresolved'); // This is always going to be a pain. But it should be possible to contextualise it nicely. // And while this isn't quite as nicely formatted as a single nice array definition, // imagine trying to debug the display and text options later if it were done with nested ternaries... *shudder* $context['ajax_assign'] = false; $assign_nav = array('url' => $scripturl . '?action=helpdesk;sa=assign;ticket=' . $context['ticket']['id'] . ';' . $context['session_var'] . '=' . $context['session_id'], 'icon' => 'assign', 'alt' => '*', 'text' => '', 'display' => false); if (shd_allowed_to('shd_assign_ticket_any', $context['ticket']['dept'])) { $assign_nav['display'] = shd_allowed_to('shd_staff', $context['ticket']['dept']) && !$context['ticket']['closed'] && !$context['ticket']['deleted']; $assign_nav['text'] = empty($context['ticket']['id_member_assigned']) ? 'shd_ticket_assign' : 'shd_ticket_reassign'; $context['ajax_assign'] = $assign_nav['display']; } elseif (shd_allowed_to('shd_assign_ticket_own', $context['ticket']['dept'])) { $assign_nav['display'] = !$context['ticket']['closed'] && !$context['ticket']['deleted'] && shd_allowed_to('shd_staff', $context['ticket']['dept']) && (empty($context['ticket']['id_member_assigned']) || $context['ticket']['assigned_self']); // either not assigned or assigned to self $assign_nav['text'] = $context['ticket']['assigned_self'] ? 'shd_ticket_unassign' : 'shd_ticket_assign_self'; } $context['ticket_navigation'][] = $assign_nav; $context['ticket_navigation'][] = array('url' => $scripturl . '?action=helpdesk;sa=deleteticket;ticket=' . $context['ticket']['id'] . ';' . $context['session_var'] . '=' . $context['session_id'], 'icon' => 'delete', 'alt' => '*', 'display' => !$context['ticket']['closed'] && !$context['ticket']['deleted'] && (shd_allowed_to('shd_delete_ticket_any', $context['ticket']['dept']) || shd_allowed_to('shd_delete_ticket_own', $context['ticket']['dept']) && $context['ticket']['ticket_opener']), 'text' => 'shd_ticket_delete', 'onclick' => 'return confirm(' . JavaScriptEscape($txt['shd_delete_confirm']) . ');'); $context['ticket_navigation'][] = array('url' => $scripturl . '?action=helpdesk;sa=restoreticket;ticket=' . $context['ticket']['id'] . ';' . $context['session_var'] . '=' . $context['session_id'], 'icon' => 'restore', 'alt' => '*', 'display' => $context['ticket']['deleted'] && (shd_allowed_to('shd_restore_ticket_any', $context['ticket']['dept']) || shd_allowed_to('shd_restore_ticket_own', $context['ticket']['dept']) && $context['ticket']['ticket_opener']), 'text' => 'shd_ticket_restore'); $context['ticket_navigation'][] = array('url' => $scripturl . '?action=helpdesk;sa=permadelete;ticket=' . $context['ticket']['id'] . ';' . $context['session_var'] . '=' . $context['session_id'], 'icon' => 'delete', 'alt' => '*', 'display' => $context['ticket']['deleted'] && shd_allowed_to('shd_delete_recycling', $context['ticket']['dept']), 'text' => 'shd_delete_permanently', 'onclick' => 'return confirm(' . JavaScriptEscape($txt['shd_delete_permanently_confirm']) . ');'); $context['ticket_navigation'][] = array('url' => $scripturl . '?action=helpdesk;sa=movedept;ticket=' . $context['ticket']['id'] . ';' . $context['session_var'] . '=' . $context['session_id'], 'icon' => 'movedept', 'alt' => '*', 'display' => $context['can_move_dept'], 'text' => 'shd_move_dept'); $context['ticket_navigation'][] = array('url' => $scripturl . '?action=helpdesk;sa=tickettotopic;ticket=' . $context['ticket']['id'] . ';' . $context['session_var'] . '=' . $context['session_id'], 'icon' => 'tickettotopic', 'alt' => '*', 'display' => $context['shd_can_move_to_topic'] && !$context['ticket']['closed'] && !$context['ticket']['deleted'] && ($context['ticket']['deleted_replies'] == 0 || shd_allowed_to('shd_access_recyclebin', $context['ticket']['dept'])), 'text' => 'shd_ticket_move_to_topic'); // While we're at it, set up general navigation for this ticket. We'll sort out access to the action log later. $context['navigation']['replies'] = array('text' => 'shd_go_to_replies', 'lang' => true, 'url' => '#replies'); $context['navigation']['ticketlog'] = array('text' => 'shd_go_to_action_log', 'test' => 'display_ticket_log', 'lang' => true, 'url' => '#ticket_log_header'); // If we are going SMF style with the navigation, we need to rework the structure a wee bit. // No sense making a new array, mind, just fix up the existing one a touch, and don't do this on the master as we don't always need it. if (empty($modSettings['shd_ticketnav_style']) || !in_array($modSettings['shd_ticketnav_style'], array('sd', 'sdcompact', 'smf'))) { $modSettings['shd_ticketnav_style'] = 'sd'; } if ($modSettings['shd_ticketnav_style'] == 'smf') { foreach ($context['ticket_navigation'] as $key => $button) { $context['can_' . $button['text']] = $button['display']; $context['ticket_navigation'][$key] += array('lang' => true, 'test' => 'can_' . $button['text'], 'image' => 'shd_ticket_' . $button['icon'] . '.png'); } } // Quick reply stuffs require_once $sourcedir . '/sd_source/SimpleDesk-Post.php'; require_once $sourcedir . '/Subs-Editor.php'; loadTemplate('sd_template/SimpleDesk-Post'); $context['ticket_form']['ticket'] = $context['ticket_id']; $context['ticket_form']['num_allowed_attachments'] = empty($modSettings['attachmentNumPerPostLimit']) || $modSettings['shd_attachments_mode'] == 'ticket' ? -1 : $modSettings['attachmentNumPerPostLimit']; $context['ticket_form']['do_attach'] = shd_allowed_to('shd_post_attachment', $context['ticket']['dept']); $context['ticket_form']['num_replies'] = $context['ticket']['num_replies']; $context['ticket_form']['disable_smileys'] = empty($modSettings['shd_allow_ticket_smileys']); shd_posting_additional_options(); if ($context['can_reply']) { shd_load_canned_replies(); } $context['can_ping'] = $context['can_reply'] && shd_allowed_to('shd_singleton_email', $context['ticket']['dept']); // Set up the fancy editor shd_postbox('shd_message', '', array('post_button' => $txt['shd_reply_ticket'])); // Lastly, our magic AJAX stuff ;D and we know we already made html_headers exist in SimpleDesk.php, score! $context['html_headers'] .= ' <script type="text/javascript"><!-- // --><![CDATA[ var sSessI = "' . $context['session_id'] . '"; var sSessV = "' . $context['session_var'] . '";'; if ($context['ticket']['privacy']['can_change']) { $context['html_headers'] .= ' var shd_ajax_problem = ' . JavaScriptEscape($txt['shd_ajax_problem']) . '; var privacyCtl = new shd_privacyControl({ ticket: ' . $context['ticket_id'] . ', sUrl: smf_scripturl + "?action=helpdesk;sa=ajax;op=privacy;ticket=' . $context['ticket_id'] . '", sSession: sSessV + "=" + sSessI, sSrcA: "privlink", sDestSpan: "privacy" });'; } if ($context['ticket']['urgency']['increase'] || $context['ticket']['urgency']['decrease']) { $context['html_headers'] .= ' var urgencyCtl = new shd_urgencyControl({ ticket: ' . $context['ticket_id'] . ', sUrl: smf_scripturl + "?action=helpdesk;sa=ajax;op=urgency;ticket=' . $context['ticket_id'] . ';change=", sSession: sSessV + "=" + sSessI, sDestSpan: "urgency", aButtons: ["up", "down"], aButtonOps: { up: "increase", down: "decrease" } });'; } if (!empty($options['display_quick_reply'])) { $context['html_headers'] .= ' var oQuickReply = new QuickReply({ bDefaultCollapsed: ' . (!empty($options['display_quick_reply']) && $options['display_quick_reply'] == 2 ? 'false' : 'true') . ', iTicketId: ' . $context['ticket_id'] . ', iStart: ' . $context['start'] . ', sScriptUrl: smf_scripturl, sImagesUrl: "' . $settings['images_url'] . '", sContainerId: "quickReplyOptions", sImageId: "quickReplyExpand", sImageCollapsed: "collapse.png", sImageExpanded: "expand.png", sJumpAnchor: "quickreply", sHeaderId: "quickreplyheader", sFooterId: "quickreplyfooter" });'; } $context['html_headers'] .= ' var oCustomFields = new CustomFields({ sImagesUrl: "' . $settings['images_url'] . '", sContainerId: "additional_info", sImageId: "shd_custom_fields_swap", sImageCollapsed: "collapse.png", sImageExpanded: "expand.png", sHeaderId: "additionalinfoheader", sFooterId: "additional_info_footer", });'; if (!empty($options['display_quick_reply']) && $context['can_go_advanced']) { $context['html_headers'] .= ' function goAdvanced() { document.getElementById("shd_bbcbox").style.display = ' . (!empty($modSettings['shd_allow_ticket_bbc']) ? '""' : '"none"') . '; document.getElementById("shd_smileybox").style.display = ' . (!empty($modSettings['shd_allow_ticket_smileys']) ? '""' : '"none"') . '; document.getElementById("shd_attach_container").style.display = ' . (!empty($context['ticket_form']['do_attach']) ? '""' : '"none"') . '; document.getElementById("shd_goadvancedbutton").style.display = "none";' . (!empty($context['controls']['richedit']['shd_message']['rich_active']) ? ' oEditorHandle_shd_message.toggleView(true);' : '') . ' } '; } $context['html_headers'] .= ' // ]' . ']></script>'; $context['shd_display'] = true; $context['controls']['richedit']['shd_message']['rich_active'] = 0; // we don't want it by default! // Register this form in the session variables. checkSubmitOnce('register'); // Should we load and display this ticket's action log? $context['display_ticket_log'] = !empty($modSettings['shd_display_ticket_logs']) && (shd_allowed_to('shd_view_ticket_logs_any', $context['ticket']['dept']) || shd_allowed_to('shd_view_ticket_logs_own', $context['ticket']['dept']) && $context['ticket']['ticket_opener']); // If yes, go ahead and load the log entries (Re-using a couple of functions from the ACP) if (!empty($context['display_ticket_log'])) { require_once $sourcedir . '/sd_source/Subs-SimpleDeskAdmin.php'; $context['ticket_log'] = shd_load_action_log_entries(-1, 10, '', '', 'la.id_ticket = ' . $context['ticket_id']); $context['ticket_log_count'] = shd_count_action_log_entries('la.id_ticket = ' . $context['ticket_id']); $context['ticket_full_log'] = allowedTo('admin_forum') || shd_allowed_to('admin_helpdesk', 0); } // What about related tickets? $context['create_relationships'] = shd_allowed_to('shd_create_relationships', $context['ticket']['dept']); $context['display_relationships'] = (shd_allowed_to('shd_view_relationships', $context['ticket']['dept']) || $context['create_relationships']) && empty($modSettings['shd_disable_relationships']); $context['delete_relationships'] = shd_allowed_to('shd_delete_relationships', $context['ticket']['dept']); if (!empty($context['display_relationships'])) { shd_load_relationships($context['ticket_id']); if ($context['relationships_count'] == 0 && empty($context['create_relationships'])) { $context['display_relationships'] = false; } } // And, of course, notifications. If we can see the ticket, we can do something with notifications. $context['display_notifications'] = array('show' => false, 'preferences' => array(), 'can_change' => shd_allowed_to(array('shd_view_profile_own', 'shd_view_profile_any'), 0) && shd_allowed_to(array('shd_view_preferences_own', 'shd_view_preferences_any'), 0), 'can_monitor' => shd_allowed_to('shd_monitor_ticket_any', $context['ticket']['dept']) || $context['ticket']['ticket_opener'] && shd_allowed_to('shd_monitor_ticket_own', $context['ticket']['dept']), 'is_monitoring' => false, 'can_ignore' => shd_allowed_to('shd_ignore_ticket_any', $context['ticket']['dept']) || $context['ticket']['ticket_opener'] && shd_allowed_to('shd_ignore_ticket_own', $context['ticket']['dept']), 'is_ignoring' => false); $notify_state = NOTIFY_PREFS; $query = $smcFunc['db_query']('', ' SELECT notify_state FROM {db_prefix}helpdesk_notify_override WHERE id_member = {int:user} AND id_ticket = {int:ticket}', array('user' => $context['user']['id'], 'ticket' => $context['ticket_id'])); if ($smcFunc['db_num_rows']($query) != 0) { list($notify_state) = $smcFunc['db_fetch_row']($query); } $smcFunc['db_free_result']($query); $context['display_notifications']['is_monitoring'] = $notify_state == NOTIFY_ALWAYS; $context['display_notifications']['is_ignoring'] = $notify_state == NOTIFY_NEVER; if ($notify_state != NOTIFY_NEVER) { if ($context['ticket']['ticket_opener'] && !empty($context['shd_preferences']['notify_new_reply_own'])) { $context['display_notifications']['preferences'][] = 'yourticket'; } if ($context['ticket']['assigned_self'] && !empty($context['shd_preferences']['notify_new_reply_assigned'])) { $context['display_notifications']['preferences'][] = 'assignedyou'; } if (!empty($context['shd_preferences']['notify_new_reply_previous'])) { // We need to query to see if we've replied here before - but we don't need to check ticket access. $query = $smcFunc['db_query']('', ' SELECT COUNT(hdtr.id_msg) FROM {db_prefix}helpdesk_tickets AS hdt INNER JOIN {db_prefix}helpdesk_ticket_replies AS hdtr ON (hdt.id_ticket = hdtr.id_ticket) WHERE hdt.id_ticket = {int:ticket} AND hdtr.id_member = {int:user} AND hdtr.id_msg != hdt.id_first_msg', array('ticket' => $context['ticket_id'], 'user' => $context['user']['id'])); list($count) = $smcFunc['db_fetch_row']($query); $smcFunc['db_free_result']($query); if (!empty($count)) { $context['display_notifications']['preferences'][] = 'priorreply'; } } if (!empty($context['shd_preferences']['notify_new_reply_any'])) { $context['display_notifications']['preferences'][] = 'anyreply'; } } if (!empty($context['display_notifications']['preferences']) || $context['display_notifications']['can_monitor'] || $context['display_notifications']['can_ignore'] || $context['display_notifications']['can_change']) { $context['display_notifications']['show'] = true; } }
/** * 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]); } } } } }
/** * Initialises the helpdesk action log. * * This function loads the language strings, and hands off to {@link shd_load_action_log_entries()} to perform the actual log * generation. * * Before doing so, however, this function will also prepare for deletion of old entries, as well as sorting out the columns and * ordering rules before handing control to the other function. * * @since 1.0 */ function shd_admin_action_log() { global $context, $settings, $scripturl, $txt, $sourcedir, $smcFunc, $sort_types; shd_load_language('sd_language/SimpleDeskLogAction'); $context['can_delete'] = allowedTo('admin_forum'); $context['displaypage'] = 30; $context['hoursdisable'] = 24; $context['waittime'] = time() - $context['hoursdisable'] * 3600; // Handle deletion... if (isset($_REQUEST['removeall']) && $context['can_delete']) { shd_db_query('', ' DELETE FROM {db_prefix}helpdesk_log_action WHERE log_time < {int:twenty_four_hours_wait}', array('twenty_four_hours_wait' => $context['waittime'])); } elseif (!empty($_REQUEST['remove']) && $context['can_delete']) { shd_db_query('', ' DELETE FROM {db_prefix}helpdesk_log_action WHERE id_action = {int:gtfo} AND log_time < {int:twenty_four_hours_wait}', array('twenty_four_hours_wait' => $context['waittime'], 'gtfo' => (int) $_REQUEST['remove'])); } // Do the column stuff! $sort_types = array('action' => 'la.action', 'time' => 'la.log_time', 'member' => 'mem.real_name', 'position' => 'mg.group_name', 'ip' => 'la.ip'); // Setup the direction stuff... $context['sort'] = isset($_REQUEST['sort']) && isset($sort_types[$_REQUEST['sort']]) ? $sort_types[$_REQUEST['sort']] : $sort_types['time']; $context['start'] = isset($_REQUEST['start']) ? $_REQUEST['start'] : 0; $context['order'] = isset($_REQUEST['asc']) ? 'ASC' : 'DESC'; $context['url_sort'] = isset($_REQUEST['sort']) ? ';sort=' . $_REQUEST['sort'] : ''; $context['url_order'] = isset($_REQUEST['asc']) ? ';asc' : ''; // Get all action log entries $context['actions'] = shd_load_action_log_entries($context['start'], $context['displaypage'], $context['sort'], $context['order']); $context['page_index'] = shd_no_expand_pageindex($scripturl . '?action=admin;area=helpdesk_info;sa=actionlog' . $context['url_sort'] . $context['url_order'], $context['start'], shd_count_action_log_entries(), $context['displaypage']); $context['sub_template'] = 'shd_action_log'; }