function shd_save_reply() { global $txt, $modSettings, $sourcedir, $context, $scripturl; global $user_info, $options, $smcFunc, $memberContext; $_REQUEST['msg'] = !empty($_REQUEST['msg']) ? (int) $_REQUEST['msg'] : 0; // We're replying so there must be an existing ticket or sumthin's WRONG. $ticketinfo = shd_load_ticket(); $reply = array(); $new_reply = $_REQUEST['msg'] == 0; // So, at this point, we can see it, but no guarantee we can reply to it. // Can we reply to any? If so, just go right along. If not, we need to do more work. if ($new_reply) { if (!shd_allowed_to('shd_reply_ticket_any', $ticketinfo['dept'])) { if (shd_allowed_to('shd_reply_ticket_own', $ticketinfo['dept'])) { if (!$ticketinfo['is_own']) { fatal_lang_error('shd_cannot_reply_any_but_own', false); } } else { fatal_lang_error('shd_cannot_reply_any', false); } // can't do nuthin' } } else { $query = shd_db_query('', ' SELECT id_msg, id_member, body, modified_time, modified_member, modified_name FROM {db_prefix}helpdesk_ticket_replies WHERE id_msg = {int:msg} AND id_ticket = {int:ticket}', array('msg' => $_REQUEST['msg'], 'ticket' => $context['ticket_id'])); if ($smcFunc['db_num_rows']($query) == 0) { $smcFunc['db_free_result']($query); fatal_lang_error('shd_no_ticket', false); } $reply = $smcFunc['db_fetch_assoc']($query); if (!shd_allowed_to('shd_edit_reply_any', $ticketinfo['dept'])) { if (shd_allowed_to('shd_edit_reply_own', $ticketinfo['dept'])) { if ($reply['id_member'] != $user_info['id']) { fatal_lang_error('shd_cannot_edit_reply_any_but_own', false); } } else { fatal_lang_error('shd_cannot_edit_reply_any', false); } } } $context['ticket_form'] = array('dept' => $ticketinfo['dept'], 'form_title' => $new_reply ? $txt['shd_reply_ticket'] : $txt['shd_ticket_edit_reply'], 'form_action' => $scripturl . '?action=helpdesk;sa=savereply', 'first_msg' => $new_reply ? 0 : $ticketinfo['id_first_msg'], 'message' => shd_format_text($ticketinfo['body'], $ticketinfo['smileys_enabled'], $new_reply ? '' : 'shd_reply_' . $ticketinfo['id_first_msg']), 'subject' => $ticketinfo['subject'], 'ticket' => $context['ticket_id'], 'msg' => $_REQUEST['msg'], 'display_id' => str_pad($context['ticket_id'], $modSettings['shd_zerofill'], '0', STR_PAD_LEFT), 'urgency' => array('setting' => $ticketinfo['urgency']), 'private' => array('setting' => $ticketinfo['private'], 'can_change' => false, 'options' => array(0 => 'shd_ticket_notprivate', 1 => 'shd_ticket_private')), 'status' => $ticketinfo['status'], 'member' => array('name' => $ticketinfo['starter_name'], 'id' => $ticketinfo['starter_id'], 'link' => shd_profile_link($ticketinfo['starter_name'], $ticketinfo['starter_id'])), 'assigned' => array('id' => $ticketinfo['assigned_id'], 'name' => !empty($ticketinfo['assigned_id']) ? $ticketinfo['assigned_name'] : $txt['shd_unassigned'], 'link' => !empty($ticketinfo['assigned_id']) ? shd_profile_link($ticketinfo['assigned_name'], $ticketinfo['assigned_id']) : '<span class="error">' . $txt['shd_unassigned'] . '</span>'), 'num_replies' => $ticketinfo['num_replies'], 'do_attach' => shd_allowed_to('shd_post_attachment', $ticketinfo['dept']), 'reply' => $_POST['shd_message'], 'return_to_ticket' => isset($_REQUEST['goback']), 'disable_smileys' => !empty($_REQUEST['no_smileys'])); $context['can_solve'] = shd_allowed_to('shd_resolve_ticket_any', $ticketinfo['dept']) || shd_allowed_to('shd_resolve_ticket_own', $ticketinfo['dept']) && $ticketinfo['starter_id'] == $user_info['id']; $context['can_silent_update'] = $new_reply && shd_allowed_to('shd_silent_update', $ticketinfo['dept']); $context['log_action'] = $new_reply ? 'newreply' : 'editreply'; $context['log_params']['subject'] = $context['ticket_form']['subject']; shd_posting_additional_options(); shd_load_canned_replies(); $context['can_ping'] = $new_reply && shd_allowed_to('shd_singleton_email', $context['ticket_form']['dept']); // Ticket privacy if (empty($modSettings['shd_privacy_display']) || $modSettings['shd_privacy_display'] == 'smart') { $context['display_private'] = shd_allowed_to('shd_view_ticket_private_any', $ticketinfo['dept']) || shd_allowed_to('shd_alter_privacy_own', $ticketinfo['dept']) || shd_allowed_to('shd_alter_privacy_any', $ticketinfo['dept']) || $context['ticket_form']['private']['setting']; } else { $context['display_private'] = true; } loadMemberData($ticketinfo['starter_id']); if (loadMemberContext($ticketinfo['starter_id'])) { $context['ticket_form']['member']['avatar'] = $memberContext[$ticketinfo['starter_id']]['avatar']; } if (!empty($ticketinfo['modified_time'])) { $context['ticket_form'] += array('modified' => array('name' => $ticketinfo['modified_name'], 'id' => $ticketinfo['modified_id'], 'time' => timeformat($ticketinfo['modified_time']), 'link' => shd_profile_link($ticketinfo['modified_name'], $ticketinfo['modified_id']))); } if (isset($_REQUEST['preview'])) { $context['ticket_form']['preview'] = array('title' => $txt['shd_previewing_reply'] . ': ' . (empty($context['ticket_form']['subject']) ? '<em>' . $txt['no_subject'] . '</em>' : $context['ticket_form']['subject']), 'body' => shd_format_text($_POST['shd_message'])); } shd_load_attachments(); shd_get_urgency_options($ticketinfo['is_own'], $ticketinfo['dept']); $context['ticket_form']['urgency']['can_change'] = false; if (!empty($ticketinfo['num_replies'])) { shd_setup_replies($ticketinfo['id_first_msg']); } // A few basic checks if ($context['ticket_form']['status'] == TICKET_STATUS_CLOSED) { fatal_lang_error('shd_cannot_edit_closed', false); } elseif ($context['ticket_form']['status'] == TICKET_STATUS_DELETED) { fatal_lang_error('shd_cannon_edit_deleted', false); } // Have there been any new replies that we missed? if (empty($options['no_new_reply_warning']) && isset($_REQUEST['num_replies'])) { $_REQUEST['num_replies'] = (int) $_REQUEST['num_replies']; $newReplies = $context['ticket_form']['num_replies'] > $_REQUEST['num_replies'] ? $context['ticket_form']['num_replies'] - $_REQUEST['num_replies'] : 0; if (!empty($newReplies)) { loadLanguage('Post'); if ($newReplies > 1) { $txt['error_new_replies'] = sprintf($txt['error_new_replies'], $newReplies); } $context['shd_errors'][] = $newReplies == 1 ? 'new_reply' : 'new_replies'; } } // OK, does the user want to close this ticket? Are there any problems with that? if (!empty($context['can_solve']) && !empty($_POST['resolve_ticket'])) { $string = shd_check_dependencies(); if (!empty($string)) { $context['shd_errors'][] = $string; } } // Custom fields? shd_load_custom_fields(false, $context['ticket_form']['msg'], $context['ticket_form']['dept']); list($missing_fields, $invalid_fields) = shd_validate_custom_fields($context['ticket_form']['msg'], $context['ticket_form']['dept']); $context['can_override_fields'] = shd_allowed_to('shd_override_cf', $context['ticket_form']['dept']); $context['overriding_fields'] = $context['can_override_fields'] && isset($_POST['override_cf']); // Did any custom fields fail validation? if (!empty($invalid_fields)) { $context['shd_errors'][] = 'invalid_fields'; $txt['error_invalid_fields'] = sprintf($txt['error_invalid_fields'], implode(', ', $invalid_fields)); } // Any flat-out missing? if (!empty($missing_fields) && !$context['overriding_fields']) { $context['shd_errors'][] = 'missing_fields'; $txt['error_missing_fields'] = sprintf($txt['error_missing_fields'], implode(', ', $missing_fields)); } if ($context['can_override_fields'] && !empty($missing_fields)) { $context['ticket_form']['additional_opts']['override_cf'] = array('show' => true, 'checked' => false, 'text' => $txt['shd_override_cf']); } if (!empty($context['shd_errors']) || !empty($context['ticket_form']['preview'])) { checkSubmitOnce('free'); // Anything else for redisplaying the form $context['page_title'] = $txt['shd_helpdesk']; $context['sub_template'] = 'reply_post'; // Oh, yeah, we need to look at the existing notifications pinging stuff, if appropriate, and reset that. if ($context['can_ping'] && !empty($_POST['notify']) && is_array($_POST['notify'])) { $items = array(); foreach ($_POST['notify'] as $item) { if (!empty($item) && is_numeric($item)) { $items[] = $item; } } if (!empty($items)) { $context['notification_ping_list'] = implode(',', $items); } } shd_check_attachments(); // Set up the fancy editor shd_postbox('shd_message', un_preparsecode($_POST['shd_message']), array('post_button' => $new_reply ? $txt['shd_reply_ticket'] : $txt['shd_ticket_edit_reply'])); // Build the link tree and navigation $context['linktree'][] = array('name' => $txt['shd_reply_ticket']); checkSubmitOnce('register'); } else { // It all worked, w00t, so let's get ready to rumble $attachIDs = shd_handle_attachments(); if ($new_reply) { // So... what is the new status? $new_status = shd_determine_status('reply', $ticketinfo['starter_id'], $user_info['id'], -1, $context['ticket_form']['dept']); // We explicitly don't care about how many replies - but it must be non-zero. Default in function spec is -1. // Now to add the ticket details $posterOptions = array('id' => $user_info['id']); $msgOptions = array('body' => $_POST['shd_message'], 'id' => $context['ticket_form']['msg'], 'smileys_enabled' => empty($context['ticket_form']['disable_smileys']), 'attachments' => $attachIDs, 'custom_fields' => !empty($context['ticket_form']['custom_fields'][$context['ticket_form']['msg']]) ? $context['ticket_form']['custom_fields'][$context['ticket_form']['msg']] : array()); $ticketOptions = array('id' => $context['ticket_form']['ticket'], 'mark_as_read' => true, 'status' => $new_status); if (!empty($context['can_solve']) && !empty($_POST['resolve_ticket'])) { $ticketOptions['status'] = TICKET_STATUS_CLOSED; shd_log_action('resolve', array('ticket' => $context['ticket_id'], 'subject' => $ticketinfo['subject'])); } shd_create_ticket_post($msgOptions, $ticketOptions, $posterOptions); // Handle notifications require_once $sourcedir . '/sd_source/SimpleDesk-Notifications.php'; shd_notifications_notify_newreply($msgOptions, $ticketOptions, $posterOptions); } else { // Only add what has actually changed // Now to add the ticket details $posterOptions = array(); $msgOptions = array('id' => $context['ticket_form']['msg'], 'attachments' => $attachIDs, 'custom_fields' => !empty($context['ticket_form']['custom_fields'][$context['ticket_form']['msg']]) ? $context['ticket_form']['custom_fields'][$context['ticket_form']['msg']] : array()); $ticketOptions = array('id' => $context['ticket_form']['ticket']); if ((bool) $ticketinfo['smileys_enabled'] == $context['ticket_form']['disable_smileys']) { // since one is enabled, one is 'now disable'... $msgOptions['smileys_enabled'] = !$context['ticket_form']['disable_smileys']; } if ($reply['body'] != $context['ticket_form']['reply']) { $msgOptions['body'] = $context['ticket_form']['reply']; } if (isset($msgOptions['body'])) { $msgOptions['modified'] = array('id' => $user_info['id'], 'name' => $user_info['name'], 'time' => time()); } if (!empty($context['can_solve']) && !empty($_POST['resolve_ticket'])) { $ticketOptions['status'] = TICKET_STATUS_CLOSED; shd_log_action('resolve', array('ticket' => $context['ticket_id'], 'subject' => $ticketinfo['subject'])); } // DOOOOOOOO EEEEEEEEEEET NAO! shd_modify_ticket_post($msgOptions, $ticketOptions, $posterOptions); // OK, did we get any custom fields back? foreach ($context['custom_fields_updated'] as $field) { $action = 'cf_' . ($field['scope'] == CFIELD_TICKET ? 'tkt' : 'rpl') . (empty($field['default']) ? 'change_' : 'chgdef_') . ($field['visible'][0] ? 'user' : '') . ($field['visible'][1] ? 'staff' : '') . 'admin'; unset($field['default'], $field['scope'], $field['visible']); $field['subject'] = $ticketinfo['subject']; shd_log_action($action, $field); } } $context['ticket_form']['msg'] = $msgOptions['id']; shd_done_posting(); } }
/** * 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; } }