diff --git a/include/ajax.tickets.php b/include/ajax.tickets.php index 1b901041a9b983b2af497f70d82b2c70cb10a562..68aaf24ae5180137412e5f05cad11a23b2e9c0f8 100644 --- a/include/ajax.tickets.php +++ b/include/ajax.tickets.php @@ -505,6 +505,10 @@ class TicketsAjaxAPI extends AjaxController { $errors['err'] = sprintf('Ticket owner, %s, is a collaborator by default!', $user->getName()); elseif (($c=$ticket->addCollaborator($user, $errors))) { + $note = Format::htmlchars(sprintf('%s <%s> added as a collaborator', + $c->getName(), $c->getEmail())); + $ticket->logNote('New Collaborator Added', $note, + $thisstaff, false); $info = array('msg' => sprintf('%s added as a collaborator', $c->getName())); return self::_collaborators($ticket, $info); @@ -564,7 +568,23 @@ class TicketsAjaxAPI extends AjaxController { return self::_addcollaborator($ticket); } + function previewCollaborators($tid) { + global $thisstaff; + + if (!($ticket=Ticket::lookup($tid)) + || !$ticket->checkStaffAccess($thisstaff)) + Http::response(404, 'No such ticket'); + + if (!$ticket->getCollaborators()) + Http::response(404, 'No such ticket'); + ob_start(); + include STAFFINC_DIR . 'templates/collaborators-preview.tmpl.php'; + $resp = ob_get_contents(); + ob_end_clean(); + + return $resp; + } function _addcollaborator($ticket, $user=null, $form=null, $info=array()) { @@ -586,7 +606,9 @@ class TicketsAjaxAPI extends AjaxController { $errors = $info = array(); if ($ticket->updateCollaborators($_POST, $errors)) - Http::response(201, sprintf('Recipients (%d)', $ticket->getNumActiveCollaborators())); + Http::response(201, sprintf('Recipients (%d of %d)', + $ticket->getNumActiveCollaborators(), + $ticket->getNumCollaborators())); if($errors && $errors['err']) $info +=array('error' => $errors['err']); diff --git a/include/class.collaborator.php b/include/class.collaborator.php index e04d8571226f539cf82546a0c641a87eb1a026e3..bf57617d70b6f7555cae73db9403b5b79d47d8f7 100644 --- a/include/class.collaborator.php +++ b/include/class.collaborator.php @@ -54,6 +54,11 @@ class Collaborator { return call_user_func(array($user, $name)); } + function __toString() { + return Format::htmlchars(sprintf('%s <%s>', $this->getName(), + $this->getEmail())); + } + function getId() { return $this->ht['id']; } @@ -85,6 +90,15 @@ class Collaborator { return $this->user; } + function remove() { + + $sql='DELETE FROM '.TICKET_COLLABORATOR_TABLE + .' WHERE id='.db_input($this->getId()) + .' LIMIT 1'; + + return (db_query($sql) && db_affected_rows()); + } + static function add($info, &$errors) { if(!$info || !$info['ticketId'] || !$info['userId']) diff --git a/include/class.ticket.php b/include/class.ticket.php index 9d0b621af858d68c0390a67ce4fbcdcaa0640173..5f829a86533c90aacb99dbf137a9f3d35b792da7 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -67,16 +67,13 @@ class Ticket { .' ,IF(sla.id IS NULL, NULL, ' .'DATE_ADD(ticket.created, INTERVAL sla.grace_period HOUR)) as sla_duedate ' .' ,count(distinct attach.attach_id) as attachments' - .' ,count(distinct collab.id) as collaborators ' .' FROM '.TICKET_TABLE.' ticket ' .' LEFT JOIN '.DEPT_TABLE.' dept ON (ticket.dept_id=dept.dept_id) ' .' LEFT JOIN '.SLA_TABLE.' sla ON (ticket.sla_id=sla.id AND sla.isactive=1) ' - .' LEFT JOIN '.TICKET_LOCK_TABLE.' tlock ON (' - .'ticket.ticket_id=tlock.ticket_id AND tlock.expire>NOW()) ' - .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach ON (' - .'ticket.ticket_id=attach.ticket_id) ' - .' LEFT JOIN '.TICKET_COLLABORATOR_TABLE.' collab ON (' - .'ticket.ticket_id=collab.ticket_id) ' + .' LEFT JOIN '.TICKET_LOCK_TABLE.' tlock + ON ( ticket.ticket_id=tlock.ticket_id AND tlock.expire>NOW()) ' + .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach + ON ( ticket.ticket_id=attach.ticket_id) ' .' WHERE ticket.ticket_id='.db_input($id) .' GROUP BY ticket.ticket_id'; @@ -562,7 +559,7 @@ class Ticket { //Collaborators function getNumCollaborators() { - return $this->ht['collaborators']; + return count($this->getCollaborators()); } function getNumActiveCollaborators() { @@ -580,10 +577,10 @@ class Ticket { function getCollaborators($criteria=array()) { - if($criteria) + if ($criteria) return Collaborator::forTicket($this->getId(), $criteria); - if(!$this->collaborators && $this->getNumCollaborators()) + if (!isset($this->collaborators)) $this->collaborators = Collaborator::forTicket($this->getId()); return $this->collaborators; @@ -600,24 +597,29 @@ class Ticket { if(!($c=Collaborator::add($vars, $errors))) return null; - $this->ht['collaborators'] +=1; $this->collaborators = null; - return $c; } //XXX: Ugly for now function updateCollaborators($vars, &$errors) { + global $thisstaff; + if (!$thisstaff) return; //Deletes if($vars['del'] && ($ids=array_filter($vars['del']))) { - $sql='DELETE FROM '.TICKET_COLLABORATOR_TABLE - .' WHERE ticket_id='.db_input($this->getId()) - .' AND id IN('.implode(',', db_input($ids)).')'; - if(db_query($sql)) - $this->ht['collaborators'] -= db_affected_rows(); + $collabs = array(); + foreach ($ids as $k => $cid) { + if (($c=Collaborator::lookup($cid)) + && $c->getTicketId() == $this->getId() + && $c->remove()) + $collabs[] = $c; + } + + $this->logNote('Collaborators Removed', + implode("<br>", $collabs), $thisstaff, false); } //statuses @@ -1456,10 +1458,18 @@ class Ticket { $this->setLastMsgId($message->getId()); //Add email recipients as collaborators - if($vars['recipients']) { - foreach($vars['recipients'] as $recipient) - if(($user=User::fromVars($recipient))) - $this->addCollaborator($user, $errors); + if ($vars['recipients']) { + $collabs = array(); + foreach ($vars['recipients'] as $recipient) { + if (($user=User::fromVars($recipient))) + if ($c=$this->addCollaborator($user, $errors)) + $collabs[] = $c; + } + //TODO: Can collaborators add others? + if ($collabs) { + $this->logNote('Collaborators CCed by enduser', + implode("<br>", $collabs), 'EndUser', false); + } } if(!$alerts) return $message; //Our work is done... diff --git a/include/staff/templates/collaborators-preview.tmpl.php b/include/staff/templates/collaborators-preview.tmpl.php new file mode 100644 index 0000000000000000000000000000000000000000..45cfecca268ddca8e8c2d9dfc91ef432613ab419 --- /dev/null +++ b/include/staff/templates/collaborators-preview.tmpl.php @@ -0,0 +1,28 @@ +<div> +<table border="0" cellspacing="" cellpadding="1"> +<colgroup><col style="min-width: 250px;"></col></colgroup> +<?php +if (($users=$ticket->getCollaborators())) {?> +<?php + foreach($users as $user) { + echo sprintf('<tr><td %s><i class="icon-%s"></i> %s <em><%s></em></td></tr>', + ($user->isActive()? 'class="faded"' : ''), + ($user->isActive()? 'comments' : 'comment-alt'), + $user->getName(), + $user->getEmail()); + } +} else { + echo "Bro, not sure how you got here!"; +}?> +</table> +<?php +$options = array(); +//TODO: Add options to manage collaborators +if ($options) { + echo '<ul class="tip_menu">'; + foreach($options as $option) + echo sprintf('<li><a href="%s">%s</a></li>', $option['url'], $option['action']); + echo '</ul>'; +} +?> +</div> diff --git a/include/staff/ticket-view.inc.php b/include/staff/ticket-view.inc.php index b255b225dc2aa43fc2c0aa4973513680218ab5c5..6fee37da63a4817fb462815677b2a0bf14370f87 100644 --- a/include/staff/ticket-view.inc.php +++ b/include/staff/ticket-view.inc.php @@ -446,18 +446,19 @@ $tcount+= $ticket->getNumNotes(); <label><strong>Collaborators:</strong></label> </td> <td> + <input type='checkbox' value='1' name="emailcollab" id="emailcollab" + <?php echo ((!$info['emailcollab'] && !$errors) || isset($info['emailcollab']))?'checked="checked"':''; ?> + style="display:<?php echo $ticket->getNumCollaborators() ? 'inline-block': 'none'; ?>;" + > <?php - if($ticket->getNumCollaborators()) { ?> - <input type='checkbox' value='1' name="emailcollab" id="emailcollab" - <?php echo ((!$info['emailcollab'] && !$errors) || isset($info['emailcollab']))?'checked="checked"':''; ?>> - <?php - } $recipients = 'Add Recipients'; if ($ticket->getNumCollaborators()) - $recipients = sprintf('Recipients (%d)', $ticket->getNumActiveCollaborators()); + $recipients = sprintf('Recipients (%d of %d)', + $ticket->getNumActiveCollaborators(), + $ticket->getNumCollaborators()); - echo sprintf('<span><a class="collaborators" - href="#tickets/%d/collaborators/manage"><span id="recipients">%s</span></a></span>', + echo sprintf('<span><a class="collaborators" id="manageCollab" + href="#tickets/%d/collaborators"><span id="recipients">%s</span></a></span>', $ticket->getId(), $recipients); ?> diff --git a/scp/ajax.php b/scp/ajax.php index 7e990934b8abe59b1b9a1aecfd3ccd91cfb06271..8c321ead8182568084e21ccd91091e51fb431c46 100644 --- a/scp/ajax.php +++ b/scp/ajax.php @@ -79,7 +79,8 @@ $dispatcher = patterns('', url_post('^(?P<tid>\d+)/lock$', 'acquireLock'), url_post('^(?P<tid>\d+)/lock/(?P<id>\d+)/renew', 'renewLock'), url_post('^(?P<tid>\d+)/lock/(?P<id>\d+)/release', 'releaseLock'), - url_get('^(?P<tid>\d+)/collaborators/manage$', 'showCollaborators'), + url_get('^(?P<tid>\d+)/collaborators/preview$', 'previewCollaborators'), + url_get('^(?P<tid>\d+)/collaborators$', 'showCollaborators'), url_post('^(?P<tid>\d+)/collaborators$', 'updateCollaborators'), url_get('^(?P<tid>\d+)/add-collaborator/(?P<uid>\d+)$', 'addCollaborator'), url_get('^(?P<tid>\d+)/add-collaborator/auth:(?P<bk>\w+):(?P<id>.+)$', 'addRemoteCollaborator'), diff --git a/scp/js/ticket.js b/scp/js/ticket.js index cbe25c1e39f4ae8d6b2917acc5fbe47c5a9a5f73..ad51940e995ccb73fa30e6cf50eda37b67811958 100644 --- a/scp/js/ticket.js +++ b/scp/js/ticket.js @@ -368,6 +368,7 @@ jQuery(function($) { e.preventDefault(); var url = 'ajax.php/'+$(this).attr('href').substr(1); $.dialog(url, 201, function (resp) { + $('input#emailcollab').show(); $('#recipients').text(resp); }); return false; diff --git a/scp/js/tips.js b/scp/js/tips.js index 205eb6fc9d2df8edbbd17d3ad43dbfab76145d36..db94a1acb362cb5b64e4b56178a5d6d780e3b00a 100644 --- a/scp/js/tips.js +++ b/scp/js/tips.js @@ -160,6 +160,28 @@ jQuery(function() { clearTimeout($(this).data('timer')); }); + + $('a#manageCollab').live('mouseover', function(e) { + e.preventDefault(); + var elem = $(this); + + var url = 'ajax.php/'+elem.attr('href').substr(1)+'/preview'; + var xoffset = 100; + elem.data('timer', 0); + + if (e.type=='mouseover') { + elem.data('timer',setTimeout(function() { showtip(url, elem, xoffset);},750)) + } else { + showtip(url,elem,xoffset); + } + }).live('mouseout', function(e) { + clearTimeout($(this).data('timer')); + }).live('click', function(e) { + clearTimeout($(this).data('timer')); + $('.tip_box').remove(); + }); + + //Ticket preview $('.ticketPreview').live('mouseover', function(e) { e.preventDefault();