Newer
Older
<?php
/*************************************************************************
tickets.php
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:
**********************************************************************/
require('staff.inc.php');
require_once(INCLUDE_DIR.'class.ticket.php');
require_once(INCLUDE_DIR.'class.dept.php');
require_once(INCLUDE_DIR.'class.filter.php');
require_once(INCLUDE_DIR.'class.canned.php');
require_once(INCLUDE_DIR.'class.json.php');
require_once(INCLUDE_DIR.'class.dynamic_forms.php');
require_once(INCLUDE_DIR.'class.export.php'); // For paper sizes
$ticket = $user = null; //clean start.
//LOCKDOWN...See if the id provided is actually valid and if the user has access.
if($_REQUEST['id']) {
if(!($ticket=Ticket::lookup($_REQUEST['id'])))
$errors['err']=sprintf(__('%s: Unknown or invalid ID.'), __('ticket'));
elseif(!$ticket->checkStaffAccess($thisstaff)) {
$errors['err']=__('Access denied. Contact admin if you believe this is in error');
//Lookup user if id is available.
if ($_REQUEST['uid'])
$user = User::lookup($_REQUEST['uid']);
// Configure form for file uploads
$response_form = new Form(array(
'attachments' => new FileUploadField(array('id'=>'attach',
'name'=>'attach:response',
'configuration' => array('extensions'=>'')))
$note_form = new Form(array(
'attachments' => new FileUploadField(array('id'=>'attach',
'name'=>'attach:note',
'configuration' => array('extensions'=>'')))
));
//At this stage we know the access status. we can process the post.
if($_POST && !$errors):
if($ticket && $ticket->getId()) {
//More coffee please.
$errors=array();
$lock=$ticket->getLock(); //Ticket lock if any
switch(strtolower($_POST['a'])):
case 'reply':
if(!$thisstaff->canPostReply())
$errors['err'] = __('Action denied. Contact admin for access');
if(!$_POST['response'])
$errors['response']=__('Response required');
//Use locks to avoid double replies
if($lock && $lock->getStaffId()!=$thisstaff->getId())
$errors['err']=__('Action Denied. Ticket is locked by someone else!');
//Make sure the email is not banned
if(!$errors['err'] && TicketFilter::isBanned($ticket->getEmail()))
$errors['err']=__('Email is in banlist. Must be removed to reply.');
$vars = $_POST;
$vars['cannedattachments'] = $response_form->getField('attachments')->getClean();
if(!$errors && ($response=$ticket->postReply($vars, $errors, $_POST['emailreply']))) {
$msg = sprintf(__('%s: Reply posted successfully'),
sprintf(__('Ticket #%s'),
sprintf('<a href="tickets.php?id=%d"><b>%s</b></a>',
$ticket->getId(), $ticket->getNumber()))
);
// Clear attachment list
$response_form->setSource(array());
$response_form->getField('attachments')->reset();
// Remove staff's locks
TicketLock::removeStaffLocks($thisstaff->getId(),
$ticket->getId());
// Cleanup response draft for this user
Draft::deleteForNamespace(
'ticket.response.' . $ticket->getId(),
$thisstaff->getId());
// Go back to the ticket listing page on reply
$ticket = null;
$errors['err']=__('Unable to post the reply. Correct the errors below and try again!');
}
break;
case 'transfer': /** Transfer ticket **/
//Check permission
$errors['err']=$errors['transfer'] = __('Action Denied. You are not allowed to transfer tickets.');
$errors['deptId'] = __('Select department');
elseif($_POST['deptId']==$ticket->getDeptId())
$errors['deptId'] = __('Ticket already in the department');
elseif(!($dept=Dept::lookup($_POST['deptId'])))
$errors['deptId'] = __('Unknown or invalid department');
//Transfer message - required.
if(!$_POST['transfer_comments'])
$errors['transfer_comments'] = __('Transfer comments required');
$errors['transfer_comments'] = __('Transfer comments too short!');
//If no errors - them attempt the transfer.
if(!$errors && $ticket->transfer($_POST['deptId'], $_POST['transfer_comments'])) {
$msg = sprintf(__('Ticket transferred successfully to %s'),$ticket->getDeptName());
//Check to make sure the staff still has access to the ticket
if(!$ticket->checkStaffAccess($thisstaff))
$ticket=null;
$errors['err'] = __('Unable to complete the ticket transfer');
$errors['transfer']=__('Correct the error(s) below and try again!');
$errors['err']=$errors['assign'] = __('Action Denied. You are not allowed to assign/reassign tickets.');
else {
$id = preg_replace("/[^0-9]/", "",$_POST['assignId']);
$claim = (is_numeric($_POST['assignId']) && $_POST['assignId']==$thisstaff->getId());
$errors['assignId'] = __('Select assignee');
elseif($_POST['assignId'][0]!='s' && $_POST['assignId'][0]!='t' && !$claim)
$errors['assignId']=__('Invalid assignee ID - get technical support');
elseif($ticket->isAssigned()) {
if($_POST['assignId'][0]=='s' && $id==$ticket->getStaffId())
$errors['assignId']=__('Ticket already assigned to the agent.');
elseif($_POST['assignId'][0]=='t' && $id==$ticket->getTeamId())
$errors['assignId']=__('Ticket already assigned to the team.');
//Comments are not required on self-assignment (claim)
if($claim && !$_POST['assign_comments'])
$_POST['assign_comments'] = sprintf(__('Ticket claimed by %s'),$thisstaff->getName());
$errors['assign_comments'] = __('Assignment comments required');
$errors['assign_comments'] = __('Comment too short');
if(!$errors && $ticket->assign($_POST['assignId'], $_POST['assign_comments'], !$claim)) {
if($claim) {
$msg = __('Ticket is NOW assigned to you!');
$msg=sprintf(__('Ticket assigned successfully to %s'), $ticket->getAssigned());
TicketLock::removeStaffLocks($thisstaff->getId(), $ticket->getId());
$ticket=null;
}
} elseif(!$errors['assign']) {
$errors['err'] = __('Unable to complete the ticket assignment');
$errors['assign'] = __('Correct the error(s) below and try again!');
$vars = $_POST;
$attachments = $note_form->getField('attachments')->getClean();
$vars['cannedattachments'] = array_merge(
$vars['cannedattachments'] ?: array(), $attachments);
$wasOpen = ($ticket->isOpen());
if(($note=$ticket->postNote($vars, $errors, $thisstaff))) {
$msg=__('Internal note posted successfully');
// Clear attachment list
$note_form->setSource(array());
$note_form->getField('attachments')->reset();
if($wasOpen && $ticket->isClosed())
$ticket = null; //Going back to main listing.
else
// Ticket is still open -- clear draft for the note
Draft::deleteForNamespace('ticket.note.'.$ticket->getId(),
$thisstaff->getId());
if(!$errors['err'])
$errors['err'] = __('Unable to post internal note - missing or invalid data.');
$errors['postnote'] = __('Unable to post the note. Correct the error(s) below and try again!');
case 'update':
if(!$ticket || !$thisstaff->canEditTickets())
$errors['err']=__('Permission Denied. You are not allowed to edit tickets');
$msg=__('Ticket updated successfully');
$_REQUEST['a'] = null; //Clear edit action - going back to view.
//Check to make sure the staff STILL has access post-update (e.g dept change).
if(!$ticket->checkStaffAccess($thisstaff))
$ticket=null;
$errors['err']=__('Unable to update the ticket. Correct the errors below and try again!');
}
break;
case 'process':
switch(strtolower($_POST['do'])):
case 'release':
if(!$ticket->isAssigned() || !($assigned=$ticket->getAssigned())) {
$errors['err'] = __('Ticket is not assigned!');
$msg=sprintf(__(
/* 1$ is the current assignee, 2$ is the agent removing the assignment */
'Ticket released (unassigned) from %1$s by %2$s'),
$assigned, $thisstaff->getName());
$ticket->logActivity(__('Ticket unassigned'),$msg);
$errors['err'] = __('Problems releasing the ticket. Try again');
}
break;
case 'claim':
if(!$thisstaff->canAssignTickets()) {
$errors['err'] = __('Permission Denied. You are not allowed to assign/claim tickets.');
$errors['err'] = __('Only open tickets can be assigned');
$errors['err'] = sprintf(__('Ticket is already assigned to %s'),$ticket->getAssigned());
} elseif($ticket->assignToStaff($thisstaff->getId(), (sprintf(__('Ticket claimed by %s'),$thisstaff->getName())), false)) {
$msg = __('Ticket is now assigned to you!');
$errors['err'] = __('Problems assigning the ticket. Try again');
$dept = $ticket->getDept();
if(!$dept || !$dept->isManager($thisstaff)) {
$errors['err']=__('Permission Denied. You are not allowed to flag tickets overdue');
$msg=sprintf(__('Ticket flagged as overdue by %s'),$thisstaff->getName());
$ticket->logActivity(__('Ticket Marked Overdue'),$msg);
$errors['err']=__('Problems marking the the ticket overdue. Try again');
}
break;
case 'answered':
$dept = $ticket->getDept();
if(!$dept || !$dept->isManager($thisstaff)) {
$errors['err']=__('Permission Denied. You are not allowed to flag tickets');
$msg=sprintf(__('Ticket flagged as answered by %s'),$thisstaff->getName());
$ticket->logActivity(__('Ticket Marked Answered'),$msg);
$errors['err']=__('Problems marking the the ticket answered. Try again');
}
break;
case 'unanswered':
$dept = $ticket->getDept();
if(!$dept || !$dept->isManager($thisstaff)) {
$errors['err']=__('Permission Denied. You are not allowed to flag tickets');
$msg=sprintf(__('Ticket flagged as unanswered by %s'),$thisstaff->getName());
$ticket->logActivity(__('Ticket Marked Unanswered'),$msg);
$errors['err']=__('Problems marking the ticket unanswered. Try again');
$errors['err']=__('Permission Denied. You are not allowed to ban emails');
} elseif(BanList::includes($ticket->getEmail())) {
$errors['err']=__('Email already in banlist');
} elseif(Banlist::add($ticket->getEmail(),$thisstaff->getName())) {
$msg=sprintf(__('Email %s added to banlist'),$ticket->getEmail());
$errors['err']=__('Unable to add the email to banlist');
$errors['err'] = __('Permission Denied. You are not allowed to remove emails from banlist.');
} elseif(Banlist::remove($ticket->getEmail())) {
$msg = __('Email removed from banlist');
} elseif(!BanList::includes($ticket->getEmail())) {
$warn = __('Email is not in the banlist');
$errors['err']=__('Unable to remove the email from banlist. Try again.');
case 'changeuser':
if (!$thisstaff->canEditTickets()) {
$errors['err'] = 'Permission Denied. You are not allowed to EDIT tickets!!';
} elseif (!$_POST['user_id'] || !($user=User::lookup($_POST['user_id']))) {
$errors['err'] = 'Unknown user selected!';
} elseif ($ticket->changeOwner($user)) {
$msg = 'Ticket ownership changed to ' . Format::htmlchars($user->getName());
} else {
$errors['err'] = 'Unable to change tiket ownership. Try again';
}
break;
$errors['err']=__('You must select action to perform');
$errors['err']=__('Unknown action');
endswitch;
if($ticket && is_object($ticket))
$ticket->reload();//Reload ticket info following post processing
}elseif($_POST['a']) {
switch($_POST['a']) {
case 'open':
$ticket=null;
if(!$thisstaff || !$thisstaff->canCreateTickets()) {
$errors['err'] = sprintf('%s %s',
sprintf(__('You do not have permission %s.'),
__('to create tickets')),
__('Contact admin for such access'));
} else {
$vars = $_POST;
$vars['uid'] = $user? $user->getId() : 0;
$vars['cannedattachments'] = $response_form->getField('attachments')->getClean();
if(($ticket=Ticket::open($vars, $errors))) {
$msg=__('Ticket created successfully');
$_REQUEST['a']=null;
if (!$ticket->checkStaffAccess($thisstaff) || $ticket->isClosed())
Draft::deleteForNamespace('ticket.staff%', $thisstaff->getId());
// Drop files from the response attachments widget
$response_form->setSource(array());
$response_form->getField('attachments')->reset();
unset($_SESSION[':form-data']);
} elseif(!$errors['err']) {
$errors['err']=__('Unable to create the ticket. Correct the error(s) and try again');
}
break;
}
}
if(!$errors)
$thisstaff ->resetStats(); //We'll need to reflect any changes just made!
endif;
/*... Quick stats ...*/
$stats= $thisstaff->getTicketsStats();
//Navigation
$nav->setTabActive('tickets');
$open_name = _P('queue-name',
/* This is the name of the open ticket queue */
'Open');
$nav->addSubMenu(array('desc'=>$open_name.' ('.number_format($stats['open']+$stats['answered']).')',
'href'=>'tickets.php',
'iconclass'=>'Ticket'),
(!$_REQUEST['status'] || $_REQUEST['status']=='open'));
} else {
$nav->addSubMenu(array('desc'=>$open_name.' ('.number_format($stats['open']).')',
'href'=>'tickets.php',
'iconclass'=>'Ticket'),
(!$_REQUEST['status'] || $_REQUEST['status']=='open'));
}
if($stats['answered']) {
$nav->addSubMenu(array('desc'=>__('Answered').' ('.number_format($stats['answered']).')',
'title'=>__('Answered Tickets'),
'href'=>'tickets.php?status=answered',
'iconclass'=>'answeredTickets'),
($_REQUEST['status']=='answered'));
$nav->addSubMenu(array('desc'=>__('My Tickets').' ('.number_format($stats['assigned']).')',
'title'=>__('Assigned Tickets'),
'href'=>'tickets.php?status=assigned',
'iconclass'=>'assignedTickets'),
($_REQUEST['status']=='assigned'));
}
if($stats['overdue']) {
$nav->addSubMenu(array('desc'=>__('Overdue').' ('.number_format($stats['overdue']).')',
'title'=>__('Stale Tickets'),
'href'=>'tickets.php?status=overdue',
'iconclass'=>'overdueTickets'),
($_REQUEST['status']=='overdue'));
if(!$sysnotice && $stats['overdue']>10)
$sysnotice=sprintf(__('%d overdue tickets!'),$stats['overdue']);
if($thisstaff->showAssignedOnly() && $stats['closed']) {
$nav->addSubMenu(array('desc'=>__('My Closed Tickets').' ('.number_format($stats['closed']).')',
'title'=>__('My Closed Tickets'),
'href'=>'tickets.php?status=closed',
'iconclass'=>'closedTickets'),
($_REQUEST['status']=='closed'));
} else {
if ($stats['resolved'])
$nav->addSubMenu(array('desc' => __('Resolved').' ('.number_format($stats['resolved']).')',
'title'=>__('Resolved Tickets'),
'href'=>'tickets.php?status=resolved',
'iconclass'=>'closedTickets'),
($_REQUEST['status']=='resolved'));
$nav->addSubMenu(array('desc' => __('Closed').' ('.number_format($stats['closed']).')',
'title'=>__('Closed Tickets'),
'href'=>'tickets.php?status=closed',
'iconclass'=>'closedTickets'),
($_REQUEST['status']=='closed'));
}
$nav->addSubMenu(array('desc'=>__('New Ticket'),
'title'=> __('Open a New Ticket'),
'iconclass'=>'newTicket',
'id' => 'new-ticket'),
($_REQUEST['a']=='open'));
$ost->addExtraHeader('<script type="text/javascript" src="js/ticket.js"></script>');
$ost->addExtraHeader('<meta name="tip-namespace" content="tickets.queue" />',
"$('#content').data('tipNamespace', 'tickets.queue');");
$ost->setPageTitle(sprintf(__('Ticket #%s'),$ticket->getNumber()));
$nav->setActiveSubMenu(-1);
$inc = 'ticket-view.inc.php';
if($_REQUEST['a']=='edit' && $thisstaff->canEditTickets()) {
if (!$forms) $forms=DynamicFormEntry::forTicket($ticket->getId());
// Auto add new fields to the entries
foreach ($forms as $f) $f->addMissingFields();
} elseif($_REQUEST['a'] == 'print' && !$ticket->pdfExport($_REQUEST['psize'], $_REQUEST['notes']))
$errors['err'] = __('Internal error: Unable to export the ticket to PDF for print.');
if($_REQUEST['a']=='open' && $thisstaff->canCreateTickets())
$inc = 'ticket-open.inc.php';
elseif($_REQUEST['a'] == 'export') {
$ts = strftime('%Y%m%d');
if (!($token=$_REQUEST['h']))
$errors['err'] = __('Query token required');
elseif (!($query=$_SESSION['search_'.$token]))
$errors['err'] = __('Query token not found');
elseif (!Export::saveTickets($query, "tickets-$ts.csv", 'csv'))
$errors['err'] = __('Internal error: Unable to dump query results');
//Clear active submenu on search with no status
if($_REQUEST['a']=='search' && !$_REQUEST['status'])
$nav->setActiveSubMenu(-1);
//set refresh rate if the user has it configured
if(!$_POST && !$_REQUEST['a'] && ($min=$thisstaff->getRefreshRate())) {
$js = "clearTimeout(window.ticket_refresh);
window.ticket_refresh = setTimeout($.refreshTicketView,"
.($min*60000).");";
$ost->addExtraHeader('<script type="text/javascript">'.$js.'</script>',
$js);
}
}
require_once(STAFFINC_DIR.'header.inc.php');
require_once(STAFFINC_DIR.$inc);
print $response_form->getMedia();