Helpdesk da PluGzOne, baseado no osTicket
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

557 lines
17 KiB

<?php
/*********************************************************************
class.thread_actions.php
Actions for thread entries. This serves as a simple repository for
drop-down actions which can be triggered on the ticket-view page for an
object's thread.
Jared Hancock <jared@osticket.com>
Peter Rotich <peter@osticket.com>
Copyright (c) 2006-2014 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
**********************************************************************/
include_once(INCLUDE_DIR.'class.thread.php');
class TEA_ShowEmailRecipients extends ThreadEntryAction {
static $id = 'emailrecipients';
static $name = /* trans */ 'View Email Recipients';
static $icon = 'group';
function isVisible() {
global $thisstaff;
if ($this->entry->getEmailHeader())
return ($thisstaff && $this->entry->getEmailHeader());
elseif ($this->entry->recipients)
return $this->entry->recipients;
}
function getJsStub() {
return sprintf("$.dialog('%s');",
$this->getAjaxUrl()
);
}
function trigger() {
switch ($_SERVER['REQUEST_METHOD']) {
case 'GET' && $this->entry->recipients:
return $this->getRecipients();
case 'GET':
return $this->trigger__get();
}
}
private function trigger__get() {
$hdr = Mail_parse::splitHeaders(
$this->entry->getEmailHeader(), true);
$recipients = array();
foreach (array('To', 'TO', 'Cc', 'CC') as $k) {
if (isset($hdr[$k]) && $hdr[$k] &&
($addresses=Mail_Parse::parseAddressList($hdr[$k]))) {
foreach ($addresses as $addr) {
$email = sprintf('%s@%s', $addr->mailbox, $addr->host);
$name = $addr->personal ?: '';
$recipients[$k][] = sprintf('%s<%s>',
(($name && strcasecmp($name, $email))? "$name ": ''),
$email);
}
}
}
include STAFFINC_DIR . 'templates/thread-email-recipients.tmpl.php';
}
private function getRecipients() {
$recipients = json_decode($this->entry->recipients, true);
include STAFFINC_DIR . 'templates/thread-email-recipients.tmpl.php';
}
}
ThreadEntry::registerAction(/* trans */ 'E-Mail', 'TEA_ShowEmailRecipients');
class TEA_ShowEmailHeaders extends ThreadEntryAction {
static $id = 'view_headers';
static $name = /* trans */ 'View Email Headers';
static $icon = 'envelope';
function isVisible() {
global $thisstaff;
if (!$this->entry->getEmailHeader())
return false;
return $thisstaff && $thisstaff->isAdmin();
}
function getJsStub() {
return sprintf("$.dialog('%s');",
$this->getAjaxUrl()
);
}
function trigger() {
switch ($_SERVER['REQUEST_METHOD']) {
case 'GET':
return $this->trigger__get();
}
}
private function trigger__get() {
$headers = $this->entry->getEmailHeader();
include STAFFINC_DIR . 'templates/thread-email-headers.tmpl.php';
}
}
ThreadEntry::registerAction(/* trans */ 'E-Mail', 'TEA_ShowEmailHeaders');
class TEA_EditThreadEntry extends ThreadEntryAction {
static $id = 'edit';
static $name = /* trans */ 'Edit';
static $icon = 'pencil';
function isVisible() {
// Can't edit system posts
return ($this->entry->staff_id || $this->entry->user_id)
&& $this->entry->type != 'R' && $this->isEnabled();
}
function isEnabled() {
global $thisstaff;
$T = $this->entry->getThread()->getObject();
// You can edit your own posts or posts by your department members
// if your a manager, or everyone's if your an admin
return $thisstaff && (
$thisstaff->getId() == $this->entry->staff_id
|| ($T instanceof Ticket
&& $T->getDept()->getManagerId() == $thisstaff->getId()
)
|| ($T instanceof Ticket
&& ($role = $thisstaff->getRole($T->getDeptId(), $T->isAssigned($thisstaff)))
&& $role->hasPerm(ThreadEntry::PERM_EDIT)
)
|| ($T instanceof Task
&& $T->getDept()->getManagerId() == $thisstaff->getId()
)
|| ($T instanceof Task
&& ($role = $thisstaff->getRole($T->getDeptId(), $T->isAssigned($thisstaff)))
&& $role->hasPerm(ThreadEntry::PERM_EDIT)
)
);
}
function getJsStub() {
return sprintf(<<<JS
var url = '%s';
$.dialog(url, [201], function(xhr, resp) {
var json = JSON.parse(resp);
if (!json || !json.thread_id)
return;
$('#thread-entry-'+json.thread_id)
.attr('id', 'thread-entry-' + json.new_id)
.html(json.entry)
.find('.thread-body')
.delay(500)
.effect('highlight');
}, {size:'large'});
JS
, $this->getAjaxUrl());
}
function trigger() {
switch ($_SERVER['REQUEST_METHOD']) {
case 'GET':
return $this->trigger__get();
case 'POST':
return $this->trigger__post();
}
}
protected function trigger__get() {
global $cfg, $thisstaff;
$poster = $this->entry->getStaff();
include STAFFINC_DIR . 'templates/thread-entry-edit.tmpl.php';
}
function updateEntry($guard=false) {
global $thisstaff;
$old = $this->entry;
$new = ThreadEntryBody::fromFormattedText($_POST['body'], $old->format);
if ($new->getClean() == $old->getBody())
// No update was performed
return $old;
$entry = ThreadEntry::create(array(
// Copy most information from the old entry
'poster' => $old->poster,
'userId' => $old->user_id,
'staffId' => $old->staff_id,
'type' => $old->type,
'threadId' => $old->thread_id,
'recipients' => $old->recipients,
// Connect the new entry to be a child of the previous
'pid' => $old->id,
// Add in new stuff
'title' => Format::htmlchars($_POST['title']),
'body' => $new,
'ip_address' => $_SERVER['REMOTE_ADDR'],
));
if (!$entry)
return false;
// Note, anything that points to the $old entry as PID should remain
// that way for email header lookups and such to remain consistent
if ($old->flags & ThreadEntry::FLAG_EDITED
// If editing another person's edit, make a new entry
and ($old->editor == $thisstaff->getId() && $old->editor_type == 'S')
and !($old->flags & ThreadEntry::FLAG_GUARDED)
) {
// Replace previous edit --------------------------
$original = $old->getParent();
// Link the new entry to the old id
$entry->pid = $old->pid;
// Drop the previous edit, and base this edit off the original
$old->delete();
$old = $original;
}
// Move the attachments to the new entry
$old->attachments->filter(array(
'inline' => false,
))->update(array(
'object_id' => $entry->id
));
// Mark the new entry as edited (but not hidden nor guarded)
$entry->flags = ($old->flags & ~(ThreadEntry::FLAG_HIDDEN | ThreadEntry::FLAG_GUARDED))
| ThreadEntry::FLAG_EDITED;
// Guard against deletes on future edit if requested. This is done
// if an email was triggered by the last edit. In such a case, it
// should not be replaced by a subsequent edit.
if ($guard)
$entry->flags |= ThreadEntry::FLAG_GUARDED;
// Log the editor
$entry->editor = $thisstaff->getId();
$entry->editor_type = 'S';
// Sort in the same place in the thread
$entry->created = $old->created;
$entry->updated = SqlFunction::NOW();
$entry->save(true);
// Hide the old entry from the object thread
$old->flags |= ThreadEntry::FLAG_HIDDEN;
$old->save();
return $entry;
}
protected function trigger__post() {
global $thisstaff;
if (!($entry = $this->updateEntry()))
return $this->trigger__get();
ob_start();
include STAFFINC_DIR . 'templates/thread-entry.tmpl.php';
$content = ob_get_clean();
Http::response('201', JsonDataEncoder::encode(array(
'thread_id' => $this->entry->id, # This is the old id!
'new_id' => $entry->id,
'entry' => $content,
)));
}
}
ThreadEntry::registerAction(/* trans */ 'Manage', 'TEA_EditThreadEntry');
class TEA_OrigThreadEntry extends ThreadEntryAction {
static $id = 'previous';
static $name = /* trans */ 'View History';
static $icon = 'copy';
function isVisible() {
// Can't edit system posts
return $this->entry->flags & ThreadEntry::FLAG_EDITED;
}
function getJsStub() {
return sprintf("$.dialog('%s');",
$this->getAjaxUrl()
);
}
function trigger() {
switch ($_SERVER['REQUEST_METHOD']) {
case 'GET':
return $this->trigger__get();
}
}
private function trigger__get() {
global $thisstaff;
if (!$this->entry->getParent())
Http::response(404, 'No history for this entry');
$entry = $this->entry;
include STAFFINC_DIR . 'templates/thread-entry-view.tmpl.php';
}
}
ThreadEntry::registerAction(/* trans */ 'Manage', 'TEA_OrigThreadEntry');
class TEA_EditAndResendThreadEntry extends TEA_EditThreadEntry {
static $id = 'edit_resend';
static $name = /* trans */ 'Edit and Resend';
static $icon = 'reply-all';
function isVisible() {
// Can only resend replies
return $this->entry->staff_id && $this->entry->type == 'R'
&& $this->isEnabled();
}
protected function trigger__post() {
$resend = @$_POST['commit'] == 'resend';
if (!($entry = $this->updateEntry($resend)))
return $this->trigger__get();
if ($resend)
$this->resend($entry);
ob_start();
include STAFFINC_DIR . 'templates/thread-entry.tmpl.php';
$content = ob_get_clean();
Http::response('201', JsonDataEncoder::encode(array(
'thread_id' => $this->entry->id, # This is the old id!
'new_id' => $entry->id,
'entry' => $content,
)));
}
function resend($response) {
global $cfg, $thisstaff;
if (!($object = $response->getThread()->getObject()))
return false;
$vars = $_POST;
$dept = $object->getDept();
$poster = $response->getStaff();
if ($thisstaff && $vars['signature'] == 'mine')
$signature = $thisstaff->getSignature();
elseif ($poster && $vars['signature'] == 'theirs')
$signature = $poster->getSignature();
elseif ($vars['signature'] == 'dept' && $dept && $dept->isPublic())
$signature = $dept->getSignature();
else
$signature = '';
$variables = array(
'response' => $response,
'signature' => $signature,
'staff' => $response->getStaff(),
'poster' => $response->getStaff());
$options = array('thread' => $response);
// Resend response to collabs
if (($object instanceof Ticket)
&& ($email=$dept->getEmail())
&& ($tpl = $dept->getTemplate())
&& ($msg=$tpl->getReplyMsgTemplate())) {
$recipients = json_decode($response->recipients, true);
$msg = $object->replaceVars($msg->asArray(),
$variables + array('recipient' => $object->getOwner()));
$attachments = $cfg->emailAttachments()
? $response->getAttachments() : array();
$email->send($object->getOwner(), $msg['subj'], $msg['body'],
$attachments, $options, $recipients);
}
// TODO: Add an option to the dialog
if ($object instanceof Task)
$object->notifyCollaborators($response, array('signature' => $signature));
// Log an event that the item was resent
$object->logEvent('resent', array('entry' => $response->id));
$type = array('type' => 'resent');
Signal::send('object.edited', $object, $type);
// Flag the entry as resent
$response->flags |= ThreadEntry::FLAG_RESENT;
$response->save();
}
}
ThreadEntry::registerAction(/* trans */ 'Manage', 'TEA_EditAndResendThreadEntry');
class TEA_ResendThreadEntry extends TEA_EditAndResendThreadEntry {
static $id = 'resend';
static $name = /* trans */ 'Resend';
static $icon = 'reply-all';
function isVisible() {
// Can only resend replies
return $this->entry->staff_id && $this->entry->type == 'R'
&& !parent::isEnabled();
}
function isEnabled() {
return true;
}
protected function trigger__get() {
global $cfg, $thisstaff;
$poster = $this->entry->getStaff();
include STAFFINC_DIR . 'templates/thread-entry-resend.tmpl.php';
}
protected function trigger__post() {
$resend = @$_POST['commit'] == 'resend';
if (@$_POST['commit'] == 'resend')
$this->resend($this->entry);
Http::response('201', 'Okee dokey');
}
}
ThreadEntry::registerAction(/* trans */ 'Manage', 'TEA_ResendThreadEntry');
/* Create a new ticket from thread entry as description */
class TEA_CreateTicket extends ThreadEntryAction {
static $id = 'create_ticket';
static $name = /* trans */ 'Create Ticket';
static $icon = 'plus';
function isVisible() {
global $thisstaff;
return $thisstaff && $thisstaff->hasPerm(Ticket::PERM_CREATE, false);
}
function getJsStub() {
return sprintf(<<<JS
window.location.href = '%s';
JS
, $this->getCreateTicketUrl()
);
}
function trigger() {
switch ($_SERVER['REQUEST_METHOD']) {
case 'GET':
return $this->trigger__get();
}
}
private function trigger__get() {
Http::redirect($this->getCreateTicketUrl());
}
private function getCreateTicketUrl() {
return sprintf('tickets.php?a=open&tid=%d', $this->entry->getId());
}
}
ThreadEntry::registerAction(/* trans */ 'Manage', 'TEA_CreateTicket');
class TEA_CreateTask extends ThreadEntryAction {
static $id = 'create_task';
static $name = /* trans */ 'Create Task';
static $icon = 'plus';
function isVisible() {
global $thisstaff;
return $thisstaff && $thisstaff->hasPerm(Task::PERM_CREATE, false);
}
function getJsStub() {
return sprintf(<<<JS
var url = '%s';
var redirect = $(this).data('redirect');
$.dialog(url, [201], function(xhr, resp) {
if (!!redirect)
$.pjax({url: redirect, container: '#pjax-container'});
else
$.pjax({url: '%s.php?id=%d#tasks', container: '#pjax-container'});
});
JS
, $this->getAjaxUrl(),
$this->entry->getThread()->getObjectType() == 'T' ? 'tickets' : 'tasks',
$this->entry->getThread()->getObjectId()
);
}
function trigger() {
switch ($_SERVER['REQUEST_METHOD']) {
case 'GET':
return $this->trigger__get();
case 'POST':
return $this->trigger__post();
}
}
private function trigger__get() {
$vars = array(
'description' => Format::htmlchars($this->entry->getBody()));
if ($_SESSION[':form-data'])
unset($_SESSION[':form-data']);
$_SESSION[':form-data']['tid'] = $this->entry->getThread()->getObJectId();
$_SESSION[':form-data']['eid'] = $this->entry->getId();
$_SESSION[':form-data']['timestamp'] = $this->entry->getCreateDate();
$_SESSION[':form-data']['type'] = $this->entry->getThread()->object_type;
if (($f= TaskForm::getInstance()->getField('description'))) {
$k = 'attach:'.$f->getId();
unset($_SESSION[':form-data'][$k]);
foreach ($this->entry->getAttachments() as $a)
if (!$a->inline && $a->file) {
$_SESSION[':form-data'][$k][$a->file->getId()] = $a->getFilename();
$_SESSION[':uploadedFiles'][$a->file->getId()] = $a->getFilename();
}
}
if ($this->entry->getThread()->getObjectType() == 'T')
return $this->getTicketsAPI()->addTask($this->getObjectId(), $vars);
else
return $this->getTasksAPI()->add($this->getObjectId(), $vars);
}
private function trigger__post() {
if ($this->entry->getThread()->getObjectType() == 'T')
return $this->getTicketsAPI()->addTask($this->getObjectId());
else
return $this->getTasksAPI()->add($this->getObjectId());
}
}
ThreadEntry::registerAction(/* trans */ 'Manage', 'TEA_CreateTask');