diff --git a/include/api.tickets.php b/include/api.tickets.php index 47d978a498aac405381d4f5659f2b8072d092da6..6371daa632ff5240b0bee90cb3bed69c0ac56384 100644 --- a/include/api.tickets.php +++ b/include/api.tickets.php @@ -149,6 +149,10 @@ class TicketApiController extends ApiController { $data = $this->getEmailRequest(); if (($thread = ThreadEntry::lookupByEmailHeaders($data)) + && ($t=$thread->getTicket()) + && ($data['staffId'] + || !$t->isClosed() + || $t->isReopenable()) && $thread->postEmail($data)) { return $thread->getTicket(); } diff --git a/include/class.mailfetch.php b/include/class.mailfetch.php index 45758c75c052057061c354e77e2c5faef639e4ff..4e6546549f44d7ad520670bb01af8e946534aaea 100644 --- a/include/class.mailfetch.php +++ b/include/class.mailfetch.php @@ -721,6 +721,10 @@ class MailFetcher { $seen = false; if (($thread = ThreadEntry::lookupByEmailHeaders($vars, $seen)) + && ($t=$thread->getTicket()) + && ($vars['staffId'] + || !$t->isClosed() + || $t->isReopenable()) && ($message = $thread->postEmail($vars))) { if (!$message instanceof ThreadEntry) // Email has been processed previously diff --git a/include/class.ticket.php b/include/class.ticket.php index d2b9a6dec7a00053bdc2d5f63d12e109f8ee28bd..0dd0759524db699f4645db80604be81dfb0c4195 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -142,6 +142,10 @@ class Ticket { return ($this->getReopenDate()); } + function isReopenable() { + return $this->getStatus()->isReopenable(); + } + function isClosed() { return $this->hasState('closed'); } @@ -939,11 +943,19 @@ class Ticket { return (db_query($sql) && db_affected_rows()); } - //set status to open on a closed ticket. - function reopen($isanswered=0) { + function reopen() { global $cfg; - return $this->setStatus($cfg->getDefaultTicketStatusId()); + if (!$this->isClosed()) + return false; + + // Set status to open based on current closed status settings + // If the closed status doesn't have configured "reopen" status then use the + // the default ticket status. + if (!($status=$this->getStatus()->getReopenStatus())) + $status = $cfg->getDefaultTicketStatusId(); + + return $status ? $this->setStatus($status, 'Reopened') : false; } function onNewTicket($message, $autorespond=true, $alertstaff=true) { @@ -1149,8 +1161,9 @@ class Ticket { } } - // Reopen if NOT open - if(!$this->isOpen()) $this->reopen(); + // Reopen if closed AND reopenable + if ($this->isClosed() && $this->isReopenable()) + $this->reopen(); /********** double check auto-response ************/ if (!($user = $message->getUser())) diff --git a/include/client/view.inc.php b/include/client/view.inc.php index 454cc9e7d80e8977d32803417dc927d8167ef0e7..1867ac467ab9b3ac50496c6f00c63c0abad3d150 100644 --- a/include/client/view.inc.php +++ b/include/client/view.inc.php @@ -4,6 +4,10 @@ if(!defined('OSTCLIENTINC') || !$thisclient || !$ticket || !$ticket->checkUserAc $info=($_POST && $errors)?Format::htmlchars($_POST):array(); $dept = $ticket->getDept(); + +if ($ticket->isClosed() && !$ticket->isReopenable()) + $warn = __('This ticket is marked as closed and cannot be reopened.'); + //Making sure we don't leak out internal dept names if(!$dept || !$dept->isPublic()) $dept = $cfg->getDefaultDept(); @@ -146,6 +150,10 @@ if($ticket->getThreadCount() && ($thread=$ticket->getClientThread())) { <?php }elseif($warn) { ?> <div id="msg_warning"><?php echo $warn; ?></div> <?php } ?> + +<?php + +if (!$ticket->isClosed() || $ticket->isReopenable()) { ?> <form id="reply" action="tickets.php?id=<?php echo $ticket->getId(); ?>#reply" name="reply" method="post" enctype="multipart/form-data"> <?php csrf_token(); ?> <h2><?php echo __('Post a Reply');?></h2> @@ -183,3 +191,5 @@ if($ticket->getThreadCount() && ($thread=$ticket->getClientThread())) { <input type="button" value="<?php echo __('Cancel');?>" onClick="history.go(-1)"> </p> </form> +<?php +} ?> diff --git a/include/staff/ticket-view.inc.php b/include/staff/ticket-view.inc.php index ffaaa8a120b2292720b6bdba85ce95059fa634a3..b0dc9ee4aa4ee6cc4f91271c3be2a46adbc5c2d4 100644 --- a/include/staff/ticket-view.inc.php +++ b/include/staff/ticket-view.inc.php @@ -22,15 +22,27 @@ $lock = $ticket->getLock(); //Ticket lock obj $id = $ticket->getId(); //Ticket ID. //Useful warnings and errors the user might want to know! -if($ticket->isAssigned() && ( - ($staff && $staff->getId()!=$thisstaff->getId()) - || ($team && !$team->hasMember($thisstaff)) +if ($ticket->isClosed() && !$ticket->isReopenable()) + $warn = sprintf( + __('Current ticket status (%s) does not allow the end user to reply.'), + $ticket->getStatus()); +elseif ($ticket->isAssigned() + && (($staff && $staff->getId()!=$thisstaff->getId()) + || ($team && !$team->hasMember($thisstaff)) )) - $warn.=' <span class="Icon assignedTicket">'.sprintf(__('Ticket is assigned to %s'),implode('/', $ticket->getAssignees())).'</span>'; -if(!$errors['err'] && ($lock && $lock->getStaffId()!=$thisstaff->getId())) - $errors['err']=sprintf(__('This ticket is currently locked by %s'),$lock->getStaffName()); -if(!$errors['err'] && ($emailBanned=TicketFilter::isBanned($ticket->getEmail()))) - $errors['err']=__('Email is in banlist! Must be removed before any reply/response'); + $warn.= sprintf(' <span class="Icon assignedTicket">%</span>', + sprintf(__('Ticket is assigned to %s'), + implode('/', $ticket->getAssignees()) + )); + +if (!$errors['err']) { + + if ($lock && $lock->getStaffId()!=$thisstaff->getId()) + $errors['err'] = sprintf(__('This ticket is currently locked by %s'), + $lock->getStaffName()); + elseif (($emailBanned=TicketFilter::isBanned($ticket->getEmail()))) + $errors['err'] = __('Email is in banlist! Must be removed before any reply/response'); +} $unbannable=($emailBanned) ? BanList::includes($ticket->getEmail()) : false;