Skip to content
Snippets Groups Projects
Commit f6ccc3f6 authored by Jared Hancock's avatar Jared Hancock
Browse files

orgs: Add ticket sharing feature

This feature allows (by option) an organization to allow its members to see
tickets from other members. It can be used beside or instead of the
automated collaboration feature. Now, collaborators retain access to tickets
on which they participate; however, sharing can be used to enable access to
other tickets owned by their organization.
parent 5d724803
No related branches found
No related tags found
No related merge requests found
...@@ -344,7 +344,7 @@ class UserNav { ...@@ -344,7 +344,7 @@ class UserNav {
$navs['new']=array('desc'=>__('Open a New Ticket'),'href'=>'open.php','title'=>''); $navs['new']=array('desc'=>__('Open a New Ticket'),'href'=>'open.php','title'=>'');
if($user && $user->isValid()) { if($user && $user->isValid()) {
if(!$user->isGuest()) { if(!$user->isGuest()) {
$navs['tickets']=array('desc'=>sprintf(__('Tickets (%d)'),$user->getNumTickets()), $navs['tickets']=array('desc'=>sprintf(__('Tickets (%d)'),$user->getNumTickets($user->canSeeOrgTickets())),
'href'=>'tickets.php', 'href'=>'tickets.php',
'title'=>__('Show all tickets')); 'title'=>__('Show all tickets'));
} else { } else {
......
...@@ -35,6 +35,9 @@ class OrganizationModel extends VerySimpleModel { ...@@ -35,6 +35,9 @@ class OrganizationModel extends VerySimpleModel {
const COLLAB_PRIMARY_CONTACT = 0x0002; const COLLAB_PRIMARY_CONTACT = 0x0002;
const ASSIGN_AGENT_MANAGER = 0x0004; const ASSIGN_AGENT_MANAGER = 0x0004;
const SHARE_PRIMARY_CONTACT = 0x0008;
const SHARE_EVERYBODY = 0x0010;
const PERM_CREATE = 'org.create'; const PERM_CREATE = 'org.create';
const PERM_EDIT = 'org.edit'; const PERM_EDIT = 'org.edit';
const PERM_DELETE = 'org.delete'; const PERM_DELETE = 'org.delete';
...@@ -100,6 +103,14 @@ class OrganizationModel extends VerySimpleModel { ...@@ -100,6 +103,14 @@ class OrganizationModel extends VerySimpleModel {
return $this->check(self::ASSIGN_AGENT_MANAGER); return $this->check(self::ASSIGN_AGENT_MANAGER);
} }
function shareWithPrimaryContacts() {
return $this->check(self::SHARE_PRIMARY_CONTACT);
}
function shareWithEverybody() {
return $this->check(self::SHARE_EVERYBODY);
}
function getUpdateDate() { function getUpdateDate() {
return $this->updated; return $this->updated;
} }
...@@ -206,6 +217,8 @@ implements TemplateVariable { ...@@ -206,6 +217,8 @@ implements TemplateVariable {
'collab-all-flag' => Organization::COLLAB_ALL_MEMBERS, 'collab-all-flag' => Organization::COLLAB_ALL_MEMBERS,
'collab-pc-flag' => Organization::COLLAB_PRIMARY_CONTACT, 'collab-pc-flag' => Organization::COLLAB_PRIMARY_CONTACT,
'assign-am-flag' => Organization::ASSIGN_AGENT_MANAGER, 'assign-am-flag' => Organization::ASSIGN_AGENT_MANAGER,
'sharing-primary' => Organization::SHARE_PRIMARY_CONTACT,
'sharing-all' => Organization::SHARE_EVERYBODY,
) as $ck=>$flag) { ) as $ck=>$flag) {
if ($this->check($flag)) if ($this->check($flag))
$base[$ck] = true; $base[$ck] = true;
...@@ -393,6 +406,16 @@ implements TemplateVariable { ...@@ -393,6 +406,16 @@ implements TemplateVariable {
$this->clearStatus($flag); $this->clearStatus($flag);
} }
foreach (array(
'sharing-primary' => Organization::SHARE_PRIMARY_CONTACT,
'sharing-all' => Organization::SHARE_EVERYBODY,
) as $ck=>$flag) {
if ($vars['sharing'] == $ck)
$this->setStatus($flag);
else
$this->clearStatus($flag);
}
// Set staff and primary contacts // Set staff and primary contacts
$this->set('domain', $vars['domain']); $this->set('domain', $vars['domain']);
$this->set('manager', $vars['manager'] ?: ''); $this->set('manager', $vars['manager'] ?: '');
......
...@@ -358,6 +358,18 @@ implements RestrictedAccess, Threadable { ...@@ -358,6 +358,18 @@ implements RestrictedAccess, Threadable {
if ($user->getId() == $this->getUserId()) if ($user->getId() == $this->getUserId())
return true; return true;
// Organization
if ($user->canSeeOrgTickets()
&& ($U = $this->getUser())
&& ($U->getOrgId() == $user->getOrgId())
) {
// The owner of this ticket is in the same organization as the
// user in question, and the organization is configured to allow
// the user in question to see other tickets in the
// organization.
return true;
}
// Collaborator? // Collaborator?
// 1) If the user was authorized via this ticket. // 1) If the user was authorized via this ticket.
if ($user->getTicketId() == $this->getId() if ($user->getTicketId() == $this->getId()
......
...@@ -432,6 +432,12 @@ implements TemplateVariable { ...@@ -432,6 +432,12 @@ implements TemplateVariable {
return (string) $account->getStatus(); return (string) $account->getStatus();
} }
function canSeeOrgTickets() {
return $this->org && (
$this->org->shareWithEverybody()
|| ($this->isPrimaryContact() && $this->org->shareWithPrimaryContacts()));
}
function register($vars, &$errors) { function register($vars, &$errors) {
// user already registered? // user already registered?
......
...@@ -16,17 +16,20 @@ if (isset($_REQUEST['status'])) { ...@@ -16,17 +16,20 @@ if (isset($_REQUEST['status'])) {
$settings['status'] = $_REQUEST['status']; $settings['status'] = $_REQUEST['status'];
} }
$org_tickets = $thisclient->canSeeOrgTickets();
if ($settings['keywords']) { if ($settings['keywords']) {
// Don't show stat counts for searches // Don't show stat counts for searches
$openTickets = $closedTickets = -1; $openTickets = $closedTickets = -1;
} }
elseif ($settings['topic_id']) { elseif ($settings['topic_id']) {
$openTickets = $thisclient->getNumTopicTicketsInState($settings['topic_id'], 'open'); $openTickets = $thisclient->getNumTopicTicketsInState($settings['topic_id'],
$closedTickets = $thisclient->getNumTopicTicketsInState($settings['topic_id'], 'closed'); 'open', $org_tickets);
$closedTickets = $thisclient->getNumTopicTicketsInState($settings['topic_id'],
'closed', $org_tickets);
} }
else { else {
$openTickets = $thisclient->getNumOpenTickets(); $openTickets = $thisclient->getNumOpenTickets($org_tickets);
$closedTickets = $thisclient->getNumClosedTickets(); $closedTickets = $thisclient->getNumClosedTickets($org_tickets);
} }
$tickets = TicketModel::objects(); $tickets = TicketModel::objects();
...@@ -63,10 +66,15 @@ $x=$sort.'_sort'; ...@@ -63,10 +66,15 @@ $x=$sort.'_sort';
$$x=' class="'.strtolower($_REQUEST['order'] ?: 'desc').'" '; $$x=' class="'.strtolower($_REQUEST['order'] ?: 'desc').'" ';
// Add visibility constraints // Add visibility constraints
$tickets->filter(Q::any(array( $visibility = Q::any(array(
'user_id' => $thisclient->getId(), 'user_id' => $thisclient->getId(),
'thread__collaborators__user_id' => $thisclient->getId(), 'thread__collaborators__user_id' => $thisclient->getId(),
))); ));
if ($thisclient->canSeeOrgTickets())
$visibility->add(array('user__org_id' => $thisclient->getOrgId()));
$tickets->filter($visibility);
// Perform basic search // Perform basic search
if ($settings['keywords']) { if ($settings['keywords']) {
...@@ -122,8 +130,9 @@ $tickets->values( ...@@ -122,8 +130,9 @@ $tickets->values(
<?php echo __('Help Topic'); ?>: <?php echo __('Help Topic'); ?>:
<select name="topic_id" class="nowarn" onchange="javascript: this.form.submit(); "> <select name="topic_id" class="nowarn" onchange="javascript: this.form.submit(); ">
<option value="">&mdash; <?php echo __('All Help Topics');?> &mdash;</option> <option value="">&mdash; <?php echo __('All Help Topics');?> &mdash;</option>
<?php foreach (Topic::getHelpTopics(true) as $id=>$name) { <?php
$count = $thisclient->getNumTopicTickets($id); foreach (Topic::getHelpTopics(true) as $id=>$name) {
$count = $thisclient->getNumTopicTickets($id, $org_tickets);
if ($count == 0) if ($count == 0)
continue; continue;
?> ?>
......
...@@ -98,6 +98,22 @@ if ($ticket && $ticket->getOwnerId() == $user->getId()) ...@@ -98,6 +98,22 @@ if ($ticket && $ticket->getOwnerId() == $user->getId())
</select> </select>
<br/><span class="error"><?php echo $errors['contacts']; ?></span> <br/><span class="error"><?php echo $errors['contacts']; ?></span>
</td> </td>
</tr>
<tr>
<td width="180">
<?php echo __('Ticket Sharing'); ?>:
</td>
<td>
<select name="sharing">
<option value=""><?php echo __('Disable'); ?></option>
<option value="sharing-primary" <?php echo $info['sharing-primary'] ? 'selected="selected"' : '';
?>><?php echo __('Primary contacts see all tickets'); ?></option>
<option value="sharing-all" <?php echo $info['sharing-all'] ? 'selected="selected"' : '';
?>><?php echo __('All members see all tickets'); ?></option>
</select>
<i class="help-tip icon-question-sign" href="#org-sharing"></i>
</td>
</tr>
<tr> <tr>
<th colspan="2"> <th colspan="2">
<?php echo __('Automated Collaboration'); ?>: <?php echo __('Automated Collaboration'); ?>:
...@@ -123,7 +139,7 @@ if ($ticket && $ticket->getOwnerId() == $user->getId()) ...@@ -123,7 +139,7 @@ if ($ticket && $ticket->getOwnerId() == $user->getId())
</tr> </tr>
<tr> <tr>
<th colspan="2"> <th colspan="2">
<?php echo __('Main Domain'); ?> <?php echo __('Email Domain'); ?>
</th> </th>
</tr> </tr>
<tr> <tr>
......
...@@ -128,7 +128,7 @@ if($ticket && $ticket->checkUserAccess($thisclient)) { ...@@ -128,7 +128,7 @@ if($ticket && $ticket->checkUserAccess($thisclient)) {
} }
else else
$inc='view.inc.php'; $inc='view.inc.php';
} elseif($thisclient->getNumTickets()) { } elseif($thisclient->getNumTickets($thisclient->canSeeOrgTickets())) {
$inc='tickets.inc.php'; $inc='tickets.inc.php';
} else { } else {
$nav->setActiveNav('new'); $nav->setActiveNav('new');
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment