diff --git a/include/class.thread.php b/include/class.thread.php index 353ce11b5ed6f38bf7651f974d3aa9b07b1e1c16..306cedf5240c0a5de01dcc2951c7864ae31b6850 100644 --- a/include/class.thread.php +++ b/include/class.thread.php @@ -366,6 +366,9 @@ implements Searchable { } $entries->filter($visibility); + + if ($type['hideBCC']) + $entries->exclude(array('flags__hasbit' => ThreadEntry::FLAG_REPLY_BCC)); } if ($options['sort'] && !strcasecmp($options['sort'], 'DESC')) @@ -760,6 +763,10 @@ implements TemplateVariable { const FLAG_COLLABORATOR = 0x0020; // Message from collaborator const FLAG_BALANCED = 0x0040; // HTML does not need to be balanced on ::display() const FLAG_SYSTEM = 0x0080; // Entry is a system note. + const FLAG_REPLY_ALL = 0x00100; // Agent response, reply all + const FLAG_REPLY_USER = 0x00200; // Agent response, reply to User + const FLAG_REPLY_COLLAB = 0x00400; // Agent response, reply to Collaborators + const FLAG_REPLY_BCC = 0x00800; // Agent response, reply to BCC const PERM_EDIT = 'thread.edit'; @@ -1476,6 +1483,26 @@ implements TemplateVariable { return $entry; } + function setReplyFlag($entry, $replyType) { + switch ($replyType) { + case 'reply-all': + return $entry->flags |= ThreadEntry::FLAG_REPLY_ALL; + break; + + case 'reply-user': + return $entry->flags |= ThreadEntry::FLAG_REPLY_USER; + break; + + case 'reply-collab': + return $entry->flags |= ThreadEntry::FLAG_REPLY_COLLAB; + break; + + case 'reply-bcc': + return $entry->flags |= ThreadEntry::FLAG_REPLY_BCC; + break; + } + } + //new entry ... we're trusting the caller to check validity of the data. static function create($vars=false) { global $cfg; @@ -1520,7 +1547,7 @@ implements TemplateVariable { $ticketUser = Ticket::objects()->filter(array('ticket_id'=>$ticket[0]))->values_flat('user_id')->first(); //User - if ($ticketUser) { + if ($ticketUser && (Ticket::checkReply('user', $vars['emailreply']) || $vars['do'] == 'create')) { $uEmail = UserEmailModel::objects()->filter(array('user_id'=>$ticketUser[0]))->values_flat('address')->first(); $u = array(); $u[$ticketUser[0]] = $uEmail[0]; @@ -1530,19 +1557,22 @@ implements TemplateVariable { if (Collaborator::getIdByUserId($vars['userId'], $vars['threadId'])) $entry->flags |= ThreadEntry::FLAG_COLLABORATOR; + //add reply type flag + self::setReplyFlag($entry, $vars['emailreply']); + //Cc collaborators - if($vars['ccs'] && $vars['emailcollab'] == 1) { + if ($vars['ccs'] && (Ticket::checkReply('cc', $vars['emailreply']) || $vars['do'] == 'create')) { $cc = Collaborator::getCollabList($vars['ccs']); $recipients['cc'] = $cc; } //Bcc Collaborators - if($vars['bccs'] && $vars['emailcollab'] == 1) { + if($vars['bccs'] && (Ticket::checkReply('bcc', $vars['emailreply']) || $vars['do'] == 'create')) { $bcc = Collaborator::getCollabList($vars['bccs']); $recipients['bcc'] = $bcc; } - if (($vars['do'] == 'create' || $vars['emailreply'] == 1) && $recipients) + if (($vars['do'] == 'create' || $vars['emailreply'] != '0') && $recipients) $entry->recipients = json_encode($recipients); if ($entry->format == 'html') diff --git a/include/class.ticket.php b/include/class.ticket.php index 008a1b29833bef9dc30362770fb9a460cffb242d..8ec533177c4bf3eaea576c9e8e495af1c14facb6 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -166,6 +166,7 @@ implements RestrictedAccess, Threadable, Searchable { var $active_collaborators; var $recipients; var $lastrespondent; + var $lastuserrespondent; function loadDynamicData($force=false) { if (!isset($this->_answers) || $force) { @@ -712,6 +713,26 @@ implements RestrictedAccess, Threadable, Searchable { return $this->lastrespondent; } + function getLastUserRespondent() { + if (!isset($this->$lastuserrespondent)) { + if (!$this->thread || !$this->thread->entries) + return $this->$lastuserrespondent = false; + $this->$lastuserrespondent = User::objects() + ->filter(array( + 'id' => $this->thread->entries + ->filter(array( + 'user_id__gt' => 0, + )) + ->values_flat('user_id') + ->order_by('-id') + ->limit(1) + )) + ->first() + ?: false; + } + return $this->$lastuserrespondent; + } + function getLastMessageDate() { return $this->thread->lastmessage; } @@ -1365,7 +1386,18 @@ implements RestrictedAccess, Threadable, Searchable { return false; } + function checkReply($userType, $replyType) { + if ($userType == 'cc' && ($replyType == 'reply-all' || $replyType == 'reply-collab')) + return true; + if ($userType == 'bcc' && ($replyType == 'reply-all' || $replyType == 'reply-bcc')) + return true; + + if ($userType == 'user' && ($replyType == 'reply-all' || $replyType == 'reply-user' || $replyType == 'reply-collab')) + return true; + + return false; + } function setAnsweredState($isanswered) { @@ -2978,17 +3010,18 @@ implements RestrictedAccess, Threadable, Searchable { $attachments = $cfg->emailAttachments() ? $response->getAttachments() : array(); //Cc collaborators $collabsCc = array(); - if ($vars['ccs'] && $vars['emailcollab']) { + if ($vars['ccs'] && Ticket::checkReply('cc', $vars['emailreply'])) { $collabsCc[] = Collaborator::getCollabList($vars['ccs']); $collabsCc['cc'] = $collabsCc[0]; } - $email->send($user, $msg['subj'], $msg['body'], $attachments, - $options, $collabsCc); + if (Ticket::checkReply('user', $vars['emailreply'])) + $email->send($user, $msg['subj'], $msg['body'], $attachments, + $options, $collabsCc); //Bcc Collaborators if ($vars['bccs'] - && $vars['emailcollab'] + && (Ticket::checkReply('bcc', $vars['emailreply'])) && ($bcctpl = $dept->getTemplate()) && ($bccmsg=$bcctpl->getReplyBCCMsgTemplate())) { foreach ($vars['bccs'] as $uid) { diff --git a/include/client/view.inc.php b/include/client/view.inc.php index fa48bdc3eaf2bb3aaf44ca37690fa64ff509eed3..3ff95cedafb6ea014b5381ede363f710736d5ce6 100644 --- a/include/client/view.inc.php +++ b/include/client/view.inc.php @@ -147,7 +147,7 @@ echo $v; $email = $thisclient->getUserName(); $clientId = TicketUser::lookupByEmail($email)->getId(); - $ticket->getThread()->render(array('M', 'R', 'user_id' => $clientId), array( + $ticket->getThread()->render(array('M', 'R', 'user_id' => $clientId, 'hideBCC' => !$viewThreads), array( 'mode' => Thread::MODE_CLIENT, 'html-id' => 'ticketThread') ); diff --git a/include/i18n/en_US/help/tips/tickets.queue.yaml b/include/i18n/en_US/help/tips/tickets.queue.yaml index a7145541614814f5d8bcfa29557d74380ccdb70a..a6238b0e79a538bef78aae4b4134f14c88147f95 100644 --- a/include/i18n/en_US/help/tips/tickets.queue.yaml +++ b/include/i18n/en_US/help/tips/tickets.queue.yaml @@ -76,3 +76,17 @@ adv_date_range: title: Search by Date Range content: > Definition here + +reply_types: + title: Reply Types + content: > + <b>Reply All:</b> + This reply is sent to the User and the Collaborators (CC and BCC) you choose to include.</br> + <b>Reply to User:</b> + This reply is sent to the User only, no Collaborators.</br> + <b>Reply to Collaborators:</b> + This reply is sent to only the User and CC'd Collaborators</br> + <b>Reply to BCC:</b> + This is sent only to the BCC'd Collaborators. + <b>Do Not Email Reply:</b> + No email alerts are sent out, however, the Agent response is visible to <b>ALL</b> Users upon viewing the Ticket. diff --git a/include/staff/templates/thread-entry.tmpl.php b/include/staff/templates/thread-entry.tmpl.php index 5781db359fb9fe1383bd8f2235f536bb2f910774..f32553f186fc5deb76785b5c1ca38825c719ba57 100644 --- a/include/staff/templates/thread-entry.tmpl.php +++ b/include/staff/templates/thread-entry.tmpl.php @@ -57,6 +57,18 @@ if ($entry->flags & ThreadEntry::FLAG_COLLABORATOR && $entry->type == 'N') { <?php } if ($entry->flags & ThreadEntry::FLAG_RESENT) { ?> <span class="label label-bare"><?php echo __('Resent'); ?></span> +<?php } + if ($entry->flags & ThreadEntry::FLAG_REPLY_ALL) { ?> + <span class="label label-bare"><?php echo __('Reply All'); ?></span> +<?php } + if ($entry->flags & ThreadEntry::FLAG_REPLY_USER) { ?> + <span class="label label-bare"><?php echo __('Reply to User'); ?></span> +<?php } + if ($entry->flags & ThreadEntry::FLAG_REPLY_COLLAB) { ?> + <span class="label label-bare"><?php echo __('Reply to Collaborator'); ?></span> +<?php } + if ($entry->flags & ThreadEntry::FLAG_REPLY_BCC) { ?> + <span class="label label-bare"><?php echo __('Reply to BCC'); ?></span> <?php } if ($entry->flags & ThreadEntry::FLAG_COLLABORATOR && $entry->type == 'B') { ?> <span class="label label-bare"><?php echo __('Bcc Collaborator'); ?></span> diff --git a/include/staff/ticket-view.inc.php b/include/staff/ticket-view.inc.php index b5ededef80a34f4bd784568e908c2edf1b8ef8fe..8715462fb486ddd49512aebeae31d9cac04f86ba 100644 --- a/include/staff/ticket-view.inc.php +++ b/include/staff/ticket-view.inc.php @@ -738,21 +738,36 @@ if ($errors['err'] && isset($_POST['a'])) { <?php } ?> <tr> <td width="120"> - <label><strong><?php echo __('To'); ?>:</strong></label> + <label><strong><?php echo __('Reply To'); ?>:</strong></label> </td> <td> <?php - # XXX: Add user-to-name and user-to-email HTML ID#s - $to =sprintf('%s <%s>', - Format::htmlchars($ticket->getName()), - $ticket->getReplyToEmail()); - $emailReply = (!isset($info['emailreply']) || $info['emailreply']); + //see who sent the last message and decide which option to select. + $lastUser = $ticket->getLastUserRespondent(); + + if ($ticket->getOwnerId() == $lastUser->getId()) + $ticketUser = true; + else { + $collabs = $ticket->getThread()->getCollaborators(); + foreach ($collabs as $collab) { + if ($collab->getUserId() == $lastUser->getId() && $collab->isCc()) + $ccUser = true; + elseif ($collab->getUserId() == $lastUser->getId() && !$collab->isCc()) + $bccUser = true; + } + } + if ($ticketUser || $ccUser || $bccUser) + $emailReply = true; ?> <select id="emailreply" name="emailreply"> - <option value="1" <?php echo $emailReply ? 'selected="selected"' : ''; ?>><?php echo $to; ?></option> + <option value="reply-all"><?php echo __('Reply All'); ?></option> + <option value="reply-user"><?php echo __('Reply to User'); ?></option> + <option value="reply-collab" <?php echo ($ccUser || $ticketUser ) ? 'selected="selected"' : ''; ?>><?php echo __('Reply to Collaborators'); ?></option> + <option value="reply-bcc" <?php echo $bccUser || $errors['bccs'] ? 'selected="selected"' : ''; ?>><?php echo __('Reply to BCC'); ?></option> <option value="0" <?php echo !$emailReply ? 'selected="selected"' : ''; ?> >— <?php echo __('Do Not Email Reply'); ?> —</option> </select> + <i class="help-tip icon-question-sign" href="#reply_types"></i> </td> </tr> </tbody> @@ -761,18 +776,12 @@ if ($errors['err'] && isset($_POST['a'])) { ?> <tbody id="cc_sec" style="display:<?php echo $emailReply? 'table-row-group':'none'; ?>;"> - <tr> - <td width="120"> - <label><strong><?php echo __('Collaborators'); ?>:</strong></label> + <tr id="user-row"> + <td width="120" style="padding-left:20px;"> + <label><?php echo __('User'); ?></label> </td> <td> - <input type='checkbox' value='1' name="emailcollab" - id="t<?php echo $ticket->getThreadId(); ?>-emailcollab" - <?php echo ((!$info['emailcollab'] && !$errors) || isset($info['emailcollab']))?'checked="checked"':''; ?> - style="display:<?php echo $ticket->getThread()->getNumCollaborators() ? 'inline-block': 'none'; ?>;" - > - <?php - ?> + <label><?php echo User::lookup($ticket->user_id); ?></label> </td> </tr> <?php $collaborators = $ticket->getThread()->getCollaborators(); @@ -786,8 +795,8 @@ if ($errors['err'] && isset($_POST['a'])) { } } ?> - <tr> - <td width="160"><b><?php echo __('Cc'); ?>:</b></td> + <tr id="cc-row"> + <td width="160" style="padding-left:20px;"><?php echo __('Cc'); ?></td> <td> <select class="collabSelections" name="ccs[]" id="cc_users" multiple="multiple" data-placeholder="<?php echo __('Select Contacts'); ?>"> @@ -805,8 +814,8 @@ if ($errors['err'] && isset($_POST['a'])) { <br/><span class="error"><?php echo $errors['ccs']; ?></span> </td> </tr> - <tr> - <td width="160"><b><?php echo __('Bcc'); ?>:</b></td> + <tr id="bcc-row"> + <td width="160" style="padding-left:20px;"><?php echo __('Bcc'); ?></td> <td> <select class="collabSelections" name="bccs[]" id="bcc_users" multiple="multiple" data-placeholder="<?php echo __('Select Contacts'); ?>"> @@ -1162,6 +1171,10 @@ $(function() { }); }); + $("#emailreply").ready(function(){ + checkReply(); + }); + // Post Reply or Note action buttons. $('a.post-response').click(function (e) { var $r = $('ul.tabs > li > a'+$(this).attr('href')+'-tab'); @@ -1186,6 +1199,40 @@ $(function() { return false; }); + $('#emailreply').on('change', function(){ + checkReply(); + }); + + function checkReply() { + var value = $("#emailreply").val(); + switch (value) { + case "reply-all": + $('#user-row').show(); + $('#cc-row').show(); + $('#bcc-row').show(); + break; + case "reply-user": + $('#user-row').show(); + $('#cc-row').hide(); + $('#bcc-row').hide(); + break; + case "reply-collab": + $('#user-row').show(); + $('#cc-row').show(); + $('#bcc-row').hide(); + break; + case "reply-bcc": + $('#user-row').hide(); + $('#cc-row').hide(); + $('#bcc-row').show(); + break; + default: + $('#user-row').show(); + $('#cc-row').show(); + $('#bcc-row').hide(); + break; + } + } }); $(function() { diff --git a/scp/tickets.php b/scp/tickets.php index 2d04b89efc48ccedab6099f58bee837d72ac2b9d..8698fa0f407882ad9fb6d18f98ef1469f56ba034 100644 --- a/scp/tickets.php +++ b/scp/tickets.php @@ -152,6 +152,12 @@ if($_POST && !$errors): if(!$vars['response']) $errors['response']=__('Response required'); + //do not post a thread entry if response intended for only bccs and there are no bccs + if (is_null($vars['bccs']) && $vars['emailreply'] == 'reply-bcc') { + $vars['emailreply'] = 'reply-bcc'; + $errors['bccs']=sprintf(__('Please add a %s'), 'BCC Recipient'); + } + if ($cfg->getLockTime()) { if (!$lock) { $errors['err'] = sprintf('%s %s', __('This action requires a lock.'), __('Please try again!'));