diff --git a/include/class.nav.php b/include/class.nav.php index 6e0179890938e6f7a933f7b089b2368dd8e0afa2..992daf107f8f8c212d4fc5528a9912e0f5e21e1b 100644 --- a/include/class.nav.php +++ b/include/class.nav.php @@ -96,9 +96,10 @@ class StaffNav { if(!$this->tabs) { $this->tabs=array(); - $this->tabs['dashboard']=array('desc'=>'Dashboard','href'=>'dashboard.php','title'=>'Staff Dashboard'); - $this->tabs['tickets']=array('desc'=>'Tickets','href'=>'tickets.php','title'=>'Ticket Queue'); - $this->tabs['kbase']=array('desc'=>'Knowledgebase','href'=>'kb.php','title'=>'Knowledgebase'); + $this->tabs['dashboard'] = array('desc'=>'Dashboard','href'=>'dashboard.php','title'=>'Staff Dashboard'); + $this->tabs['users'] = array('desc' => 'Users', 'href' => 'users.php', 'title' => 'User Directory'); + $this->tabs['tickets'] = array('desc'=>'Tickets','href'=>'tickets.php','title'=>'Ticket Queue'); + $this->tabs['kbase'] = array('desc'=>'Knowledgebase','href'=>'kb.php','title'=>'Knowledgebase'); } return $this->tabs; @@ -134,6 +135,10 @@ class StaffNav { $subnav[]=array('desc'=>'Staff Directory','href'=>'directory.php','iconclass'=>'teams'); $subnav[]=array('desc'=>'My Profile','href'=>'profile.php','iconclass'=>'users'); break; + case 'users': + $subnav[] = array('desc' => 'User Directory', 'href' => 'users.php', 'iconclass' => 'teams'); + $subnav[] = array('desc' => 'Organizations', 'href' => 'orgs.php', 'iconclass' => 'departments'); + break; case 'kbase': $subnav[]=array('desc'=>'FAQs','href'=>'kb.php', 'urls'=>array('faq.php'), 'iconclass'=>'kb'); if($staff) { diff --git a/include/staff/user-view.inc.php b/include/staff/user-view.inc.php new file mode 100644 index 0000000000000000000000000000000000000000..1ef2de2dc6e4078ac8ff9c79dca8b6c7d9085d42 --- /dev/null +++ b/include/staff/user-view.inc.php @@ -0,0 +1,263 @@ +<?php +if(!defined('OSTSCPINC') || !$thisstaff || !is_object($user)) die('Invalid path'); + +?> +<table width="940" cellpadding="2" cellspacing="0" border="0"> + <tr> + <td width="50%" class="has_bottom_border"> + <h2><a href="users.php?id=<?php echo $user->getId(); ?>" + title="Reload"><i class="icon-refresh"></i> <?php echo $user->getName(); ?></a></h2> + </td> + <td width="50%" class="right_align has_bottom_border"> + <span class="action-button" data-dropdown="#action-dropdown-more"> + <span ><i class="icon-cog"></i> More</span> + <i class="icon-caret-down"></i> + </span> + <a id="user-delete" class="action-button user-action" + href="#users/<?php echo $user->getId(); ?>/delete"><i class="icon-trash"></i> Delete User</a> + <?php + if ($user->getAccount()) { ?> + <a id="user-manage" class="action-button user-action" + href="#users/<?php echo $user->getId(); ?>/manage"><i class="icon-edit"></i> Manage Account</a> + <?php + } else { ?> + <a id="user-register" class="action-button user-action" + href="#users/<?php echo $user->getId(); ?>/register"><i class="icon-edit"></i> Register</a> + <?php + } ?> + <div id="action-dropdown-more" class="action-dropdown anchor-right"> + <ul> + <li><a class="user-action" + href="#users/<?php echo $user->getId(); ?>/manage/access"><i + class="icon-lock"></i> Manage Account Access</a></li> + <li><a class="user-action" + href="#users/<?php echo $user->getId(); ?>/manage/access"><i + class="icon-lock"></i> Change Account Password</a></li> + </ul> + </div> + </td> + </tr> +</table> +<table class="ticket_info" cellspacing="0" cellpadding="0" width="940" border="0"> + <tr> + <td width="50"> + <table border="0" cellspacing="" cellpadding="4" width="100%"> + <tr> + <th width="100">Name:</th> + <td><b><a href="#users/<?php echo $user->getId(); + ?>/edit" class="user-action"><i + class="icon-edit"></i> <?php echo + $user->getName()->getOriginal(); + ?></a></td> + </tr> + <tr> + <th>Email:</th> + <td> + <span id="user-<?php echo $user->getId(); ?>-email"><?php echo $user->getEmail(); ?></span> + </td> + </tr> + <tr> + <th>Company:</th> + <td> + <span id="user-<?php echo $user->getId(); + ?>-org"><?php echo $user->getOrg(); ?></span> + </td> + </tr> + </table> + </td> + <td width="50%" style="vertical-align:top"> + <table border="0" cellspacing="" cellpadding="4" width="100%"> + <tr> + <th>Status:</th> + <td> <span id="user-<?php echo $user->getId(); + ?>-status"><?php echo $user->getAccountStatus(); ?></span></td> + </tr> + <tr> + <th>Created:</th> + <td><?php echo Format::db_datetime($user->getCreateDate()); ?></td> + </tr> + <tr> + <th>Updated:</th> + <td><?php echo Format::db_datetime($user->getUpdateDate()); ?></td> + </tr> + </table> + </td> + </tr> +</table> +<br> +<div class="clear"></div> +<ul class="tabs"> + <li><a class="active" id="tickets_tab" href="#tickets"><i + class="icon-list-alt"></i> User Tickets</a></li> +</ul> +<div id="tickets"> +<?php +//List all tickets the user + +$select ='SELECT ticket.ticket_id,ticket.`number`,ticket.dept_id,ticket.staff_id,ticket.team_id ' + .' ,dept.dept_name,ticket.status,ticket.source,ticket.isoverdue,ticket.isanswered,ticket.created ' + .' ,CAST(GREATEST(IFNULL(ticket.lastmessage, 0), IFNULL(ticket.reopened, 0), ticket.created) as datetime) as effective_date ' + .' ,CONCAT_WS(" ", staff.firstname, staff.lastname) as staff, team.name as team ' + .' ,IF(staff.staff_id IS NULL,team.name,CONCAT_WS(" ", staff.lastname, staff.firstname)) as assigned ' + .' ,IF(ptopic.topic_pid IS NULL, topic.topic, CONCAT_WS(" / ", ptopic.topic, topic.topic)) as helptopic ' + .' ,cdata.priority_id, cdata.subject, pri.priority_desc, pri.priority_color'; + +$from =' FROM '.TICKET_TABLE.' ticket ' + .' LEFT JOIN '.DEPT_TABLE.' dept ON ticket.dept_id=dept.dept_id ' + .' LEFT JOIN '.STAFF_TABLE.' staff ON (ticket.staff_id=staff.staff_id) ' + .' LEFT JOIN '.TEAM_TABLE.' team ON (ticket.team_id=team.team_id) ' + .' LEFT JOIN '.TOPIC_TABLE.' topic ON (ticket.topic_id=topic.topic_id) ' + .' LEFT JOIN '.TOPIC_TABLE.' ptopic ON (ptopic.topic_id=topic.topic_pid) ' + .' LEFT JOIN '.TABLE_PREFIX.'ticket__cdata cdata ON (cdata.ticket_id = ticket.ticket_id) ' + .' LEFT JOIN '.PRIORITY_TABLE.' pri ON (pri.priority_id = cdata.priority_id)'; + +$where = 'WHERE ticket.user_id = '.db_input($user->getId()); + +TicketForm::ensureDynamicDataView(); + +$query ="$select $from $where ORDER BY ticket.created DESC"; + +// Fetch the results +$results = array(); +$res = db_query($query); +while ($row = db_fetch_array($res)) + $results[$row['ticket_id']] = $row; + +if ($results) { + $counts_sql = 'SELECT ticket.ticket_id, + count(DISTINCT attach.attach_id) as attachments, + count(DISTINCT thread.id) as thread_count, + count(DISTINCT collab.id) as collaborators + FROM '.TICKET_TABLE.' ticket + LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach ON (ticket.ticket_id=attach.ticket_id) ' + .' LEFT JOIN '.TICKET_THREAD_TABLE.' thread ON ( ticket.ticket_id=thread.ticket_id) ' + .' LEFT JOIN '.TICKET_COLLABORATOR_TABLE.' collab + ON ( ticket.ticket_id=collab.ticket_id) ' + .' WHERE ticket.ticket_id IN ('.implode(',', db_input(array_keys($results))).') + GROUP BY ticket.ticket_id'; + $ids_res = db_query($counts_sql); + while ($row = db_fetch_array($ids_res)) { + $results[$row['ticket_id']] += $row; + } +} +?> +<div style="width:700px; float:left;"> + <?php + if ($results) { + echo sprintf('<strong>Showing 1 - %d of %s</strong>', + count($results), count($results)); + } else { + echo sprintf('%s does not have any tickets', $user->getName()); + } + ?> +</div> +<div style="float:right;text-align:right;padding-right:5px;"> + <b><a class="Icon newTicket" href="tickets.php?a=open&uid=<?php echo $user->getId(); ?>"> Create New Ticket</a></b> +</div> +<br/> +<?php +if ($results) { ?> +<form action="users.php" method="POST" name='tickets' style="padding-top:10px;"> +<?php csrf_token(); ?> + <input type="hidden" name="a" value="mass_process" > + <input type="hidden" name="do" id="action" value="" > + <table class="list" border="0" cellspacing="1" cellpadding="2" width="940"> + <thead> + <tr> + <?php + if (0) {?> + <th width="8px"> </th> + <?php + } ?> + <th width="70">Ticket</th> + <th width="100">Date</th> + <th width="100">Status</th> + <th width="250">Subject</th> + <th width="100">Priority</th> + <th width="250">Department</th> + <th width="200">Assignee</th> + </tr> + </thead> + <tbody> + <?php + foreach($results as $row) { + $flag=null; + if ($row['lock_id']) + $flag='locked'; + elseif ($row['isoverdue']) + $flag='overdue'; + + $assigned=''; + if ($row['staff_id']) + $assigned=sprintf('<span class="Icon staffAssigned">%s</span>',Format::truncate($row['staff'],40)); + elseif ($row['team_id']) + $assigned=sprintf('<span class="Icon teamAssigned">%s</span>',Format::truncate($row['team'],40)); + else + $assigned=' '; + + $status = ucfirst($row['status']); + if(!strcasecmp($row['status'], 'open')) + $status = "<b>$status</b>"; + + $tid=$row['number']; + $subject = Format::htmlchars(Format::truncate($row['subject'],40)); + $threadcount=$row['thread_count']; + ?> + <tr id="<?php echo $row['ticket_id']; ?>"> + <?php + //Implement mass action....if need be. + if (0) { ?> + <td align="center" class="nohover"> + <input class="ckb" type="checkbox" name="tids[]" value="<?php echo $row['ticket_id']; ?>" <?php echo $sel?'checked="checked"':''; ?>> + </td> + <?php + } ?> + <td align="center" nowrap> + <a class="Icon <?php echo strtolower($row['source']); ?>Ticket ticketPreview" title="Preview Ticket" + href="tickets.php?id=<?php echo $row['ticket_id']; ?>"><?php echo $tid; ?></a></td> + <td align="center" nowrap><?php echo Format::db_datetime($row['effective_date']); ?></td> + <td><?php echo $status; ?></td> + <td><a <?php if ($flag) { ?> class="Icon <?php echo $flag; ?>Ticket" title="<?php echo ucfirst($flag); ?> Ticket" <?php } ?> + href="tickets.php?id=<?php echo $row['ticket_id']; ?>"><?php echo $subject; ?></a> + <?php + if ($threadcount>1) + echo "<small>($threadcount)</small> ".'<i + class="icon-fixed-width icon-comments-alt"></i> '; + if ($row['collaborators']) + echo '<i class="icon-fixed-width icon-group faded"></i> '; + if ($row['attachments']) + echo '<i class="icon-fixed-width icon-paperclip"></i> '; + ?> + </td> + <td class="nohover" align="center" style="background-color:<?php echo $row['priority_color']; ?>;"> + <?php echo $row['priority_desc']; ?></td> + <td><?php echo Format::truncate($row['dept_name'], 40); ?></td> + <td> <?php echo $assigned; ?></td> + </tr> + <?php + } + ?> + </tbody> +</table> +</form> +<?php + } ?> +</div> + +<script type="text/javascript"> +$(function() { + $(document).on('click', 'a.user-action', function(e) { + e.preventDefault(); + var url = 'ajax.php/'+$(this).attr('href').substr(1); + $.dialog(url, [201, 204], function (xhr) { + if (xhr.status == 204) + window.location.href = 'users.php'; + else + window.location.href = window.location.href; + }, { + onshow: function() { $('#user-search').focus(); } + }); + return false; + }); +}); +</script> diff --git a/include/staff/users.inc.php b/include/staff/users.inc.php new file mode 100644 index 0000000000000000000000000000000000000000..dab7d730527eddcc74afb20865285af5d154a3a9 --- /dev/null +++ b/include/staff/users.inc.php @@ -0,0 +1,181 @@ +<?php +if(!defined('OSTSCPINC') || !$thisstaff) die('Access Denied'); + +$qstr=''; + +$select = 'SELECT user.*, email.address as email '; + +$from = 'FROM '.USER_TABLE.' user ' + . 'JOIN '.USER_EMAIL_TABLE.' email ON (user.id = email.user_id) '; + +$where='WHERE 1 '; + + +if ($_REQUEST['query']) { + + $from .=' LEFT JOIN '.FORM_ENTRY_TABLE.' entry + ON (entry.object_type=\'U\' AND entry.object_id = user.id) + LEFT JOIN '.FORM_ANSWER_TABLE.' value + ON (value.entry_id=entry.id) '; + + $search = db_input(strtolower($_REQUEST['query']), false); + $where .= ' AND ( + email.address LIKE \'%'.$search.'%\' + OR user.name LIKE \'%'.$search.'%\' + OR value.value LIKE \'%'.$search.'%\' + )'; + + $qstr.='&query='.urlencode($_REQUEST['query']); +} + +$sortOptions = array('name' => 'user.name', + 'email' => 'email.address', + 'create' => 'user.created', + 'update' => 'user.updated'); +$orderWays = array('DESC'=>'DESC','ASC'=>'ASC'); +$sort= ($_REQUEST['sort'] && $sortOptions[strtolower($_REQUEST['sort'])]) ? strtolower($_REQUEST['sort']) : 'name'; +//Sorting options... +if ($sort && $sortOptions[$sort]) + $order_column =$sortOptions[$sort]; + +$order_column = $order_column ?: 'user.name'; + +if ($_REQUEST['order'] && $orderWays[strtoupper($_REQUEST['order'])]) + $order = $orderWays[strtoupper($_REQUEST['order'])]; + +$order=$order ?: 'ASC'; +if ($order_column && strpos($order_column,',')) + $order_column = str_replace(','," $order,",$order_column); + +$x=$sort.'_sort'; +$$x=' class="'.strtolower($order).'" '; +$order_by="$order_column $order "; + +$total=db_count('SELECT count(DISTINCT user.id) '.$from.' '.$where); +$page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; +$pageNav=new Pagenate($total,$page,PAGE_LIMIT); +$pageNav->setURL('users.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); +//Ok..lets roll...create the actual query +$qstr.='&order='.($order=='DESC'?'ASC':'DESC'); + +$select .= ', count(DISTINCT ticket.ticket_id) as tickets '; + +$from .= ' LEFT JOIN '.TICKET_TABLE.' ticket ON (ticket.user_id = user.id) '; + + +$query="$select $from $where GROUP BY user.id ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit(); +//echo $query; +?> +<h2>User Directory</h2> +<div style="width:700px; float:left;"> + <form action="users.php" method="get"> + <?php csrf_token(); ?> + <input type="hidden" name="a" value="search"> + <table> + <tr> + <td><input type="text" id="basic-user-search" name="query" size=30 value="<?php echo Format::htmlchars($_REQUEST['query']); ?>" + autocomplete="off" autocorrect="off" autocapitalize="off"></td> + <td><input type="submit" name="basic_search" class="button" value="Search"></td> + <!-- <td> <a href="" id="advanced-user-search">[advanced]</a></td> --> + </tr> + </table> + </form> + </div> + <div style="float:right;text-align:right;padding-right:5px;"> + <b><a href="#users/add" class="Icon newstaff add-user">Add New User</a></b></div> +<div class="clear"></div> +<?php +$showing = $search ? 'Search Results: ' : ''; +$res = db_query($query); +if($res && ($num=db_num_rows($res))) + $showing .= $pageNav->showing(); +else + $showing .= 'No users found!'; +?> +<form action="users.php" method="POST" name="staff" > + <?php csrf_token(); ?> + <input type="hidden" name="do" value="mass_process" > + <input type="hidden" id="action" name="a" value="" > + <table class="list" border="0" cellspacing="1" cellpadding="0" width="940"> + <caption><?php echo $showing; ?></caption> + <thead> + <tr> + <th width="300"><a <?php echo $name_sort; ?> href="users.php?<?php echo $qstr; ?>&sort=name">Name</a></th> + <th width="300"><a <?php echo $email_sort; ?> href="users.php?<?php echo $qstr; ?>&sort=email">Email</a></th> + <th width="100"><a <?php echo $status_sort; ?> href="users.php?<?php echo $qstr; ?>&sort=status">Status</a></th> + <th width="100"><a <?php echo $create_sort; ?> href="users.php?<?php echo $qstr; ?>&sort=create">Created</a></th> + <th width="145"><a <?php echo $update_sort; ?> href="users.php?<?php echo $qstr; ?>&sort=update">Updated</a></th> + </tr> + </thead> + <tbody> + <?php + if($res && db_num_rows($res)): + $ids=($errors && is_array($_POST['ids']))?$_POST['ids']:null; + while ($row = db_fetch_array($res)) { + + $name = new PersonsName($row['name']); + $status = 'Active'; + $sel=false; + if($ids && in_array($row['id'], $ids)) + $sel=true; + ?> + <tr id="<?php echo $row['id']; ?>"> + <td> + <a href="users.php?id=<?php echo $row['id']; ?>"><?php echo $name; ?></a> + + <?php + if ($row['tickets']) + echo sprintf('<i class="icon-fixed-width icon-file-text-alt"></i> + <small>(%d)</small>', $row['tickets']); + ?> + </td> + <td><?php echo $row['email']; ?></td> + <td><?php echo $status; ?></td> + <td><?php echo Format::db_date($row['created']); ?></td> + <td><?php echo Format::db_datetime($row['updated']); ?> </td> + </tr> + <?php + } //end of while. + endif; ?> + <tfoot> + <tr> + <td colspan="5"> </td> + </tr> + </tfoot> +</table> +<?php +if($res && $num): //Show options.. + echo '<div> Page:'.$pageNav->getPageLinks().' </div>'; +endif; +?> +</form> + +<script type="text/javascript"> +$(function() { + $('input#basic-user-search').typeahead({ + source: function (typeahead, query) { + $.ajax({ + url: "ajax.php/users/local?q="+query, + dataType: 'json', + success: function (data) { + typeahead.process(data); + } + }); + }, + onselect: function (obj) { + window.location.href = 'users.php?id='+obj.id; + }, + property: "/bin/true" + }); + + $(document).on('click', 'a.add-user', function(e) { + e.preventDefault(); + $.userLookup('ajax.php/users/add', function (user) { + window.location.href = 'users.php?id='+user.id; + }); + + return false; + }); +}); +</script> + diff --git a/scp/users.php b/scp/users.php new file mode 100644 index 0000000000000000000000000000000000000000..8048682a2dd718553b1f6c8bd0e6c3dec6d08399 --- /dev/null +++ b/scp/users.php @@ -0,0 +1,63 @@ +<?php +/********************************************************************* + users.php + + Peter Rotich <peter@osticket.com> + Jared Hancock <jared@osticket.com> + Copyright (c) 2006-2014 osTicket + http://www.osticket.com + + Released under the GNU General Public License WITHOUT ANY WARRANTY. + See LICENSE.TXT for details. + + vim: expandtab sw=4 ts=4 sts=4: +**********************************************************************/ +require('staff.inc.php'); +$user = null; +if ($_REQUEST['id'] && !($user=User::lookup($_REQUEST['id']))) + $errors['err'] = 'Unknown or invalid user ID.'; + +if ($_POST) { + switch(strtolower($_POST['do'])) { + case 'update': + if (!$user) { + $errors['err']='Unknown or invalid user.'; + } elseif(($acct = $user->getAccount()) + && !$acct->update($_POST, $errors)) { + $errors['err']='Unable to update user account information'; + } elseif($user->updateInfo($_POST, $errors)) { + $msg='User updated successfully'; + $_REQUEST['a'] = null; + } elseif(!$errors['err']) { + $errors['err']='Unable to update user profile. Correct any error(s) below and try again!'; + } + break; + case 'create': + $form = UserForm::getUserForm()->getForm($_POST); + if (($user = User::fromForm($form))) { + $msg = Format::htmlchars($user->getName()).' added successfully'; + $_REQUEST['a'] = null; + } elseif (!$errors['err']) { + $errors['err'] = 'Unable to add user. Correct any error(s) below and try again.'; + } + break; + case 'mass_process': + if (!$_POST['ids'] || !is_array($_POST['ids']) || !count($_POST['ids'])) { + $errors['err'] = 'You must select at least one user member.'; + } else { + $errors['err'] = "Coming soon!"; + } + break; + default: + $errors['err'] = 'Unknown action/command'; + break; + } +} + +$page = $user? 'user-view.inc.php' : 'users.inc.php'; + +$nav->setTabActive('users'); +require(STAFFINC_DIR.'header.inc.php'); +require(STAFFINC_DIR.$page); +include(STAFFINC_DIR.'footer.inc.php'); +?>