diff --git a/css/thread.css b/css/thread.css index 6a9ebbd38d8aa81bc266ddb29f083f951f10ff15..049165780c799beed80f45e1e4fc8f1f24a0cb65 100644 --- a/css/thread.css +++ b/css/thread.css @@ -277,6 +277,7 @@ padding: 10px 20px; margin: 0 0 20px; border-left: 5px solid #eeeeee; + color: #777; } .thread-body blockquote p { font-weight: 300; @@ -415,7 +416,6 @@ .thread-body ol, .thread-body table, .thread-body dl, -.thread-body blockquote, .thread-body pre { margin: 0; margin-bottom: 10px; diff --git a/include/ajax.kbase.php b/include/ajax.kbase.php index c6bbd3156ecba7893839e0e1bc8c1404a32f9266..2f5bc75bfa6e0a8c88c9ab7ab2b4a0961224eb23 100644 --- a/include/ajax.kbase.php +++ b/include/ajax.kbase.php @@ -18,7 +18,7 @@ if(!defined('INCLUDE_DIR')) die('!'); class KbaseAjaxAPI extends AjaxController { - function cannedResp($id, $format='') { + function cannedResp($id, $format='text') { global $thisstaff, $cfg; include_once(INCLUDE_DIR.'class.canned.php'); @@ -26,39 +26,10 @@ class KbaseAjaxAPI extends AjaxController { if(!$id || !($canned=Canned::lookup($id)) || !$canned->isEnabled()) Http::response(404, 'No such premade reply'); - //Load ticket. - if($_GET['tid']) { - include_once(INCLUDE_DIR.'class.ticket.php'); - $ticket = Ticket::lookup($_GET['tid']); - } - - $resp = array(); - switch($format) { - case 'json': - $resp['id'] = $canned->getId(); - $resp['ticket'] = $canned->getTitle(); - $resp['response'] = $ticket - ? $ticket->replaceVars($canned->getResponseWithImages()) - : $canned->getResponseWithImages(); - $resp['files'] = $canned->attachments->getSeparates(); - - if (!$cfg->isHtmlThreadEnabled()) { - $resp['response'] = Format::html2text($resp['response'], 90); - $resp['files'] += $canned->attachments->getInlines(); - } - - $response = $this->json_encode($resp); - break; - - case 'txt': - default: - $response =$ticket?$ticket->replaceVars($canned->getResponse()):$canned->getResponse(); - - if (!$cfg->isHtmlThreadEnabled()) - $response = Format::html2text($response, 90); - } + if (!$cfg->isHtmlThreadEnabled()) + $format .= '.plain'; - return $response; + return $canned->getFormattedResponse($format); } function faq($id, $format='html') { diff --git a/include/ajax.tickets.php b/include/ajax.tickets.php index 445733dc6f80fc0283e72740e742f79aabd19b24..5722a76a78dac30cb36667808fc32e47c8fc8924 100644 --- a/include/ajax.tickets.php +++ b/include/ajax.tickets.php @@ -657,5 +657,40 @@ class TicketsAjaxAPI extends AjaxController { Http::response(201, 'Successfully managed'); } + function cannedResponse($tid, $cid, $format='text') { + global $thisstaff, $cfg; + + if (!($ticket = Ticket::lookup($tid)) + || !$ticket->checkStaffAccess($thisstaff)) + Http::response(404, 'Unknown ticket ID'); + + + if ($cid && !is_numeric($cid)) { + if (!($response=$ticket->getThread()->getVar($cid))) + Http::response(422, 'Unknown ticket variable'); + + // Ticket thread variables are assumed to be quotes + $response = "<br/><blockquote>$response</blockquote><br/>"; + // Return text if html thread is not enabled + if (!$cfg->isHtmlThreadEnabled()) + $response = Format::html2text($response, 90); + + // XXX: assuming json format for now. + return Format::json_encode(array('response' => $response)); + } + + if (!$cfg->isHtmlThreadEnabled()) + $format.='.plain'; + + $varReplacer = function (&$var) use($ticket) { + return $ticket->replaceVars($var); + }; + + include_once(INCLUDE_DIR.'class.canned.php'); + if (!$cid || !($canned=Canned::lookup($cid)) || !$canned->isEnabled()) + Http::response(404, 'No such premade reply'); + + return $canned->getFormattedResponse($format, $varReplacer); + } } ?> diff --git a/include/class.ajax.php b/include/class.ajax.php index c852a551734a572662e75de6a6d18c43e1bc8892..3be9713d89be8d1d2391f4c49c22919a5baccf78 100644 --- a/include/class.ajax.php +++ b/include/class.ajax.php @@ -38,9 +38,7 @@ class AjaxController extends ApiController { * Convert a PHP array into a JSON-encoded string */ function json_encode($what) { - require_once (INCLUDE_DIR.'class.json.php'); - $encoder = new JsonDataEncoder(); - return $encoder->encode($what); + return Format::json_encode($what); } function encode($what) { diff --git a/include/class.canned.php b/include/class.canned.php index 457c6d8f904eaaf476bc3744422989f17c940169..bfb5e82ce5e09a6eca8dab6f16aeda2e0485cc4f 100644 --- a/include/class.canned.php +++ b/include/class.canned.php @@ -86,6 +86,60 @@ class Canned { return $this->getResponse(); } + function getHtml() { + return $this->getFormattedResponse('html'); + } + + function getPlainText() { + return $this->getFormattedResponse('text.plain'); + } + + function getFormattedResponse($format='text', $cb=null) { + + $resp = array(); + $html = true; + switch($format) { + case 'json.plain': + $html = false; + // fall-through + case 'json': + $resp['id'] = $this->getId(); + $resp['title'] = $this->getTitle(); + $resp['response'] = $this->getResponseWithImages(); + + // Callback to strip or replace variables! + if ($cb && is_callable($cb)) + $resp = $cb($resp); + + $resp['files'] = $this->attachments->getSeparates(); + // strip html + if (!$html) { + $resp['response'] = Format::html2text($resp['response'], 90); + $resp['files'] += $this->attachments->getInlines(); + } + return Format::json_encode($resp); + break; + case 'html': + case 'text.html': + $response = $this->getResponseWithImages(); + break; + case 'text.plain': + $html = false; + case 'text': + default: + $response = $this->getResponse(); + if (!$html) + $response = Format::html2text($response, 90); + break; + } + + // Callback to strip or replace variables! + if ($response && $cb && is_callable($cb)) + $response = $cb($response); + + return $response; + } + function getNotes() { return $this->ht['notes']; } diff --git a/include/class.format.php b/include/class.format.php index 3b841a4a585db66be41e2485acd5cf866b319d00..4c73d5188f5c1ab46e5b4d712f80c57f7106c9cc 100644 --- a/include/class.format.php +++ b/include/class.format.php @@ -99,6 +99,15 @@ class Format { return $filename; } + /** + * Json Encoder + * + */ + function json_encode($what) { + require_once (INCLUDE_DIR.'class.json.php'); + return JsonDataEncoder::encode($what); + } + function phone($phone) { $stripped= preg_replace("/[^0-9]/", "", $phone); diff --git a/include/class.ticket.php b/include/class.ticket.php index 57a8077e5d6361ba5ee048e42be7f8242960c912..63dde20fa9e247ca48643e82d1b407347ce7e2f1 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -1670,9 +1670,16 @@ class Ticket { foreach ($canned->attachments->getAll() as $file) $files[] = $file['id']; + if ($cfg->isHtmlThreadEnabled()) + $response = new HtmlThreadBody( + $this->replaceVars($canned->getHtml())); + else + $response = new TextThreadBody( + $this->replaceVars($canned->getPlainText())); + $info = array('msgId' => $msgId, 'poster' => 'SYSTEM (Canned Reply)', - 'response' => $this->replaceVars($canned->getResponse()), + 'response' => $response, 'cannedattachments' => $files); $errors = array(); diff --git a/include/i18n/en_US/templates/premade.yaml b/include/i18n/en_US/templates/premade.yaml index 26880b7c13739628a43620da83cf1e266a3259fa..94f2def11c938a70694010cb9de61542e24f735b 100644 --- a/include/i18n/en_US/templates/premade.yaml +++ b/include/i18n/en_US/templates/premade.yaml @@ -2,7 +2,8 @@ # Canned response templates # --- -- title: What is osTicket (sample)? +- isenabled:1 + title: What is osTicket (sample)? response: | osTicket is a widely-used open source support ticket system, an attractive alternative to higher-cost and complex customer support @@ -15,7 +16,8 @@ type: text/plain data: Canned Attachments Rock! -- title: Sample (with variables) +- isenabled: 1 + title: Sample (with variables) response: | Hi %{ticket.name.first}, <br> diff --git a/include/staff/ticket-view.inc.php b/include/staff/ticket-view.inc.php index d0b1b34d757b858a64c83faab0fb1b28175aa8f8..a63df79ea83538377ed3c84512c1fddac1077807 100644 --- a/include/staff/ticket-view.inc.php +++ b/include/staff/ticket-view.inc.php @@ -505,19 +505,21 @@ $tcount+= $ticket->getNumNotes(); <label><strong>Response:</strong></label> </td> <td> - <?php - if(($cannedResponses=Canned::responsesByDeptId($ticket->getDeptId()))) {?> - <select id="cannedResp" name="cannedResp"> - <option value="0" selected="selected">Select a canned response</option> - <?php - foreach($cannedResponses as $id =>$title) { + <select id="cannedResp" name="cannedResp"> + <option value="0" selected="selected">Select a canned response</option> + <option value='lastmessage'>Original Message</option> + <option value='original'>Last Message</option> + <?php + if(($cannedResponses=Canned::responsesByDeptId($ticket->getDeptId()))) { + echo '<option value="0" disabled="disabled"> + ------------- Premade Replies ------------- </option>'; + foreach($cannedResponses as $id =>$title) echo sprintf('<option value="%d">%s</option>',$id,$title); - } - ?> - </select> - <br> + } + ?> + </select> + <br> <?php - } $signature = ''; switch ($thisstaff->getDefaultSignatureType()) { case 'dept': diff --git a/scp/ajax.php b/scp/ajax.php index 6f784080b2d8d018a35274792b4e6f8005403a9f..a192cce8cf92da76bf185a441840093133d03099 100644 --- a/scp/ajax.php +++ b/scp/ajax.php @@ -137,7 +137,8 @@ $dispatcher = patterns('', url_get('^lookup', 'lookup'), url_get('^search', 'search'), url_get('^(?P<tid>\d+)/forms/manage$', 'manageForms'), - url_post('^(?P<tid>\d+)/forms/manage$', 'updateForms') + url_post('^(?P<tid>\d+)/forms/manage$', 'updateForms'), + url_get('^(?P<tid>\d+)/canned-resp/(?P<cid>\w+).(?P<format>json|txt)', 'cannedResponse') )), url('^/collaborators/', patterns('ajax.tickets.php:TicketsAjaxAPI', url_get('^(?P<cid>\d+)/view$', 'viewCollaborator'), diff --git a/scp/js/scp.js b/scp/js/scp.js index 254ba5fd568deff7433400721bb67ff05864edc5..d79b03955150d2221fe8a3ef920c1a021db5b301 100644 --- a/scp/js/scp.js +++ b/scp/js/scp.js @@ -195,16 +195,18 @@ var scp_prep = function() { $('form select#cannedResp').change(function() { - var fObj=$(this).closest('form'); - var cannedId = $(this).val(); - var ticketId = $(':input[name=id]',fObj).val(); - + var fObj = $(this).closest('form'); + var cid = $(this).val(); + var tid = $(':input[name=id]',fObj).val(); $(this).find('option:first').attr('selected', 'selected').parent('select'); + var $url = 'ajax.php/kb/canned-response/'+cid+'.json'; + if (tid) + $url = 'ajax.php/tickets/'+tid+'/canned-resp/'+cid+'.json'; + $.ajax({ type: "GET", - url: 'ajax.php/kb/canned-response/'+cannedId+'.json', - data: 'tid='+ticketId, + url: $url, dataType: 'json', cache: false, success: function(canned){