Permalink
Browse files

feature: Release Role Permission

This feature adds a new Role permission called Release. This permission
(if Enabled) allows an Agent to release ticket assignment. This permission
is configurable for each and every Role in the helpdesk. This also keeps
current functionality where Department Managers do not need the Role
Permission in order to release tickets. In addition to the permission,
this feature adds a new Release modal giving the option to choose who to
release assignment from (Agent/Team/Both). This also adds a comment box to
the release modal to optionally enter a reason for releasing assignment.
Lastly, this adds a Release Thread Event so an event is logged showing who
released who’s assignment.
  • Loading branch information...
JediKev committed Jun 12, 2018
1 parent 3cbc57e commit d354e095f7cba226c83f62a884bfe59799774fa6
@@ -652,6 +652,66 @@ function claim($tid) {
}
function release($tid) {
global $thisstaff;
if (!($ticket=Ticket::lookup($tid)))
Http::response(404, __('No such ticket'));
if (!$ticket->checkStaffPerm($thisstaff, Ticket::PERM_RELEASE) && !$thisstaff->isManager())
Http::response(403, __('Permission denied'));
if (!$ticket->isAssigned())
$errors['err'] = __('Ticket is not assigned!');
$errors = array();
$info = array(':title' => sprintf(__('Ticket #%s: %s'),
$ticket->getNumber(),
__('Release Confirmation')));
$form = ReleaseForm::instantiate($_POST);
$hasData = ($_POST['sid'] || $_POST['tid']);
$staff = $ticket->getStaff();
$team = $ticket->getTeam();
if ($_POST) {
if ($hasData && $ticket->release($_POST, $errors)) {
$data = array();
if ($staff && !$ticket->getStaff())
$data['staff'] = array($staff->getId(), (string) $staff->getName()->getOriginal());
if ($team && !$ticket->getTeam())
$data['team'] = $team->getId();
$ticket->logEvent('released', $data);
$comments = $form->getComments();
if ($comments) {
$title = __('Assignment Released');
$_errors = array();
$ticket->postNote(
array('note' => $comments, 'title' => $title),
$_errors, $thisstaff, false);
}
$_SESSION['::sysmsgs']['msg'] = __('Ticket assignment released successfully');
Http::response(201, $ticket->getId());
}
if (!$hasData)
$errors['err'] = __('Please check an assignee to release assignment');
$form->addErrors($errors);
$info['error'] = $errors['err'] ?: __('Unable to release ticket assignment');
}
if($errors && $errors['err'])
$info['error'] = $errors['err'] ?: __('Unable to release ticket');
include STAFFINC_DIR . 'templates/release.tmpl.php';
}
function massProcess($action, $w=null) {
global $thisstaff, $cfg;
@@ -4928,6 +4928,49 @@ function getFields() {
}
class ReleaseForm extends Form {
static $id = 'unassign';
function getFields() {
if ($this->fields)
return $this->fields;
$fields = array(
'comments' => new TextareaField(array(
'id' => 1, 'label'=> '', 'required'=>false, 'default'=>'',
'configuration' => array(
'html' => true,
'size' => 'small',
'placeholder' => __('Optional reason for releasing assignment'),
),
)
),
);
$this->setFields($fields);
return $this->fields;
}
function getField($name) {
if (($fields = $this->getFields())
&& isset($fields[$name]))
return $fields[$name];
}
function isValid($include=false) {
if (!parent::isValid($include))
return false;
return !$this->errors();
}
function getComments() {
return $this->getField('comments')->getClean();
}
}
class ReferralForm extends Form {
static $id = 'refer';
@@ -1871,6 +1871,7 @@ class ThreadEvent extends VerySimpleModel {
// Valid events for database storage
const ASSIGNED = 'assigned';
const RELEASED = 'released';
const CLOSED = 'closed';
const CREATED = 'created';
const COLLAB = 'collab';
@@ -1906,6 +1907,7 @@ function getUserName() {
function getIcon() {
$icons = array(
'assigned' => 'hand-right',
'released' => 'unlock',
'collab' => 'group',
'created' => 'magic',
'overdue' => 'time',
@@ -2092,7 +2094,7 @@ function annul($event) {
* $object - Object to log activity for
* $state - State name of the activity (one of 'created', 'edited',
* 'deleted', 'closed', 'reopened', 'error', 'collab', 'resent',
* 'assigned', 'transferred')
* 'assigned', 'released', 'transferred')
* $data - (array?) Details about the state change
* $user - (string|User|Staff) user triggering the state change
* $annul - (state) a corresponding state change that is annulled by
@@ -2175,6 +2177,30 @@ function getDescription($mode=self::MODE_STAFF) {
}
}
class ReleaseEvent extends ThreadEvent {
static $icon = 'unlock';
static $state = 'released';
function getDescription($mode=self::MODE_STAFF) {
$data = $this->getData();
switch (true) {
case isset($data['staff'], $data['team']):
$desc = __('Ticket released from <strong>{<Team>data.team}</strong> and <strong>{<Staff>data.staff}</strong> by <b>{somebody}</b> {timestamp}');
break;
case isset($data['staff']):
$desc = __('Ticket released from <strong>{<Staff>data.staff}</strong> by <b>{somebody}</b> {timestamp}');
break;
case isset($data['team']):
$desc = __('Ticket released from <strong>{<Team>data.team}</strong> by <b>{somebody}</b> {timestamp}');
break;
default:
$desc = __('<b>{somebody}</b> released ticket assignment {timestamp}');
break;
}
return $this->template($desc);
}
}
class ReferralEvent extends ThreadEvent {
static $icon = 'exchange';
static $state = 'referred';
@@ -98,6 +98,7 @@ class Ticket extends VerySimpleModel
const PERM_CREATE = 'ticket.create';
const PERM_EDIT = 'ticket.edit';
const PERM_ASSIGN = 'ticket.assign';
const PERM_RELEASE = 'ticket.release';
const PERM_TRANSFER = 'ticket.transfer';
const PERM_REPLY = 'ticket.reply';
const PERM_CLOSE = 'ticket.close';
@@ -119,6 +120,11 @@ class Ticket extends VerySimpleModel
/* @trans */ 'Assign',
'desc' =>
/* @trans */ 'Ability to assign tickets to agents or teams'),
self::PERM_RELEASE => array(
'title' =>
/* @trans */ 'Release',
'desc' =>
/* @trans */ 'Ability to release ticket assignment'),
self::PERM_TRANSFER => array(
'title' =>
/* @trans */ 'Transfer',
@@ -2470,8 +2476,15 @@ function unassign() {
return true;
}
function release() {
return $this->unassign();
function release($info=array(), &$errors) {
if ($info['sid'] && $info['tid'])
return $this->unassign();
elseif ($info['sid'] && $this->setStaffId(0))
return true;
elseif ($info['tid'] && $this->setTeamId(0))
return true;
return false;
}
function refer(ReferralForm $form, &$errors, $alert=true) {
@@ -20,6 +20,7 @@
ticket.create,
ticket.edit,
ticket.assign,
ticket.release,
ticket.transfer,
ticket.reply,
ticket.close,
@@ -44,6 +45,7 @@
ticket.create,
ticket.edit,
ticket.assign,
ticket.release,
ticket.transfer,
ticket.reply,
ticket.close,
@@ -0,0 +1,89 @@
<?php
global $cfg;
$assignees = array();
if (($staff = $ticket->getStaff()))
$assignees[] = $staff;
if (($team = $ticket->getTeam()))
$assignees[] = $team;
$form = ReleaseForm::instantiate($_POST);
?>
<h3 class="drag-handle"><?php echo $info[':title'] ?: __('Release Confirmation'); ?></h3>
<b><a class="close" href="#"><i class="icon-remove-circle"></i></a></b>
<div class="clear"></div>
<hr/>
<?php
if ($info['error']) {
echo sprintf('<p id="msg_error">%s</p>', $info['error']);
} elseif ($info['warn']) {
echo sprintf('<p id="msg_warning">%s</p>', $info['warn']);
} elseif ($info['msg']) {
echo sprintf('<p id="msg_notice">%s</p>', $info['msg']);
} elseif ($info['notice']) {
echo sprintf('<p id="msg_info"><i class="icon-info-sign"></i> %s</p>',
$info['notice']);
}
?>
<form class="mass-action" method="post"
action="#tickets/<?php echo $ticket->getId(); ?>/release"
name="release">
<input type='hidden' name='do' value='release'>
<table width="100%">
<tbody>
<?php if ($staff && $team) { ?>
<tr><td>
<p>
<?php echo __('Please check assignee(s) to release assignment.'); ?>
</p>
</td></tr>
<?php } ?>
<?php if(count($assignees) > 1) { ?>
<?php foreach($assignees as $assignee) { ?>
<tr><td>
<label class="inline checkbox">
<?php echo sprintf(
($isStaff = $assignee instanceof Staff)
? '<input type="checkbox" name="sid[]" id="s%d" value="%d">'
: '<input type="checkbox" name="tid[]" id="t%d" value="%d">',
$assignee->getId(),
$assignee->getId()); ?>
</label>
<?php echo '<i class="icon-'.(($isStaff) ? 'user' : 'group').'"></i>'; ?>
<?php echo $assignee->getName(); ?>
</td></tr>
<?php } ?>
<?php } else { ?>
<tr><td>
<input type="hidden" name="<?php echo (($staff)?'s':'t').'id[]'; ?>" value="()">
<p>
<?php echo __('Please confirm to continue.'); ?>
</p>
<p>
<?php echo sprintf(
__('Are you sure you want to <b>unassign</b> ticket from <b>%s</b>?'),
($staff) ?: $team); ?>
</p>
</td></tr>
<?php } ?>
<tr><td>
<p>
<?php print $form->getField('comments')->render(); ?>
</p>
</td></tr>
</tbody>
</table>
<hr>
<p class="full-width">
<span class="buttons pull-left">
<input type="reset" value="<?php echo __('Reset'); ?>">
<input type="button" name="cancel" class="close"
value="<?php echo __('Cancel'); ?>">
</span>
<span class="buttons pull-right">
<input type="submit" value="<?php
echo __('Release'); ?>">
</span>
</p>
</form>
<div class="clear"></div>
@@ -20,6 +20,8 @@
$lock = $ticket->acquireLock($thisstaff->getId());
$mylock = ($lock && $lock->getStaffId() == $thisstaff->getId()) ? $lock : null;
$id = $ticket->getId(); //Ticket ID.
$isManager = $dept->isManager($thisstaff); //Check if Agent is Manager
$canRelease = ($isManager || $role->hasPerm(Ticket::PERM_RELEASE)); //Check if Agent can release tickets
//Useful warnings and errors the user might want to know!
if ($ticket->isClosed() && !$ticket->isReopenable())
@@ -146,14 +148,14 @@ class="icon-group"></i> <?php echo __('Team'); ?></a>
<?php
}
if($ticket->isOpen() && ($dept && $dept->isManager($thisstaff))) {
if($ticket->isAssigned()) { ?>
<li><a class="confirm-action" id="ticket-release" href="#release"><i class="icon-user"></i> <?php
echo __('Release (unassign) Ticket'); ?></a></li>
<?php
}
if ($ticket->isAssigned() && $canRelease) { ?>
<li><a href="#tickets/<?php echo $ticket->getId();
?>/release" class="ticket-action"
data-redirect="tickets.php?id=<?php echo $ticket->getId(); ?>" >
<i class="icon-unlock"></i> <?php echo __('Release (unassign) Ticket'); ?></a></li>
<?php
}
if($ticket->isOpen() && $isManager) {
if(!$ticket->isOverdue()) { ?>
<li><a class="confirm-action" id="ticket-overdue" href="#overdue"><i class="icon-bell"></i> <?php
echo __('Mark as Overdue'); ?></a></li>
@@ -167,6 +167,7 @@ function staffLoginPage($msg='Unauthorized') {
url('^(?P<tid>\d+)/field/(?P<fid>\d+)/edit$', 'editField'),
url('^(?P<tid>\d+)/field/(?P<field>\w+)/edit$', 'editField'),
url('^(?P<tid>\d+)/assign(?:/(?P<to>\w+))?$', 'assign'),
url('^(?P<tid>\d+)/release$', 'release'),
url('^(?P<tid>\d+)/refer(?:/(?P<to>\w+))?$', 'refer'),
url('^(?P<tid>\d+)/referrals$', 'referrals'),
url('^(?P<tid>\d+)/claim$', 'claim'),
@@ -282,19 +282,6 @@
break;
case 'process':
switch(strtolower($_POST['do'])):
case 'release':
if(!$ticket->isAssigned() || !($assigned=$ticket->getAssigned())) {
$errors['err'] = __('Ticket is not assigned!');
} elseif($ticket->release()) {
$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);
} else {
$errors['err'] = sprintf('%s %s', __('Problems releasing the ticket.'), __('Please try again!'));
}
break;
case 'claim':
if(!$role->hasPerm(Ticket::PERM_EDIT)) {
$errors['err'] = __('Permission Denied. You are not allowed to assign/claim tickets.');

0 comments on commit d354e09

Please sign in to comment.