Skip to content
Snippets Groups Projects
ajax.tickets.php 24.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • Jared Hancock's avatar
    Jared Hancock committed
    <?php
    /*********************************************************************
        ajax.tickets.php
    
        AJAX interface for tickets
    
        Peter Rotich <peter@osticket.com>
    
        Copyright (c)  2006-2013 osTicket
    
    Jared Hancock's avatar
    Jared Hancock committed
        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:
    **********************************************************************/
    
    if(!defined('INCLUDE_DIR')) die('403');
    
    include_once(INCLUDE_DIR.'class.ticket.php');
    
    require_once(INCLUDE_DIR.'class.ajax.php');
    
    Jared Hancock's avatar
    Jared Hancock committed
    
    class TicketsAjaxAPI extends AjaxController {
    
        function lookup() {
    
            global $thisstaff;
    
            if(!is_numeric($_REQUEST['q']))
    
                return self::lookupByEmail();
    
            $limit = isset($_REQUEST['limit']) ? (int) $_REQUEST['limit']:25;
    
            $tickets=array();
    
            $sql='SELECT DISTINCT ticketID, email.address AS email'
    
    Jared Hancock's avatar
    Jared Hancock committed
                .' FROM '.TICKET_TABLE.' ticket'
    
                .' LEFT JOIN '.USER_TABLE.' user ON user.id = ticket.user_id'
                .' LEFT JOIN '.USER_EMAIL_TABLE.' email ON user.id = email.user_id'
                .' WHERE ticketID LIKE \''.db_input($_REQUEST['q'], false).'%\'';
    
            $sql.=' AND ( staff_id='.db_input($thisstaff->getId());
    
            if(($teams=$thisstaff->getTeams()) && count(array_filter($teams)))
    
    Peter Rotich's avatar
    Peter Rotich committed
                $sql.=' OR team_id IN('.implode(',', db_input(array_filter($teams))).')';
    
            if(!$thisstaff->showAssignedOnly() && ($depts=$thisstaff->getDepts()))
    
    Peter Rotich's avatar
    Peter Rotich committed
                $sql.=' OR dept_id IN ('.implode(',', db_input($depts)).')';
    
    Jared Hancock's avatar
    Jared Hancock committed
                .' ORDER BY ticket.created LIMIT '.$limit;
    
    
            if(($res=db_query($sql)) && db_num_rows($res)) {
    
                while(list($id, $email)=db_fetch_row($res)) {
                    $info = "$id - $email";
                    $tickets[] = array('id'=>$id, 'email'=>$email, 'value'=>$id,
                        'info'=>$info, 'matches'=>$_REQUEST['q']);
                }
    
            if (!$tickets)
                return self::lookupByEmail();
    
            return $this->json_encode($tickets);
        }
    
    
        function lookupByEmail() {
    
            global $thisstaff;
    
    
    
            $limit = isset($_REQUEST['limit']) ? (int) $_REQUEST['limit']:25;
            $tickets=array();
    
    
            $sql='SELECT email.address AS email, count(ticket.ticket_id) as tickets '
    
    Jared Hancock's avatar
    Jared Hancock committed
                .' FROM '.TICKET_TABLE.' ticket'
    
                .' JOIN '.USER_TABLE.' user ON user.id = ticket.user_id'
                .' JOIN '.USER_EMAIL_TABLE.' email ON user.id = email.user_id'
    
                .' LEFT JOIN '.FORM_ENTRY_TABLE.' entry ON (entry.object_id = user.id
                    AND entry.object_type=\'U\')
                   LEFT JOIN '.FORM_ANSWER_TABLE.' data ON (data.entry_id = entry.id)'
                .' WHERE (email.address LIKE \'%'.db_input(strtolower($_REQUEST['q']), false).'%\'
                    OR data.value LIKE \'%'.db_input($_REQUEST['q'], false).'%\')';
    
            $sql.=' AND ( staff_id='.db_input($thisstaff->getId());
    
            if(($teams=$thisstaff->getTeams()) && count(array_filter($teams)))
    
    Peter Rotich's avatar
    Peter Rotich committed
                $sql.=' OR team_id IN('.implode(',', db_input(array_filter($teams))).')';
    
    
            if(!$thisstaff->showAssignedOnly() && ($depts=$thisstaff->getDepts()))
    
    Peter Rotich's avatar
    Peter Rotich committed
                $sql.=' OR dept_id IN ('.implode(',', db_input($depts)).')';
    
                .' GROUP BY email.address '
    
    Jared Hancock's avatar
    Jared Hancock committed
                .' ORDER BY ticket.created  LIMIT '.$limit;
    
    Peter Rotich's avatar
    Peter Rotich committed
            if(($res=db_query($sql)) && db_num_rows($res)) {
    
                while(list($email, $count)=db_fetch_row($res))
    
                    $tickets[] = array('email'=>$email, 'value'=>$email,
                        'info'=>"$email ($count)", 'matches'=>$_REQUEST['q']);
    
            return $this->json_encode($tickets);
    
        function _search($req) {
    
            $result=array();
    
            $select = 'SELECT DISTINCT ticket.ticket_id';
    
    Peter Rotich's avatar
    Peter Rotich committed
            $from = ' FROM '.TICKET_TABLE.' ticket ';
            $where = ' WHERE 1 ';
    
    
            //Access control.
    
    Peter Rotich's avatar
    Peter Rotich committed
            $where.=' AND ( ticket.staff_id='.db_input($thisstaff->getId());
    
    
            if(($teams=$thisstaff->getTeams()) && count(array_filter($teams)))
    
    Peter Rotich's avatar
    Peter Rotich committed
                $where.=' OR ticket.team_id IN('.implode(',', db_input(array_filter($teams))).')';
    
    
            if(!$thisstaff->showAssignedOnly() && ($depts=$thisstaff->getDepts()))
    
    Peter Rotich's avatar
    Peter Rotich committed
                $where.=' OR ticket.dept_id IN ('.implode(',', db_input($depts)).')';
    
    Peter Rotich's avatar
    Peter Rotich committed
            $where.=' ) ';
    
    
            //Department
    
            if($req['deptId'])
                $where.=' AND ticket.dept_id='.db_input($req['deptId']);
    
            if($req['topicId'])
                $where.=' AND ticket.topic_id='.db_input($req['topicId']);
    
            //Status
    
            switch(strtolower($req['status'])) {
    
    Peter Rotich's avatar
    Peter Rotich committed
                    $where.=' AND ticket.status="open" ';
    
                case 'answered':
                    $where.=' AND ticket.status="open" AND ticket.isanswered=1 ';
                    break;
    
                case 'overdue':
    
    Peter Rotich's avatar
    Peter Rotich committed
                    $where.=' AND ticket.status="open" AND ticket.isoverdue=1 ';
    
                    break;
                case 'closed':
    
    Peter Rotich's avatar
    Peter Rotich committed
                    $where.=' AND ticket.status="closed" ';
    
            if(isset($req['assignee']) && strcasecmp($req['status'], 'closed'))  {
                $id=preg_replace("/[^0-9]/", "", $req['assignee']);
                $assignee = $req['assignee'];
    
                $where.= ' AND ( ( ticket.status="open" ';
    
    Peter Rotich's avatar
    Peter Rotich committed
                if($assignee[0]=='t')
    
                    $where.=' AND ticket.team_id='.db_input($id);
    
    Peter Rotich's avatar
    Peter Rotich committed
                elseif($assignee[0]=='s')
    
                    $where.=' AND ticket.staff_id='.db_input($id);
                elseif(is_numeric($id))
                    $where.=' AND ticket.staff_id='.db_input($id);
    
                $where.=')';
    
                if($req['staffId'] && !$req['status']) //Assigned TO + Closed By
                    $where.= ' OR (ticket.staff_id='.db_input($req['staffId']). ' AND ticket.status="closed") ';
                elseif(isset($req['staffId'])) // closed by any
    
    Peter Rotich's avatar
    Peter Rotich committed
    
                $where.= ' ) ';
    
            } elseif($req['staffId']) {
                $where.=' AND (ticket.staff_id='.db_input($req['staffId']).' AND ticket.status="closed") ';
    
    Peter Rotich's avatar
    Peter Rotich committed
            //dates
    
            $startTime  =($req['startDate'] && (strlen($req['startDate'])>=8))?strtotime($req['startDate']):0;
            $endTime    =($req['endDate'] && (strlen($req['endDate'])>=8))?strtotime($req['endDate']):0;
    
    Peter Rotich's avatar
    Peter Rotich committed
            if( ($startTime && $startTime>time()) or ($startTime>$endTime && $endTime>0))
                $startTime=$endTime=0;
    
    Peter Rotich's avatar
    Peter Rotich committed
            if($startTime)
    
    Peter Rotich's avatar
    Peter Rotich committed
                $where.=' AND ticket.created>=FROM_UNIXTIME('.$startTime.')';
    
    Peter Rotich's avatar
    Peter Rotich committed
    
            if($endTime)
    
    Peter Rotich's avatar
    Peter Rotich committed
                $where.=' AND ticket.created<=FROM_UNIXTIME('.$endTime.')';
    
            if($req['query']) {
                $queryterm=db_real_escape($req['query'], false);
    
                $from.=' LEFT JOIN '.TICKET_THREAD_TABLE.' thread ON (ticket.ticket_id=thread.ticket_id )'
                    .' LEFT JOIN '.FORM_ENTRY_TABLE.' tentry ON (tentry.object_id = ticket.ticket_id
                       AND tentry.object_type="T")
                       LEFT JOIN '.FORM_ANSWER_TABLE.' tans ON (tans.entry_id = tentry.id
                       AND tans.value_id IS NULL)
                       LEFT JOIN '.FORM_ENTRY_TABLE.' uentry ON (uentry.object_id = ticket.user_id
                       AND uentry.object_type="U")
                       LEFT JOIN '.FORM_ANSWER_TABLE.' uans ON (uans.entry_id = uentry.id
                       AND uans.value_id IS NULL)
                       LEFT JOIN '.USER_TABLE.' user ON (ticket.user_id = user.id)
                       LEFT JOIN '.USER_EMAIL_TABLE.' uemail ON (user.id = uemail.user_id)';
    
                $where.=" AND (  uemail.address LIKE '%$queryterm%'"
                           ." OR user.name LIKE '%$queryterm%'"
                           ." OR tans.value LIKE '%$queryterm%'"
                           ." OR uans.value LIKE '%$queryterm%'"
    
    Peter Rotich's avatar
    Peter Rotich committed
                           ." OR thread.title LIKE '%$queryterm%'"
    
                           ." OR thread.body LIKE '%$queryterm%'"
    
    Peter Rotich's avatar
    Peter Rotich committed
                           .' )';
            }
    
            // Dynamic fields
    
            $dynfields='(SELECT entry.object_id, %s '.
                 'FROM '.FORM_ANSWER_TABLE.' ans '.
                 'JOIN '.FORM_ENTRY_TABLE.' entry ON entry.id=ans.entry_id '.
                 'JOIN '.FORM_FIELD_TABLE.' field ON field.id=ans.field_id '.
                 'WHERE entry.object_type="T" GROUP BY entry.object_id)';
            $vals = array();
    
            foreach (TicketForm::getInstance()->getFields() as $f) {
    
                if (isset($req[$f->getFormName()])
    
                        && ($val = $req[$f->getFormName()])) {
    
                    $id = $f->get('id');
                    $vals[] = "MAX(IF(field.id = '$id', ans.value_id, NULL)) as `f_{$id}_id`";
                    $vals[] = "MAX(IF(field.id = '$id', ans.value, NULL)) as `f_$id`";
                    $where .= " AND (dyn.`f_{$id}_id` = ".db_input($val)
                        . " OR dyn.`f_$id` LIKE '%".db_real_escape($val)."%')";
    
            if ($vals)
                $from .= ' LEFT JOIN '.sprintf($dynfields, implode(',', $vals))
                    ." dyn ON (dyn.object_id = ticket.ticket_id)";
    
            $sql="$select $from $where";
    
            $res = db_query($sql);
    
            while (list($tickets[]) = db_fetch_row($res));
            $tickets = array_filter($tickets);
    
            return $tickets;
        }
    
        function search() {
            $tickets = self::_search($_REQUEST);
    
            $result = array();
    
    
            if (count($tickets)) {
                $uid = md5($_SERVER['QUERY_STRING']);
                $_SESSION["adv_$uid"] = $tickets;
                $result['success'] =sprintf(
                    "Search criteria matched %d %s - <a href='tickets.php?%s'>view</a>",
                    count($tickets), (count($tickets)>1?"tickets":"ticket"),
                    'advsid='.$uid
                );
    
            } else {
    
    Peter Rotich's avatar
    Peter Rotich committed
                $result['fail']='No tickets found matching your search criteria.';
    
            return $this->json_encode($result);
        }
    
    
    Jared Hancock's avatar
    Jared Hancock committed
        function acquireLock($tid) {
            global $cfg,$thisstaff;
    
            if(!$tid or !is_numeric($tid) or !$thisstaff or !$cfg or !$cfg->getLockTime())
    
    Jared Hancock's avatar
    Jared Hancock committed
                return 0;
    
            if(!($ticket = Ticket::lookup($tid)) || !$ticket->checkStaffAccess($thisstaff))
    
    Jared Hancock's avatar
    Jared Hancock committed
                return $this->json_encode(array('id'=>0, 'retry'=>false, 'msg'=>'Lock denied!'));
    
    Jared Hancock's avatar
    Jared Hancock committed
            //is the ticket already locked?
            if($ticket->isLocked() && ($lock=$ticket->getLock()) && !$lock->isExpired()) {
                /*Note: Ticket->acquireLock does the same logic...but we need it here since we need to know who owns the lock up front*/
                //Ticket is locked by someone else.??
                if($lock->getStaffId()!=$thisstaff->getId())
                    return $this->json_encode(array('id'=>0, 'retry'=>false, 'msg'=>'Unable to acquire lock.'));
    
    Jared Hancock's avatar
    Jared Hancock committed
                //Ticket already locked by staff...try renewing it.
                $lock->renew(); //New clock baby!
    
            } elseif(!($lock=$ticket->acquireLock($thisstaff->getId(),$cfg->getLockTime()))) {
                //unable to obtain the lock..for some really weired reason!
                //Client should watch for possible loop on retries. Max attempts?
                return $this->json_encode(array('id'=>0, 'retry'=>true));
    
    
            return $this->json_encode(array('id'=>$lock->getId(), 'time'=>$lock->getTime()));
    
    Jared Hancock's avatar
    Jared Hancock committed
        }
    
        function renewLock($tid, $id) {
            global $thisstaff;
    
            if(!$id or !is_numeric($id) or !$thisstaff)
                return $this->json_encode(array('id'=>0, 'retry'=>true));
    
    Jared Hancock's avatar
    Jared Hancock committed
            $lock= TicketLock::lookup($id);
            if(!$lock || !$lock->getStaffId() || $lock->isExpired()) //Said lock doesn't exist or is is expired
                return self::acquireLock($tid); //acquire the lock
    
    Jared Hancock's avatar
    Jared Hancock committed
            if($lock->getStaffId()!=$thisstaff->getId()) //user doesn't own the lock anymore??? sorry...try to next time.
                return $this->json_encode(array('id'=>0, 'retry'=>false)); //Give up...
    
    Jared Hancock's avatar
    Jared Hancock committed
            //Renew the lock.
            $lock->renew(); //Failure here is not an issue since the lock is not expired yet.. client need to check time!
    
    Jared Hancock's avatar
    Jared Hancock committed
            return $this->json_encode(array('id'=>$lock->getId(), 'time'=>$lock->getTime()));
        }
    
        function releaseLock($tid, $id=0) {
            global $thisstaff;
    
            if($id && is_numeric($id)){ //Lock Id provided!
    
    Jared Hancock's avatar
    Jared Hancock committed
                $lock = TicketLock::lookup($id, $tid);
                //Already gone?
                if(!$lock || !$lock->getStaffId() || $lock->isExpired()) //Said lock doesn't exist or is is expired
                    return 1;
    
    Jared Hancock's avatar
    Jared Hancock committed
                //make sure the user actually owns the lock before releasing it.
                return ($lock->getStaffId()==$thisstaff->getId() && $lock->release())?1:0;
    
            }elseif($tid){ //release all the locks the user owns on the ticket.
                return TicketLock::removeStaffLocks($thisstaff->getId(),$tid)?1:0;
            }
    
            return 0;
        }
    
        function previewTicket ($tid) {
    
            global $thisstaff;
    
    
    Peter Rotich's avatar
    Peter Rotich committed
            if(!$thisstaff || !($ticket=Ticket::lookup($tid)) || !$ticket->checkStaffAccess($thisstaff))
                Http::response(404, 'No such ticket');
    
    Peter Rotich's avatar
    Peter Rotich committed
            $staff=$ticket->getStaff();
            $lock=$ticket->getLock();
            $error=$msg=$warn=null;
    
    Peter Rotich's avatar
    Peter Rotich committed
            if($lock && $lock->getStaffId()==$thisstaff->getId())
                $warn.='&nbsp;<span class="Icon lockedTicket">Ticket is locked by '.$lock->getStaffName().'</span>';
            elseif($ticket->isOverdue())
                $warn.='&nbsp;<span class="Icon overdueTicket">Marked overdue!</span>';
    
    Peter Rotich's avatar
    Peter Rotich committed
            ob_start();
            echo sprintf(
                    '<div style="width:500px; padding: 2px 2px 0 5px;">
                     <h2>%s</h2><br>',Format::htmlchars($ticket->getSubject()));
    
            if($error)
                echo sprintf('<div id="msg_error">%s</div>',$error);
            elseif($msg)
                echo sprintf('<div id="msg_notice">%s</div>',$msg);
            elseif($warn)
                echo sprintf('<div id="msg_warning">%s</div>',$warn);
    
            echo '<table border="0" cellspacing="" cellpadding="1" width="100%" class="ticket_info">';
    
            $ticket_state=sprintf('<span>%s</span>',ucfirst($ticket->getStatus()));
            if($ticket->isOpen()) {
                if($ticket->isOverdue())
                    $ticket_state.=' &mdash; <span>Overdue</span>';
                else
                    $ticket_state.=sprintf(' &mdash; <span>%s</span>',$ticket->getPriority());
            }
    
            echo sprintf('
                    <tr>
                        <th width="100">Ticket State:</th>
                        <td>%s</td>
                    </tr>
                    <tr>
                        <th>Create Date:</th>
                        <td>%s</td>
                    </tr>',$ticket_state,
                    Format::db_datetime($ticket->getCreateDate()));
            if($ticket->isClosed()) {
                echo sprintf('
                        <tr>
                            <th>Close Date:</th>
                            <td>%s   <span class="faded">by %s</span></td>
                        </tr>',
                        Format::db_datetime($ticket->getCloseDate()),
                        ($staff?$staff->getName():'staff')
                        );
    
            } elseif($ticket->getEstDueDate()) {
    
    Peter Rotich's avatar
    Peter Rotich committed
                echo sprintf('
                        <tr>
                            <th>Due Date:</th>
                            <td>%s</td>
                        </tr>',
    
                        Format::db_datetime($ticket->getEstDueDate()));
    
    Peter Rotich's avatar
    Peter Rotich committed
            }
            echo '</table>';
    
    Peter Rotich's avatar
    Peter Rotich committed
    
            echo '<hr>
                <table border="0" cellspacing="" cellpadding="1" width="100%" class="ticket_info">';
            if($ticket->isOpen()) {
                echo sprintf('
                        <tr>
                            <th width="100">Assigned To:</th>
                            <td>%s</td>
    
                        </tr>',$ticket->isAssigned()?implode('/', $ticket->getAssignees()):' <span class="faded">&mdash; Unassigned &mdash;</span>');
    
    Peter Rotich's avatar
    Peter Rotich committed
            }
            echo sprintf(
                '   <tr>
                        <th width="100">Department:</th>
                        <td>%s</td>
                    </tr>
                    <tr>
                        <th>Help Topic:</th>
                        <td>%s</td>
                    </tr>
                    <tr>
                        <th>From:</th>
                        <td>%s <span class="faded">%s</span></td>
                    </tr>',
                Format::htmlchars($ticket->getDeptName()),
                Format::htmlchars($ticket->getHelpTopic()),
                Format::htmlchars($ticket->getName()),
                $ticket->getEmail());
            echo '
                </table>';
    
    Jared Hancock's avatar
    Jared Hancock committed
            $options[]=array('action'=>'Thread ('.$ticket->getThreadCount().')','url'=>"tickets.php?id=$tid");
            if($ticket->getNumNotes())
                $options[]=array('action'=>'Notes ('.$ticket->getNumNotes().')','url'=>"tickets.php?id=$tid#notes");
    
    Jared Hancock's avatar
    Jared Hancock committed
            if($ticket->isOpen())
                $options[]=array('action'=>'Reply','url'=>"tickets.php?id=$tid#reply");
    
            if($thisstaff->canAssignTickets())
                $options[]=array('action'=>($ticket->isAssigned()?'Reassign':'Assign'),'url'=>"tickets.php?id=$tid#assign");
    
            if($thisstaff->canTransferTickets())
                $options[]=array('action'=>'Transfer','url'=>"tickets.php?id=$tid#transfer");
    
            $options[]=array('action'=>'Post Note','url'=>"tickets.php?id=$tid#note");
    
    
    Peter Rotich's avatar
    Peter Rotich committed
            if($thisstaff->canEditTickets())
                $options[]=array('action'=>'Edit Ticket','url'=>"tickets.php?id=$tid&a=edit");
    
    
    Jared Hancock's avatar
    Jared Hancock committed
            if($options) {
    
    Peter Rotich's avatar
    Peter Rotich committed
                echo '<ul class="tip_menu">';
                foreach($options as $option)
                    echo sprintf('<li><a href="%s">%s</a></li>',$option['url'],$option['action']);
                echo '</ul>';
    
    Peter Rotich's avatar
    Peter Rotich committed
            echo '</div>';
            $resp = ob_get_contents();
            ob_end_clean();
    
    Jared Hancock's avatar
    Jared Hancock committed
    
            return $resp;
        }
    
        function addRemoteCollaborator($tid, $bk, $id) {
            global $thisstaff;
    
            if (!($ticket=Ticket::lookup($tid))
                    || !$ticket->checkStaffAccess($thisstaff))
                Http::response(404, 'No such ticket');
            elseif (!$bk || !$id)
                Http::response(422, 'Backend and user id required');
            elseif (!($backend = AuthenticationBackend::getBackend($bk)))
                Http::response(404, 'User not found');
    
            $user_info = $backend->lookup($id);
            $form = UserForm::getUserForm()->getForm($user_info);
            $info = array();
            if (!$user_info)
                $info['error'] = 'Unable to find user in directory';
    
            return self::_addcollaborator($ticket, null, $form, $info);
        }
    
    
        //Collaborators utils
    
        function addCollaborator($tid, $uid=0) {
    
            global $thisstaff;
    
            if (!($ticket=Ticket::lookup($tid))
                    || !$ticket->checkStaffAccess($thisstaff))
                Http::response(404, 'No such ticket');
    
    
    
            $user = $uid? User::lookup($uid) : null;
    
    
    Peter Rotich's avatar
    Peter Rotich committed
            //If not a post then assume new collaborator form
            if(!$_POST)
    
                return self::_addcollaborator($ticket, $user);
    
    Peter Rotich's avatar
    Peter Rotich committed
    
            $user = $form = null;
            if (isset($_POST['id']) && $_POST['id']) { //Existing user/
                $user =  User::lookup($_POST['id']);
            } else { //We're creating a new user!
                $form = UserForm::getUserForm()->getForm($_POST);
                $user = User::fromForm($form);
            }
    
    Peter Rotich's avatar
    Peter Rotich committed
            $errors = $info = array();
    
    Peter Rotich's avatar
    Peter Rotich committed
            if ($user) {
                if ($user->getId() == $ticket->getOwnerId())
                    $errors['err'] = sprintf('Ticket owner, %s, is a collaborator by default!',
                            $user->getName());
                elseif (($c=$ticket->addCollaborator($user, $errors))) {
                    $info = array('msg' => sprintf('%s added as a collaborator',
                                $c->getName()));
                    return self::_collaborators($ticket, $info);
                }
    
    Peter Rotich's avatar
    Peter Rotich committed
            }
    
            if($errors && $errors['err']) {
                $info +=array('error' => $errors['err']);
    
    Peter Rotich's avatar
    Peter Rotich committed
                $info +=array('error' =>'Unable to add collaborator - try again');
    
    Peter Rotich's avatar
    Peter Rotich committed
            return self::_addcollaborator($ticket, $user, $form, $info);
    
        }
    
        function updateCollaborator($cid) {
            global $thisstaff;
    
            if(!($c=Collaborator::lookup($cid))
                    || !($user=$c->getUser())
                    || !($ticket=$c->getTicket())
                    || !$ticket->checkStaffAccess($thisstaff)
                    )
                Http::response(404, 'Unknown collaborator');
    
            $errors = array();
            if(!$user->updateInfo($_POST, $errors))
                return self::_collaborator($c ,$user->getForms($_POST), $errors);
    
            $info = array('msg' => sprintf('%s updated successfully',
                        $c->getName()));
    
    
    Peter Rotich's avatar
    Peter Rotich committed
            return self::_collaborators($ticket, $info);
    
        }
    
        function viewCollaborator($cid) {
            global $thisstaff;
    
            if(!($collaborator=Collaborator::lookup($cid))
                    || !($ticket=$collaborator->getTicket())
                    || !$ticket->checkStaffAccess($thisstaff))
                Http::response(404, 'Unknown collaborator');
    
            return self::_collaborator($collaborator);
        }
    
        function showCollaborators($tid) {
            global $thisstaff;
    
            if(!($ticket=Ticket::lookup($tid))
                    || !$ticket->checkStaffAccess($thisstaff))
                Http::response(404, 'No such ticket');
    
    
    Peter Rotich's avatar
    Peter Rotich committed
            if($ticket->getCollaborators())
                return self::_collaborators($ticket);
    
            return self::_addcollaborator($ticket);
        }
    
    
    
        function _addcollaborator($ticket, $user=null, $form=null, $info=array()) {
    
            $info += array(
                        'title' => sprintf('Ticket #%s: Add a collaborator', $ticket->getNumber()),
    
                        'action' => sprintf('#tickets/%d/add-collaborator', $ticket->getId()),
                        'onselect' => sprintf('ajax.php/tickets/%d/add-collaborator/', $ticket->getId()),
    
    Peter Rotich's avatar
    Peter Rotich committed
                        );
            return self::_userlookup($user, $form, $info);
    
        }
    
    
        function updateCollaborators($tid) {
            global $thisstaff;
    
            if(!($ticket=Ticket::lookup($tid))
                    || !$ticket->checkStaffAccess($thisstaff))
                Http::response(404, 'No such ticket');
    
    
            $errors = $info = array();
            if ($ticket->updateCollaborators($_POST, $errors))
    
                Http::response(201, sprintf('Recipients (%d)', $ticket->getNumActiveCollaborators()));
    
    
            if($errors && $errors['err'])
    
                $info +=array('error' => $errors['err']);
    
    
    Peter Rotich's avatar
    Peter Rotich committed
            return self::_collaborators($ticket, $info);
    
    Peter Rotich's avatar
    Peter Rotich committed
        function _collaborator($collaborator, $form=null, $info=array()) {
    
            $info += array('action' => '#collaborators/'.$collaborator->getId());
    
            $user = $collaborator->getUser();
    
    Peter Rotich's avatar
    Peter Rotich committed
            include(STAFFINC_DIR . 'templates/user.tmpl.php');
    
            $resp = ob_get_contents();
            ob_end_clean();
    
            return $resp;
        }
    
    
    Peter Rotich's avatar
    Peter Rotich committed
        function _collaborators($ticket, $info=array()) {
    
    
            ob_start();
            include(STAFFINC_DIR . 'templates/collaborators.tmpl.php');
            $resp = ob_get_contents();
            ob_end_clean();
    
            return $resp;
        }
    
    Peter Rotich's avatar
    Peter Rotich committed
    
        function viewUser($tid) {
            global $thisstaff;
    
            if(!$thisstaff
                    || !($ticket=Ticket::lookup($tid))
                    || !$ticket->checkStaffAccess($thisstaff))
                Http::response(404, 'No such ticket');
    
    
            if(!($user = $ticket->getOwner()))
                Http::response(404, 'Unknown user');
    
    
            $info = array(
    
                'title' => sprintf('Ticket #%s: %s', $ticket->getNumber(),
                    Format::htmlchars($user->getName()))
                );
    
    Peter Rotich's avatar
    Peter Rotich committed
    
            ob_start();
            include(STAFFINC_DIR . 'templates/user.tmpl.php');
            $resp = ob_get_contents();
            ob_end_clean();
            return $resp;
    
        }
    
        function updateUser($tid) {
    
            global $thisstaff;
    
            if(!$thisstaff
                    || !($ticket=Ticket::lookup($tid))
                    || !$ticket->checkStaffAccess($thisstaff)
                    || ! ($user = $ticket->getOwner()))
                Http::response(404, 'No such ticket/user');
    
            $errors = array();
            if($user->updateInfo($_POST, $errors))
                 Http::response(201, $user->to_json());
    
            $forms = $user->getForms();
    
            $info = array(
    
                'title' => sprintf('Ticket #%s: %s', $ticket->getNumber(),
                    Format::htmlchars($user->getName()))
                );
    
    Peter Rotich's avatar
    Peter Rotich committed
    
            ob_start();
            include(STAFFINC_DIR . 'templates/user.tmpl.php');
            $resp = ob_get_contents();
            ob_end_clean();
            return $resp;
        }
    
        function changeUserForm($tid) {
            global $thisstaff;
    
            if(!$thisstaff
                    || !($ticket=Ticket::lookup($tid))
                    || !$ticket->checkStaffAccess($thisstaff))
                Http::response(404, 'No such ticket');
    
    
            $user = $ticket->getOwner();
    
            $info = array(
                    'title' => sprintf('Change user for ticket #%s', $ticket->getNumber())
                    );
    
            return self::_userlookup($user, $info);
        }
    
        function _userlookup($user, $form, $info) {
    
            ob_start();
            include(STAFFINC_DIR . 'templates/user-lookup.tmpl.php');
            $resp = ob_get_contents();
            ob_end_clean();
            return $resp;
    
        }