/**
 *	Updates a ticket's urgency up or down one level, if the user isn't using Javascript
 *
 *	Assuming the user can see the ticket and has suitable permissions, the urgency of the ticket will be updated and an
 *	action log entry added. If they cannot see the ticket, or do not have urgency-change permission (including higher
 *	urgency permission if necessary), a fatal error will be generated.
 *
 *	Accessed through ?action=helpdesk;sa=urgencychange;ticket=x;change=(increase|decrease);sessvar=sessid before directing back to the main helpdesk page.
 *
 *	@see shd_can_alter_urgency()
 *
 *	@since 1.0
*/
function shd_urgency_change_noajax()
{
    global $smcFunc, $user_info, $context, $sourcedir;
    checkSession('get');
    // First, figure out the state of the ticket - is it private or not? Can we even see it? Current urgency?
    if (empty($context['ticket_id'])) {
        fatal_lang_error('shd_no_ticket', false);
    }
    $query = shd_db_query('', '
		SELECT id_member_started, subject, urgency, status, id_dept
		FROM {db_prefix}helpdesk_tickets AS hdt
		WHERE {query_see_ticket}
			AND id_ticket = {int:current_ticket}', array('current_ticket' => $context['ticket_id']));
    if ($row = $smcFunc['db_fetch_assoc']($query)) {
        $can_urgency = shd_can_alter_urgency($row['urgency'], $row['id_member_started'], $row['status'] == TICKET_STATUS_CLOSED, $row['status'] == TICKET_STATUS_DELETED, $row['id_dept']);
        if (empty($_GET['change']) || empty($can_urgency[$_GET['change']])) {
            fatal_lang_error('shd_cannot_change_urgency');
        }
        $new_urgency = $row['urgency'] + ($_GET['change'] == 'increase' ? 1 : -1);
        $action = 'urgency_' . $_GET['change'];
        require_once $sourcedir . '/sd_source/Subs-SimpleDeskPost.php';
        $msgOptions = array();
        $posterOptions = array();
        $ticketOptions = array('id' => $context['ticket_id'], 'urgency' => $new_urgency);
        shd_modify_ticket_post($msgOptions, $ticketOptions, $posterOptions);
        shd_log_action($action, array('ticket' => $context['ticket_id'], 'subject' => $row['subject'], 'urgency' => $new_urgency));
        redirectexit('action=helpdesk;sa=ticket;ticket=' . $context['ticket_id']);
    } else {
        fatal_lang_error('shd_no_ticket', false);
    }
}
Example #2
0
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();
    }
}
/**
 *	Actually commits a ticket assignment to the database.
 *
 *	This function sets up the relevant options before handing over to shd_modify_ticket_post() which is the preferred way to modify
 *	tickets generally. No permissions check is performed here.
 *
 *	Relies on $context['shd_return_to'] to have been set, defaults to 'ticket' to return to ticket, otherwise return to home page
 *	on value of 'home'.
 *
 *	@param int $ticket Ticket id number, assumed to exist.
 *	@param int $assignment User id of the user to which this ticket will be assigned; can be 0 to unassign a ticket
 *
 *	@see shd_assign()
 *	@see shd_assign2()
*/
function shd_commit_assignment($ticket, $assignment, $is_ajax = false)
{
    global $smcFunc, $sourcedir, $context, $modSettings;
    require_once $sourcedir . '/sd_source/Subs-SimpleDeskPost.php';
    $msgOptions = array();
    $posterOptions = array();
    $ticketOptions = array('id' => $context['ticket_id'], 'assigned' => $assignment);
    // Int hooks - after we've set everything up but before we actually press the button
    call_integration_hook('shd_hook_assign', array(&$ticket, &$assignment));
    shd_modify_ticket_post($msgOptions, $ticketOptions, $posterOptions);
    // Handle notifications
    require_once $sourcedir . '/sd_source/SimpleDesk-Notifications.php';
    shd_notifications_notify_assign($ticket, $assignment);
    // If we're doing it AJAXively, we just want this to do the job and then go back to AJAX workflow.
    if ($is_ajax) {
        return;
    }
    if (!empty($context['shd_return_to']) && $context['shd_return_to'] == 'home') {
        redirectexit($context['shd_home'] . $context['shd_dept_link']);
    } else {
        redirectexit('action=helpdesk;sa=ticket;ticket=' . $ticket);
    }
}
/**
 *	Handles AJAX updates to ticket urgency.
 *
 *	Receives request through ?action=helpdesk;sa=ajax;op=urgency;change=x where x is increase or decrease.
 *
 *	Operations:
 *	- silent session check; if fail, add to $context['ajax_return']['error']
 *	- ticket id check; if fail, add to $context['ajax_return']['error']
 *	- get enough ticket data to do this
 *	- check permissions with {@link shd_can_alter_urgency()} and permissions; if fail, add to $context['ajax_return']['error']
 *	- identify whether the new urgency needs 'urgent' styling or not and put the new urgency in $context['ajax_return']['message']
 *	- update the database with the new urgency
 *	- identify whether the new urgency continues to allow the current user to change urgency or not
 *	- put the button links if appropriate into $context['ajax_return']['increase'] and $context['ajax_return']['decrease'] and return
*/
function shd_ajax_urgency()
{
    global $smcFunc, $user_info, $context, $txt, $scripturl, $settings, $sourcedir;
    $session_check = checkSession('get', '', false);
    // check the session but don't die fatally.
    if (!empty($session_check)) {
        $context['ajax_return'] = array('error' => $txt[$session_check]);
        return;
    }
    // First, figure out the state of the ticket - is it private or not? Can we even see it?
    if (empty($context['ticket_id'])) {
        $context['ajax_return'] = array('error' => $txt['shd_no_ticket']);
        return;
    }
    $query = shd_db_query('', '
		SELECT id_member_started, subject, urgency, status, id_dept
		FROM {db_prefix}helpdesk_tickets AS hdt
		WHERE {query_see_ticket}
			AND id_ticket = {int:current_ticket}', array('current_ticket' => $context['ticket_id']));
    if ($row = $smcFunc['db_fetch_assoc']($query)) {
        $can_urgency = shd_can_alter_urgency($row['urgency'], $row['id_member_started'], $row['status'] == TICKET_STATUS_CLOSED, $row['status'] == TICKET_STATUS_DELETED, $row['id_dept']);
        if (empty($_GET['change']) || empty($can_urgency[$_GET['change']])) {
            $context['ajax_return'] = array('error' => $txt['shd_cannot_change_urgency']);
            return;
        }
        $new_urgency = $row['urgency'] + ($_GET['change'] == 'increase' ? 1 : -1);
        $action = 'urgency_' . $_GET['change'];
        require_once $sourcedir . '/sd_source/Subs-SimpleDeskPost.php';
        $msgOptions = array();
        $posterOptions = array();
        $ticketOptions = array('id' => $context['ticket_id'], 'urgency' => $new_urgency);
        shd_modify_ticket_post($msgOptions, $ticketOptions, $posterOptions);
        shd_log_action($action, array('ticket' => $context['ticket_id'], 'subject' => $row['subject'], 'urgency' => $new_urgency));
        $new_options = shd_can_alter_urgency($new_urgency, $row['id_member_started'], $row['status'] == TICKET_STATUS_CLOSED, $row['status'] == TICKET_STATUS_DELETED, $row['id_dept']);
        $context['ajax_return'] = array('message' => $new_urgency > TICKET_URGENCY_HIGH ? '<span class="error">' . $txt['shd_urgency_' . $new_urgency] . '</span>' : $txt['shd_urgency_' . $new_urgency]);
        $array = array('increase' => '<a id="urglink_increase" href="' . $scripturl . '?action=helpdesk;sa=urgencychange;ticket=' . $context['ticket_id'] . ';change=increase;' . $context['session_var'] . '=' . $context['session_id'] . '" title="' . $txt['shd_urgency_increase'] . '"><img src="' . $settings['images_url'] . '/sort_up.png" width="9px" alt="' . $txt['shd_urgency_increase'] . '" /></a>', 'decrease' => '<a id="urglink_decrease" href="' . $scripturl . '?action=helpdesk;sa=urgencychange;ticket=' . $context['ticket_id'] . ';change=decrease;' . $context['session_var'] . '=' . $context['session_id'] . '" title="' . $txt['shd_urgency_decrease'] . '"><img src="' . $settings['images_url'] . '/sort_down.png" width="9px" alt="' . $txt['shd_urgency_decrease'] . '" /></a>');
        foreach ($new_options as $button => $can) {
            if ($can) {
                $context['ajax_return'][$button] = $array[$button];
            }
        }
        return;
    } else {
        $context['ajax_return'] = array('error' => $txt['shd_no_ticket']);
        return;
    }
}