1<?php 2/********************************************************************* 3 class.canned.php 4 5 Canned Responses AKA Premade replies 6 7 Peter Rotich <peter@osticket.com> 8 Copyright (c) 2006-2013 osTicket 9 http://www.osticket.com 10 11 Released under the GNU General Public License WITHOUT ANY WARRANTY. 12 See LICENSE.TXT for details. 13 14 vim: expandtab sw=4 ts=4 sts=4: 15**********************************************************************/ 16include_once(INCLUDE_DIR.'class.file.php'); 17 18class Canned 19extends VerySimpleModel { 20 static $meta = array( 21 'table' => CANNED_TABLE, 22 'pk' => array('canned_id'), 23 'joins' => array( 24 'dept' => array( 25 'constraint' => array('dept_id' => 'Dept.id'), 26 'null' => true, 27 ), 28 'attachments' => array( 29 'constraint' => array( 30 "'C'" => 'Attachment.type', 31 'canned_id' => 'Attachment.object_id', 32 ), 33 'list' => true, 34 'null' => true, 35 'broker' => 'GenericAttachments', 36 ), 37 ), 38 ); 39 40 const PERM_MANAGE = 'canned.manage'; 41 42 static protected $perms = array( 43 self::PERM_MANAGE => array( 44 'title' => 45 /* @trans */ 'Premade', 46 'desc' => 47 /* @trans */ 'Ability to add/update/disable/delete canned responses') 48 ); 49 50 static function getPermissions() { 51 return self::$perms; 52 } 53 54 function getId(){ 55 return $this->canned_id; 56 } 57 58 function isEnabled() { 59 return $this->isenabled; 60 } 61 62 function isActive(){ 63 return $this->isEnabled(); 64 } 65 66 function getFilters() { 67 68 if (!isset($this->_filters)) { 69 $this->_filters = array(); 70 $cid = sprintf('"canned_id":%d', $this->getId()); 71 $sql='SELECT filter.id, filter.name ' 72 .' FROM '.FILTER_TABLE.' filter' 73 .' INNER JOIN '.FILTER_ACTION_TABLE.' action' 74 .' ON (filter.id=action.filter_id)' 75 .' WHERE action.type="canned"' 76 ." AND action.configuration LIKE '%$cid%'"; 77 78 if (($res=db_query($sql)) && db_num_rows($res)) 79 while (list($id, $name) = db_fetch_row($res)) 80 $this->_filters[$id] = $name; 81 } 82 83 return $this->_filters; 84 } 85 86 function getAttachedFiles($inlines=false) { 87 return AttachmentFile::objects() 88 ->filter(array( 89 'attachments__type'=>'C', 90 'attachments__object_id'=>$this->getId(), 91 'attachments__inline' => $inlines, 92 )); 93 } 94 95 function getNumFilters() { 96 return count($this->getFilters()); 97 } 98 99 function getTitle() { 100 return $this->title; 101 } 102 103 function getResponse() { 104 return $this->response; 105 } 106 function getResponseWithImages() { 107 return Format::viewableImages($this->getResponse()); 108 } 109 110 function getReply() { 111 return $this->getResponse(); 112 } 113 114 function getHtml() { 115 return $this->getFormattedResponse('html'); 116 } 117 118 function getPlainText() { 119 return $this->getFormattedResponse('text.plain'); 120 } 121 122 function getFormattedResponse($format='text', $cb=null) { 123 124 $resp = array(); 125 $html = true; 126 switch($format) { 127 case 'json.plain': 128 $html = false; 129 // fall-through 130 case 'json': 131 $resp['id'] = $this->getId(); 132 $resp['title'] = $this->getTitle(); 133 $resp['response'] = $this->getResponseWithImages(); 134 135 // Callback to strip or replace variables! 136 if ($cb && is_callable($cb)) 137 $resp = $cb($resp); 138 139 $resp['files'] = array(); 140 foreach ($this->getAttachedFiles(!$html) as $file) { 141 $_SESSION[':cannedFiles'][$file->id] = $file->name; 142 $resp['files'][] = array( 143 'id' => $file->id, 144 'name' => $file->name, 145 'size' => $file->size, 146 'download_url' => $file->getDownloadUrl(), 147 ); 148 } 149 // strip html 150 if (!$html) { 151 $resp['response'] = Format::html2text($resp['response'], 90); 152 } 153 154 return Format::json_encode($resp); 155 break; 156 case 'html': 157 case 'text.html': 158 $response = $this->getResponseWithImages(); 159 break; 160 case 'text.plain': 161 $html = false; 162 case 'text': 163 default: 164 $response = $this->getResponse(); 165 if (!$html) 166 $response = Format::html2text($response, 90); 167 break; 168 } 169 170 // Callback to strip or replace variables! 171 if ($response && $cb && is_callable($cb)) 172 $response = $cb($response); 173 174 return $response; 175 } 176 177 function getNotes() { 178 return $this->ht['notes']; 179 } 180 181 function getDeptId(){ 182 return $this->ht['dept_id']; 183 } 184 185 function getHashtable() { 186 $base = $this->ht; 187 unset($base['attachments']); 188 return $base; 189 } 190 191 function getInfo() { 192 return $this->getHashtable(); 193 } 194 195 function getNumAttachments() { 196 return $this->attachments->count(); 197 } 198 199 function delete(){ 200 if ($this->getNumFilters() > 0) 201 return false; 202 203 if (!parent::delete()) 204 return false; 205 206 $type = array('type' => 'deleted'); 207 Signal::send('object.deleted', $this, $type); 208 209 $this->attachments->deleteAll(); 210 211 return true; 212 } 213 214 /*** Static functions ***/ 215 216 static function create($vars=false) { 217 $faq = new static($vars); 218 $faq->created = SqlFunction::NOW(); 219 return $faq; 220 } 221 222 static function getIdByTitle($title) { 223 $row = static::objects() 224 ->filter(array('title' => $title)) 225 ->values_flat('canned_id') 226 ->first(); 227 228 return $row ? $row[0] : null; 229 } 230 231 static function getCannedResponses($deptId=0, $explicit=false) { 232 global $thisstaff; 233 234 $canned = static::objects() 235 ->filter(array('isenabled' => true)) 236 ->order_by('title') 237 ->values_flat('canned_id', 'title'); 238 239 if ($thisstaff) { 240 $staffDepts = array(); 241 242 $staffDepts = $thisstaff->getDepts(); 243 $staffDepts[] = 0; 244 245 $canned->filter(array('dept_id__in' => $staffDepts)); 246 } 247 248 if ($deptId) { 249 $depts = array($deptId); 250 if (!$explicit) 251 $depts[] = 0; 252 $canned->filter(array('dept_id__in' => $depts)); 253 } 254 255 $responses = array(); 256 foreach ($canned as $row) { 257 list($id, $title) = $row; 258 $responses[$id] = $title; 259 } 260 261 return $responses; 262 } 263 264 function responsesByDeptId($deptId, $explicit=false) { 265 return self::getCannedResponses($deptId, $explicit); 266 } 267 268 function save($refetch=false) { 269 if ($this->dirty || $refetch) 270 $this->updated = SqlFunction::NOW(); 271 return parent::save($refetch || $this->dirty); 272 } 273 274 function update($vars,&$errors) { 275 global $cfg; 276 277 $vars['title'] = Format::striptags(trim($vars['title'])); 278 279 $id = isset($this->canned_id) ? $this->canned_id : null; 280 if ($id && $id != $vars['id']) 281 $errors['err']=sprintf('%s - %s', __('Internal error occurred'), __('Please try again!')); 282 283 if (!$vars['title']) 284 $errors['title'] = __('Title required'); 285 elseif (strlen($vars['title']) < 3) 286 $errors['title'] = __('Title is too short. 3 chars minimum'); 287 elseif (($cid=self::getIdByTitle($vars['title'])) && $cid!=$id) 288 $errors['title'] = __('Title already exists'); 289 290 if (!$vars['response']) 291 $errors['response'] = __('Response text is required'); 292 293 if ($errors) 294 return false; 295 296 $this->dept_id = $vars['dept_id'] ?: 0; 297 $this->isenabled = $vars['isenabled']; 298 $this->title = $vars['title']; 299 $this->response = Format::sanitize($vars['response']); 300 $this->notes = Format::sanitize($vars['notes']); 301 302 $isnew = !isset($id); 303 if ($this->save()) 304 return true; 305 306 if ($isnew) 307 $errors['err'] = sprintf(__('Unable to update %s.'), __('this canned response')); 308 else 309 $errors['err']=sprintf(__('Unable to create %s.'), __('this canned response')) 310 .' '.__('Internal error occurred'); 311 312 return true; 313 } 314} 315RolePermission::register( /* @trans */ 'Knowledgebase', Canned::getPermissions()); 316 317?> 318