Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?php
/*************************************************************************
tickets.php
Handles all tickets related actions.
Peter Rotich <peter@osticket.com>
Copyright (c) 2006-2012 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:
**********************************************************************/
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');
$page='';
$ticket=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']='Unknown or invalid ticket ID';
elseif(!$ticket->checkStaffAccess($thisstaff)) {
$errors['err']='Access denied. Contact admin if you believe this is in error';
$ticket=null; //Clear ticket obj.
}
}
//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
$statusKeys=array('open'=>'Open','Reopen'=>'Open','Close'=>'Closed');
switch(strtolower($_POST['a'])):
case 'reply':
if(!$_POST['msgId'])
$errors['err']='Missing message ID - Internal error';
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.';
$wasOpen =($ticket->isOpen());
if(!$errors && ($respId=$ticket->postReply($_POST, $errorsi, isset($_POST['emailreply'])))) {
$msg='Reply posted successfully';
$ticket->reload();
if($ticket->isClosed() && $wasOpen)
$ticket=null;
} elseif(!$errors['err']) {
$errors['err']='Unable to post the reply. Correct the errors below and try again!';
}
break;
case 'transfer': /** Transfer ticket **/
//Check permission
if(!$thisstaff->canTransferTickets())
$errors['err']=$errors['transfer'] = 'Action Denied. You are not allowed to transfer tickets.';
else {
//Check target dept.
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';
elseif(strlen($_POST['transfer_comments'])<5)
$errors['transfer_comments'] = 'Transfer comments too short!';
//If no errors - them attempt the transfer.
if(!$errors && $ticket->transfer($_POST['deptId'], $_POST['transfer_comments'])) {
$msg = 'Ticket transferred successfully to '.$ticket->getDeptName();
//Check to make sure the staff still has access to the ticket
if(!$ticket->checkStaffAccess($thisstaff))
$ticket=null;
} elseif(!$errors['transfer']) {
$errors['err'] = 'Unable to complete the ticket transfer';
$errors['transfer']='Correct the error(s) below and try again!';
if(!$thisstaff->canAssignTickets())
$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());
if(!$_POST['assignId'] || !$id)
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 staff.';
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'] = 'Ticket claimed by '.$thisstaff->getName();
elseif(!$_POST['assign_comments'])
$errors['assign_comments'] = 'Assignment comments required';
elseif(strlen($_POST['assign_comments'])<5)
$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!';
} else {
$msg='Ticket assigned successfully to '.$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!';
}
}
break;
case 'postnote': /* Post Internal Note */
//Make sure the staff can set desired state
if($_POST['state']) {
if($_POST['state']=='closed' && !$thisstaff->canCloseTickets())
$errors['state'] = "You don't have permission to close tickets";
elseif(in_array($_POST['state'], array('overdue', 'notdue', 'unassigned'))
&& (!($dept=$ticket->getDept()) || !$dept->isManager($thisstaff)))
$errors['state'] = "You don't have permission to set the state";
}
$wasOpen = ($ticket->isOpen());
if(($noteId=$ticket->postNote($_POST, $errors, $thisstaff))) {
if($wasOpen && $ticket->isClosed())
$ticket = null; //Going back to main listing.
} else {
$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']='Perm. Denied. You are not allowed to edit tickets';
$_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;
} elseif(!$errors['err']) {
$errors['err']='Unable to update the ticket. Correct the errors below and try again!';
}
break;
case 'process':
switch(strtolower($_POST['do'])):
case 'close':
if(!$thisstaff->canCloseTickets()) {
$errors['err'] = 'Perm. Denied. You are not allowed to close tickets.';
} elseif($ticket->isClosed()) {
$errors['err'] = 'Ticket is already closed!';
} elseif($ticket->close()) {
$msg='Ticket #'.$ticket->getExtId().' status set to CLOSED';
//Log internal note
if($_POST['ticket_status_notes'])
$note = $_POST['ticket_status_notes'];
else
$note='Ticket closed (without comments)';
$ticket->logNote('Ticket Closed', $note, $thisstaff);
//Going back to main listing.
TicketLock::removeStaffLocks($thisstaff->getId(), $ticket->getId());
$page=$ticket=null;
} else {
$errors['err']='Problems closing the ticket. Try again';
//if staff can close or create tickets ...then assume they can reopen.
if(!$thisstaff->canCloseTickets() && !$thisstaff->canCreateTickets()) {
$errors['err']='Perm. Denied. You are not allowed to reopen tickets.';
} elseif($ticket->isOpen()) {
$errors['err'] = 'Ticket is already open!';
} elseif($ticket->reopen()) {
$msg='Ticket REOPENED';
if($_POST['ticket_status_notes'])
$note = $_POST['ticket_status_notes'];
else
} else {
$errors['err']='Problems reopening the ticket. Try again';
if(!$ticket->isAssigned() || !($assigned=$ticket->getAssigned())) {
$errors['err'] = 'Ticket is not assigned!';
} elseif($ticket->release()) {
$msg='Ticket released (unassigned) from '.$assigned;
$ticket->logActivity('Ticket unassigned',$msg.' by '.$thisstaff->getName());
} else {
$errors['err'] = 'Problems releasing the ticket. Try again';
}
break;
case 'claim':
if(!$thisstaff->canAssignTickets()) {
$errors['err'] = 'Perm. Denied. You are not allowed to assign/claim tickets.';
} elseif(!$ticket->isOpen()) {
$errors['err'] = 'Only open tickets can be assigned';
} elseif($ticket->isAssigned()) {
$errors['err'] = 'Ticket is already assigned to '.$ticket->getAssigned();
} elseif($ticket->assignToStaff($thisstaff->getId(), ('Ticket claimed by '.$thisstaff->getName()), false)) {
$msg = 'Ticket is now assigned to you!';
} else {
$errors['err'] = 'Problems assigning the ticket. Try again';
}
$dept = $ticket->getDept();
if(!$dept || !$dept->isManager($thisstaff)) {
$errors['err']='Perm. Denied. You are not allowed to flag tickets overdue';
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
} elseif($ticket->markOverdue()) {
$msg='Ticket flagged as overdue';
$ticket->logActivity('Ticket Marked Overdue',($msg.' by '.$thisstaff->getName()));
} else {
$errors['err']='Problems marking the the ticket overdue. Try again';
}
break;
case 'answered':
$dept = $ticket->getDept();
if(!$dept || !$dept->isManager($thisstaff)) {
$errors['err']='Perm. Denied. You are not allowed to flag tickets';
} elseif($ticket->markAnswered()) {
$msg='Ticket flagged as answered';
$ticket->logActivity('Ticket Marked Answered',($msg.' by '.$thisstaff->getName()));
} else {
$errors['err']='Problems marking the the ticket answered. Try again';
}
break;
case 'unanswered':
$dept = $ticket->getDept();
if(!$dept || !$dept->isManager($thisstaff)) {
$errors['err']='Perm. Denied. You are not allowed to flag tickets';
} elseif($ticket->markUnAnswered()) {
$msg='Ticket flagged as unanswered';
$ticket->logActivity('Ticket Marked Unanswered',($msg.' by '.$thisstaff->getName()));
} else {
$errors['err']='Problems marking the the ticket unanswered. Try again';
$errors['err']='Perm. 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='Email ('.$ticket->getEmail().') added to banlist';
$errors['err']='Unable to add the email to banlist';
}
break;
case 'unbanemail':
if(!$thisstaff->canBanEmails()) {
$errors['err'] = 'Perm. 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';
} else {
$errors['err']='Unable to remove the email from banlist. Try again.';
}
break;
case 'delete': // Dude what are you trying to hide? bad customer support??
$errors['err']='Perm. Denied. You are not allowed to DELETE tickets!!';
} elseif($ticket->delete()) {
$msg='Ticket #'.$ticket->getNumber().' deleted successfully';
//Log a debug note
$ost->logDebug('Ticket #'.$ticket->getNumber().' deleted',
sprintf('Ticket #%s deleted by %s',
$ticket->getNumber(), $thisstaff->getName())
);
$ticket=null; //clear the object.
} else {
$errors['err']='Problems deleting the ticket. Try again';
}
break;
default:
$errors['err']='You must select action to perform';
endswitch;
break;
default:
$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 'mass_process':
if(!$thisstaff->canManageTickets())
$errors['err']='You do not have permission to mass manage tickets. Contact admin for such access';
elseif(!$_POST['tids'] || !is_array($_POST['tids']))
$errors['err']='No tickets selected. You must select at least one ticket.';
$i = 0;
switch(strtolower($_POST['do'])) {
case 'reopen':
if($thisstaff->canCloseTickets() || $thisstaff->canCreateTickets()) {
$note='Ticket reopened by '.$thisstaff->getName();
foreach($_POST['tids'] as $k=>$v) {
if(($t=Ticket::lookup($v)) && $t->isClosed() && @$t->reopen()) {
$i++;
$t->logNote('Ticket Reopened', $note, $thisstaff);
}
}
if($i==$count)
$msg = "Selected tickets ($i) reopened successfully";
$warn = "$i of $count selected tickets reopened";
else
$errors['err'] = 'Unable to reopen selected tickets';
} else {
$errors['err'] = 'You do not have permission to reopen tickets';
break;
case 'close':
if($thisstaff->canCloseTickets()) {
$note='Ticket closed without response by '.$thisstaff->getName();
foreach($_POST['tids'] as $k=>$v) {
if(($t=Ticket::lookup($v)) && $t->isOpen() && @$t->close()) {
$i++;
$t->logNote('Ticket Closed', $note, $thisstaff);
}
}
if($i==$count)
$msg ="Selected tickets ($i) closed succesfully";
$warn = "$i of $count selected tickets closed";
else
$errors['err'] = 'Unable to close selected tickets';
} else {
$errors['err'] = 'You do not have permission to close tickets';
break;
case 'mark_overdue':
$note='Ticket flagged as overdue by '.$thisstaff->getName();
foreach($_POST['tids'] as $k=>$v) {
if(($t=Ticket::lookup($v)) && !$t->isOverdue() && $t->markOverdue()) {
$t->logNote('Ticket Marked Overdue', $note, $thisstaff);
}
}
if($i==$count)
$msg = "Selected tickets ($i) marked overdue";
$warn = "$i of $count selected tickets marked overdue";
else
$errors['err'] = 'Unable to flag selected tickets as overdue';
break;
case 'delete':
if($thisstaff->canDeleteTickets()) {
foreach($_POST['tids'] as $k=>$v) {
if(($t=Ticket::lookup($v)) && @$t->delete()) $i++;
//Log a warning
if($i) {
$log = sprintf('%s (%s) just deleted %d ticket(s)',
$thisstaff->getName(), $thisstaff->getUserName(), $i);
$ost->logWarning('Tickets deleted', $log, false);
}
if($i==$count)
$msg = "Selected tickets ($i) deleted successfully";
$warn = "$i of $count selected tickets deleted";
else
$errors['err'] = 'Unable to delete selected tickets';
} else {
$errors['err'] = 'You do not have permission to delete tickets';
}
break;
default:
$errors['err']='Unknown or unsupported action - get technical help';
}
}
break;
case 'open':
$ticket=null;
if(!$thisstaff || !$thisstaff->canCreateTickets()) {
$errors['err']='You do not have permission to create tickets. Contact admin for such access';
}elseif(($ticket=Ticket::open($_POST, $errors))) {
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
$msg='Ticket created successfully';
$_REQUEST['a']=null;
if(!$ticket->checkStaffAccess($thisstaff) || $ticket->isClosed())
$ticket=null;
}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');
if($cfg->showAnsweredTickets()) {
$nav->addSubMenu(array('desc'=>'Open ('.($stats['open']+$stats['answered']).')',
'title'=>'Open Tickets',
'href'=>'tickets.php',
'iconclass'=>'Ticket'),
(!$_REQUEST['status'] || $_REQUEST['status']=='open'));
} else {
$nav->addSubMenu(array('desc'=>'Open ('.$stats['open'].')',
'title'=>'Open Tickets',
'href'=>'tickets.php',
'iconclass'=>'Ticket'),
(!$_REQUEST['status'] || $_REQUEST['status']=='open'));
}
if($stats['answered']) {
$nav->addSubMenu(array('desc'=>'Answered ('.$stats['answered'].')',
'title'=>'Answered Tickets',
'href'=>'tickets.php?status=answered',
'iconclass'=>'answeredTickets'),
($_REQUEST['status']=='answered'));
}
}
if($stats['assigned']) {
if(!$ost->getWarning() && $stats['assigned']>3)
$ost->setWarning($stats['assigned'].' tickets assigned to you! Do something about it!');
$nav->addSubMenu(array('desc'=>'My Tickets ('.$stats['assigned'].')',
'title'=>'Assigned Tickets',
'href'=>'tickets.php?status=assigned',
'iconclass'=>'assignedTickets'),
($_REQUEST['status']=='assigned'));
}
if($stats['overdue']) {
$nav->addSubMenu(array('desc'=>'Overdue ('.$stats['overdue'].')',
'title'=>'Stale Tickets',
'href'=>'tickets.php?status=overdue',
'iconclass'=>'overdueTickets'),
($_REQUEST['status']=='overdue'));
if(!$sysnotice && $stats['overdue']>10)
$sysnotice=$stats['overdue'] .' overdue tickets!';
}
if($thisstaff->showAssignedOnly() && $stats['closed']) {
$nav->addSubMenu(array('desc'=>'My Closed Tickets ('.$stats['closed'].')',
'title'=>'My Closed Tickets',
'href'=>'tickets.php?status=closed',
'iconclass'=>'closedTickets'),
($_REQUEST['status']=='closed'));
} else {
$nav->addSubMenu(array('desc'=>'Closed Tickets',
'title'=>'Closed Tickets',
'href'=>'tickets.php?status=closed',
'iconclass'=>'closedTickets'),
($_REQUEST['status']=='closed'));
}
if($thisstaff->canCreateTickets()) {
$nav->addSubMenu(array('desc'=>'New Ticket',
'href'=>'tickets.php?a=open',
'iconclass'=>'newTicket'),
($_REQUEST['a']=='open'));
}
$inc = 'tickets.inc.php';
if($ticket) {
$ost->setPageTitle('Ticket #'.$ticket->getNumber());
$nav->setActiveSubMenu(-1);
$inc = 'ticket-view.inc.php';
if($_REQUEST['a']=='edit' && $thisstaff->canEditTickets())
$inc = 'ticket-edit.inc.php';
elseif($_REQUEST['a'] == 'print' && !$ticket->pdfExport($_REQUEST['psize'], $_REQUEST['notes']))
$errors['err'] = 'Internal error: Unable to export the ticket to PDF for print.';
$inc = 'tickets.inc.php';
if($_REQUEST['a']=='open' && $thisstaff->canCreateTickets())
$inc = 'ticket-open.inc.php';
elseif($_REQUEST['a'] == 'export') {
require_once(INCLUDE_DIR.'class.export.php');
$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()))
$ost->addExtraHeader('<meta http-equiv="refresh" content="'.($min*60).'" />');
}
require_once(STAFFINC_DIR.'header.inc.php');
require_once(STAFFINC_DIR.$inc);
require_once(STAFFINC_DIR.'footer.inc.php');
?>