Skip to content
Snippets Groups Projects
class.staff.php 26.6 KiB
Newer Older
Jared Hancock's avatar
Jared Hancock committed
<?php
/*********************************************************************
    class.staff.php

    Everything about staff.

    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:
**********************************************************************/
include_once(INCLUDE_DIR.'class.ticket.php');
Jared Hancock's avatar
Jared Hancock committed
include_once(INCLUDE_DIR.'class.dept.php');
include_once(INCLUDE_DIR.'class.error.php');
Jared Hancock's avatar
Jared Hancock committed
include_once(INCLUDE_DIR.'class.team.php');
include_once(INCLUDE_DIR.'class.group.php');
include_once(INCLUDE_DIR.'class.passwd.php');
include_once(INCLUDE_DIR.'class.user.php');
Jared Hancock's avatar
Jared Hancock committed
include_once(INCLUDE_DIR.'class.auth.php');
class Staff extends AuthenticatedUser {
Jared Hancock's avatar
Jared Hancock committed
    var $ht;
    var $id;

    var $dept;
Peter Rotich's avatar
Peter Rotich committed
    var $departments;
    var $group;
Jared Hancock's avatar
Jared Hancock committed
    var $teams;
Jared Hancock's avatar
Jared Hancock committed
    var $stats;
    function Staff($var) {
Jared Hancock's avatar
Jared Hancock committed
        $this->id =0;
        return ($this->load($var));
    }

    function load($var='') {
Jared Hancock's avatar
Jared Hancock committed

        if(!$var && !($var=$this->getId()))
            return false;

        $sql='SELECT staff.created as added, grp.*, staff.* '
            .' FROM '.STAFF_TABLE.' staff '
            .' LEFT JOIN '.GROUP_TABLE.' grp ON(grp.group_id=staff.group_id)
               WHERE ';
        if (is_numeric($var))
            $sql .= 'staff_id='.db_input($var);
        elseif (Validator::is_email($var))
            $sql .= 'email='.db_input($var);
        elseif (is_string($var))
            $sql .= 'username='.db_input($var);
Jared Hancock's avatar
Jared Hancock committed

        if(!($res=db_query($sql)) || !db_num_rows($res))
            return NULL;

Jared Hancock's avatar
Jared Hancock committed
        $this->ht=db_fetch_array($res);
        $this->id  = $this->ht['staff_id'];
Peter Rotich's avatar
Peter Rotich committed
        $this->teams = $this->ht['teams'] = array();
        $this->group = $this->dept = null;
        $this->departments = $this->stats = array();
        $this->config = new Config('staff.'.$this->id);
        //WE have to patch info here to support upgrading from old versions.
        if(($time=strtotime($this->ht['passwdreset']?$this->ht['passwdreset']:$this->ht['added'])))
            $this->ht['passwd_change'] = time()-$time; //XXX: check timezone issues.

        if($this->ht['timezone_id'])
            $this->ht['tz_offset'] = Timezone::getOffsetById($this->ht['timezone_id']);
        elseif($this->ht['timezone_offset'])
            $this->ht['tz_offset'] = $this->ht['timezone_offset'];

Jared Hancock's avatar
Jared Hancock committed
        return ($this->id);
    }

    function reload() {
Jared Hancock's avatar
Jared Hancock committed
        return $this->load();
    }

Peter Rotich's avatar
Peter Rotich committed
    function __toString() {
        return (string) $this->getName();
    }

    function asVar() {
Peter Rotich's avatar
Peter Rotich committed
        return $this->__toString();
    function getHashtable() {
Jared Hancock's avatar
Jared Hancock committed
        return $this->ht;
    }

    function getInfo() {
        return $this->config->getInfo() + $this->getHashtable();
    // AuthenticatedUser implementation...
    // TODO: Move to an abstract class that extends Staff
    function getRole() {
        return 'staff';
    }

    function getAuthBackend() {
        list($authkey, ) = explode(':', $this->getAuthKey());
        return StaffAuthenticationBackend::getBackend($authkey);
Jared Hancock's avatar
Jared Hancock committed
    /*compares user password*/
    function check_passwd($password, $autoupdate=true) {
Jared Hancock's avatar
Jared Hancock committed

        /*bcrypt based password match*/
        if(Passwd::cmp($password, $this->getPasswd()))
Jared Hancock's avatar
Jared Hancock committed
            return true;

        //Fall back to MD5
        if(!$password || strcmp($this->getPasswd(), MD5($password)))
            return false;

        //Password is a MD5 hash: rehash it (if enabled) otherwise force passwd change.
        $sql='UPDATE '.STAFF_TABLE.' SET passwd='.db_input(Passwd::hash($password))
            .' WHERE staff_id='.db_input($this->getId());

        if(!$autoupdate || !db_query($sql))
Jared Hancock's avatar
Jared Hancock committed
            $this->forcePasswdRest();

    function cmp_passwd($password) {
        return $this->check_passwd($password, false);
    function hasPassword() {
        return (bool) $this->ht['passwd'];
    }

Jared Hancock's avatar
Jared Hancock committed
    function forcePasswdRest() {
        return db_query('UPDATE '.STAFF_TABLE.' SET change_passwd=1 WHERE staff_id='.db_input($this->getId()));
    }

    /* check if passwd reset is due. */
    function isPasswdResetDue() {
Jared Hancock's avatar
Jared Hancock committed
        global $cfg;
        return ($cfg && $cfg->getPasswdResetPeriod()
                    && $this->ht['passwd_change']>($cfg->getPasswdResetPeriod()*30*24*60*60));
Jared Hancock's avatar
Jared Hancock committed
    }

    function isPasswdChangeDue() {
        return $this->isPasswdResetDue();
    }

    function getTZoffset() {
        return $this->ht['tz_offset'];
    }

    function observeDaylight() {
        return $this->ht['daylight_saving']?true:false;
    }

    function getRefreshRate() {
Jared Hancock's avatar
Jared Hancock committed
        return $this->ht['auto_refresh_rate'];
    }

    function getPageLimit() {
        return $this->ht['max_page_size'];
    }

    function getId() {
Jared Hancock's avatar
Jared Hancock committed
        return $this->id;
    }

    function getEmail() {
Jared Hancock's avatar
Jared Hancock committed
        return $this->ht['email'];
    }

    function getUserName() {
Jared Hancock's avatar
Jared Hancock committed
        return $this->ht['username'];
    }

    function getPasswd() {
Jared Hancock's avatar
Jared Hancock committed
        return $this->ht['passwd'];
    }

    function getName() {
        return new PersonsName($this->ht['firstname'].' '.$this->ht['lastname']);
    function getFirstName() {
Jared Hancock's avatar
Jared Hancock committed
        return $this->ht['firstname'];
    }
    function getLastName() {
Jared Hancock's avatar
Jared Hancock committed
        return $this->ht['lastname'];
    }
    function getSignature() {
Jared Hancock's avatar
Jared Hancock committed
        return $this->ht['signature'];
    }

    function getDefaultSignatureType() {
        return $this->ht['default_signature_type'];
    }

    function getDefaultPaperSize() {
        return $this->ht['default_paper_size'];
    }

    function forcePasswdChange() {
Jared Hancock's avatar
Jared Hancock committed
        return ($this->ht['change_passwd']);
    }

Peter Rotich's avatar
Peter Rotich committed
    function getDepartments() {

        if($this->departments)
            return $this->departments;

        //Departments the staff is "allowed" to access...
        // based on the group they belong to + user's primary dept + user's managed depts.
        $sql='SELECT DISTINCT d.dept_id FROM '.STAFF_TABLE.' s '
            .' LEFT JOIN '.GROUP_DEPT_TABLE.' g ON(s.group_id=g.group_id) '
            .' INNER JOIN '.DEPT_TABLE.' d ON(d.dept_id=s.dept_id OR d.manager_id=s.staff_id OR d.dept_id=g.dept_id) '
            .' WHERE s.staff_id='.db_input($this->getId());

        $depts = array();
        if(($res=db_query($sql)) && db_num_rows($res)) {
            while(list($id)=db_fetch_row($res))
                $depts[] = $id;
        } else { //Neptune help us! (fallback)
            $depts = array_merge($this->getGroup()->getDepartments(), array($this->getDeptId()));
        }

        $this->departments = array_filter(array_unique($depts));


        return $this->departments;
    }

    function getDepts() {
Peter Rotich's avatar
Peter Rotich committed
        return $this->getDepartments();
    }

    function getManagedDepartments() {

        return ($depts=Dept::getDepartments(
                    array('manager' => $this->getId())
                    ))?array_keys($depts):array();
    }
Peter Rotich's avatar
Peter Rotich committed
    function getGroupId() {
        return $this->ht['group_id'];
Peter Rotich's avatar
Peter Rotich committed
    function getGroup() {
Peter Rotich's avatar
Peter Rotich committed
        if(!$this->group && $this->getGroupId())
            $this->group = Group::lookup($this->getGroupId());

        return $this->group;
    function getDeptId() {
Jared Hancock's avatar
Jared Hancock committed
        return $this->ht['dept_id'];
    }

    function getDept() {
        if(!$this->dept && $this->getDeptId())
Jared Hancock's avatar
Jared Hancock committed
            $this->dept= Dept::lookup($this->getDeptId());

        return $this->dept;
    }

    function getLanguage() {
        static $cached = false;
        if (!$cached) $cached = &$_SESSION['staff:lang'];

        if (!$cached) {
            $cached = $this->config->get('lang');
            if (!$cached)
                $cached = Internationalization::getDefaultLanguage();
        }
        return $cached;
    }
    function isManager() {
Jared Hancock's avatar
Jared Hancock committed
        return (($dept=$this->getDept()) && $dept->getManagerId()==$this->getId());
    }

    function isStaff() {
Jared Hancock's avatar
Jared Hancock committed
        return TRUE;
    }

    function isGroupActive() {
Jared Hancock's avatar
Jared Hancock committed
        return ($this->ht['group_enabled']);
    }

    function isactive() {
Jared Hancock's avatar
Jared Hancock committed
        return ($this->ht['isactive']);
    }

    function isVisible() {
Jared Hancock's avatar
Jared Hancock committed
         return ($this->ht['isvisible']);
    }
    function onVacation() {
Jared Hancock's avatar
Jared Hancock committed
        return ($this->ht['onvacation']);
    }

    function isAvailable() {
        return ($this->isactive() && $this->isGroupActive() && !$this->onVacation());
    }

    function showAssignedOnly() {
Jared Hancock's avatar
Jared Hancock committed
        return ($this->ht['assigned_only']);
    }

    function isAccessLimited() {
        return $this->showAssignedOnly();
    }
    function isAdmin() {
Jared Hancock's avatar
Jared Hancock committed
        return ($this->ht['isadmin']);
    }

    function isTeamMember($teamId) {
        return ($teamId && in_array($teamId, $this->getTeams()));
Jared Hancock's avatar
Jared Hancock committed
    }

    function canAccessDept($deptId) {
        return ($deptId && in_array($deptId, $this->getDepts()) && !$this->isAccessLimited());
    function canCreateTickets() {
Jared Hancock's avatar
Jared Hancock committed
        return ($this->ht['can_create_tickets']);
    }

    function canEditTickets() {
Jared Hancock's avatar
Jared Hancock committed
        return ($this->ht['can_edit_tickets']);
    }
    function canDeleteTickets() {
Jared Hancock's avatar
Jared Hancock committed
        return ($this->ht['can_delete_tickets']);
    }
    function canCloseTickets() {
Jared Hancock's avatar
Jared Hancock committed
        return ($this->ht['can_close_tickets']);
    }

    function canPostReply() {
        return ($this->ht['can_post_ticket_reply']);
    }

    function canViewStaffStats() {
        return ($this->ht['can_view_staff_stats']);
    }

Jared Hancock's avatar
Jared Hancock committed
    function canAssignTickets() {
        return ($this->ht['can_assign_tickets']);
    }

    function canTransferTickets() {
        return ($this->ht['can_transfer_tickets']);
    }

    function canBanEmails() {
        return ($this->ht['can_ban_emails']);
    }
    function canManageTickets() {
        return ($this->isAdmin()
                 || $this->canDeleteTickets()
Jared Hancock's avatar
Jared Hancock committed
                    || $this->canCloseTickets());
    }

    function canManagePremade() {
Jared Hancock's avatar
Jared Hancock committed
        return ($this->ht['can_manage_premade']);
    }

    function canManageCannedResponses() {
        return $this->canManagePremade();
    }

    function canManageFAQ() {
Jared Hancock's avatar
Jared Hancock committed
        return ($this->ht['can_manage_faq']);
    }

    function canManageFAQs() {
        return $this->canManageFAQ();
    }

    function showAssignedTickets() {
        return ($this->ht['show_assigned_tickets']);
    function getTeams() {
        if(!$this->teams) {
            $sql='SELECT team_id FROM '.TEAM_MEMBER_TABLE
                .' WHERE staff_id='.db_input($this->getId());
Jared Hancock's avatar
Jared Hancock committed
            if(($res=db_query($sql)) && db_num_rows($res))
                while(list($id)=db_fetch_row($res))
                    $this->teams[] = $id;
        }

        return $this->teams;
    }
    /* stats */

    function resetStats() {
        $this->stats = array();
    }

    /* returns staff's quick stats - used on nav menu...etc && warnings */
    function getTicketsStats() {

        if(!$this->stats['tickets'])
            $this->stats['tickets'] = Ticket::getStaffStats($this);

        return  $this->stats['tickets'];
    }

    function getNumAssignedTickets() {
        return ($stats=$this->getTicketsStats())?$stats['assigned']:0;
    }

    function getNumClosedTickets() {
        return ($stats=$this->getTicketsStats())?$stats['closed']:0;
    }

    //Staff profile update...unfortunately we have to separate it from admin update to avoid potential issues
    function updateProfile($vars, &$errors) {
        global $cfg;
Jared Hancock's avatar
Jared Hancock committed

        $vars['firstname']=Format::striptags($vars['firstname']);
        $vars['lastname']=Format::striptags($vars['lastname']);

        if($this->getId()!=$vars['id'])
            $errors['err']=__('Internal error occurred');
Jared Hancock's avatar
Jared Hancock committed

        if(!$vars['firstname'])
            $errors['firstname']=__('First name is required');
Jared Hancock's avatar
Jared Hancock committed
        if(!$vars['lastname'])
            $errors['lastname']=__('Last name is required');
Jared Hancock's avatar
Jared Hancock committed

        if(!$vars['email'] || !Validator::is_email($vars['email']))
            $errors['email']=__('Valid email is required');
Jared Hancock's avatar
Jared Hancock committed
        elseif(Email::getIdByEmail($vars['email']))
            $errors['email']=__('Already in-use as system email');
Jared Hancock's avatar
Jared Hancock committed
        elseif(($uid=Staff::getIdByEmail($vars['email'])) && $uid!=$this->getId())
            $errors['email']=__('Email already in-use by another agent');
Jared Hancock's avatar
Jared Hancock committed

        if($vars['phone'] && !Validator::is_phone($vars['phone']))
            $errors['phone']=__('Valid phone number is required');
Jared Hancock's avatar
Jared Hancock committed

        if($vars['mobile'] && !Validator::is_phone($vars['mobile']))
            $errors['mobile']=__('Valid phone number is required');
        if($vars['passwd1'] || $vars['passwd2'] || $vars['cpasswd']) {
Jared Hancock's avatar
Jared Hancock committed

            if(!$vars['passwd1'])
                $errors['passwd1']=__('New password is required');
Jared Hancock's avatar
Jared Hancock committed
            elseif($vars['passwd1'] && strlen($vars['passwd1'])<6)
                $errors['passwd1']=__('Password must be at least 6 characters');
            elseif($vars['passwd1'] && strcmp($vars['passwd1'], $vars['passwd2']))
                $errors['passwd2']=__('Passwords do not match');
            if (($rtoken = $_SESSION['_staff']['reset-token'])) {
                $_config = new Config('pwreset');
                if ($_config->get($rtoken) != $this->getId())
                    $errors['err'] =
                        __('Invalid reset token. Logout and try again');
                elseif (!($ts = $_config->lastModified($rtoken))
                        && ($cfg->getPwResetWindow() < (time() - strtotime($ts))))
                    $errors['err'] =
                        __('Invalid reset token. Logout and try again');
            }
            elseif(!$vars['cpasswd'])
                $errors['cpasswd']=__('Current password is required');
            elseif(!$this->cmp_passwd($vars['cpasswd']))
                $errors['cpasswd']=__('Invalid current password!');
            elseif(!strcasecmp($vars['passwd1'], $vars['cpasswd']))
                $errors['passwd1']=__('New password MUST be different from the current password!');
Jared Hancock's avatar
Jared Hancock committed
        }

        if(!$vars['timezone_id'])
            $errors['timezone_id']=__('Time zone selection is required');
Jared Hancock's avatar
Jared Hancock committed

        if($vars['default_signature_type']=='mine' && !$vars['signature'])
            $errors['default_signature_type'] = __("You don't have a signature");
Jared Hancock's avatar
Jared Hancock committed

        if($errors) return false;

        $this->config->set('lang', $vars['lang']);
        $_SESSION['staff:lang'] = null;
        TextDomain::configureForUser($this);
Jared Hancock's avatar
Jared Hancock committed
        $sql='UPDATE '.STAFF_TABLE.' SET updated=NOW() '
            .' ,firstname='.db_input($vars['firstname'])
            .' ,lastname='.db_input($vars['lastname'])
            .' ,email='.db_input($vars['email'])
            .' ,phone="'.db_input(Format::phone($vars['phone']),false).'"'
            .' ,phone_ext='.db_input($vars['phone_ext'])
            .' ,mobile="'.db_input(Format::phone($vars['mobile']),false).'"'
            .' ,signature='.db_input(Format::sanitize($vars['signature']))
Jared Hancock's avatar
Jared Hancock committed
            .' ,timezone_id='.db_input($vars['timezone_id'])
            .' ,daylight_saving='.db_input(isset($vars['daylight_saving'])?1:0)
            .' ,show_assigned_tickets='.db_input(isset($vars['show_assigned_tickets'])?1:0)
            .' ,max_page_size='.db_input($vars['max_page_size'])
            .' ,auto_refresh_rate='.db_input($vars['auto_refresh_rate'])
            .' ,default_signature_type='.db_input($vars['default_signature_type'])
            .' ,default_paper_size='.db_input($vars['default_paper_size']);
        if($vars['passwd1']) {
            $sql.=' ,change_passwd=0, passwdreset=NOW(), passwd='.db_input(Passwd::hash($vars['passwd1']));
            $info = array('password' => $vars['passwd1']);
            Signal::send('auth.pwchange', $this, $info);
            $this->cancelResetTokens();
        }
Jared Hancock's avatar
Jared Hancock committed

        $sql.=' WHERE staff_id='.db_input($this->getId());

        //echo $sql;

        return (db_query($sql));
    }


    function updateTeams($teams) {
        if($teams) {
            foreach($teams as $k=>$id) {
                $sql='INSERT IGNORE INTO '.TEAM_MEMBER_TABLE.' SET updated=NOW() '
                    .' ,staff_id='.db_input($this->getId()).', team_id='.db_input($id);
Jared Hancock's avatar
Jared Hancock committed
                db_query($sql);
            }
        }
Peter Rotich's avatar
Peter Rotich committed

Jared Hancock's avatar
Jared Hancock committed
        $sql='DELETE FROM '.TEAM_MEMBER_TABLE.' WHERE staff_id='.db_input($this->getId());
        if($teams)
Peter Rotich's avatar
Peter Rotich committed
            $sql.=' AND team_id NOT IN('.implode(',', db_input($teams)).')';
Jared Hancock's avatar
Jared Hancock committed
        db_query($sql);

        return true;
    }

    function update($vars, &$errors) {
Peter Rotich's avatar
Peter Rotich committed

        if(!$this->save($this->getId(), $vars, $errors))
Jared Hancock's avatar
Jared Hancock committed
            return false;

        $this->updateTeams($vars['teams']);
        $this->reload();

        Signal::send('model.modified', $this);
Jared Hancock's avatar
Jared Hancock committed
        return true;
    }

    function delete() {
Jared Hancock's avatar
Jared Hancock committed
        global $thisstaff;

        if (!$thisstaff || $this->getId() == $thisstaff->getId())
Jared Hancock's avatar
Jared Hancock committed
            return 0;

        $sql='DELETE FROM '.STAFF_TABLE
            .' WHERE staff_id = '.db_input($this->getId()).' LIMIT 1';
        if(db_query($sql) && ($num=db_affected_rows())) {
Jared Hancock's avatar
Jared Hancock committed
            // DO SOME HOUSE CLEANING
            //Move remove any ticket assignments...TODO: send alert to Dept. manager?
            db_query('UPDATE '.TICKET_TABLE.' SET staff_id=0 WHERE staff_id='.db_input($this->getId()));

            //Update the poster and clear staff_id on ticket thread table.
            db_query('UPDATE '.TICKET_THREAD_TABLE
                    .' SET staff_id=0, poster= '.db_input($this->getName()->getOriginal())
                    .' WHERE staff_id='.db_input($this->getId()));

Jared Hancock's avatar
Jared Hancock committed
            //Cleanup Team membership table.
            db_query('DELETE FROM '.TEAM_MEMBER_TABLE.' WHERE staff_id='.db_input($this->getId()));

            // Destrory config settings
            $this->config->destroy();
        Signal::send('model.deleted', $this);

Jared Hancock's avatar
Jared Hancock committed
        return $num;
    }

    /**** Static functions ********/
    function getStaffMembers($availableonly=false) {

        $sql='SELECT s.staff_id, CONCAT_WS(" ", s.firstname, s.lastname) as name '
Jared Hancock's avatar
Jared Hancock committed
            .' FROM '.STAFF_TABLE.' s ';

        if($availableonly) {
            $sql.=' INNER JOIN '.GROUP_TABLE.' g ON(g.group_id=s.group_id AND g.group_enabled=1) '
                 .' WHERE s.isactive=1 AND s.onvacation=0';
        }

        $sql.='  ORDER BY s.lastname, s.firstname';
        $users=array();
        if(($res=db_query($sql)) && db_num_rows($res)) {
            while(list($id, $name) = db_fetch_row($res))
                $users[$id] = $name;
        }

        return $users;
    }

    function getAvailableStaffMembers() {
        return self::getStaffMembers(true);
    }

    function getIdByUsername($username) {
Jared Hancock's avatar
Jared Hancock committed

        $sql='SELECT staff_id FROM '.STAFF_TABLE.' WHERE username='.db_input($username);
        if(($res=db_query($sql)) && db_num_rows($res))
            list($id) = db_fetch_row($res);

        return $id;
    }
    function getIdByEmail($email) {
Jared Hancock's avatar
Jared Hancock committed
        $sql='SELECT staff_id FROM '.STAFF_TABLE.' WHERE email='.db_input($email);
        if(($res=db_query($sql)) && db_num_rows($res))
            list($id) = db_fetch_row($res);

        return $id;
    }

    function lookup($id) {
        return ($id && ($staff= new Staff($id)) && $staff->getId()) ? $staff : null;
    function create($vars, &$errors) {
        if(($id=self::save(0, $vars, $errors)) && ($staff=Staff::lookup($id))) {
            if ($vars['teams'])
                $staff->updateTeams($vars['teams']);
            if ($vars['welcome_email'])
                $staff->sendResetEmail('registration-staff');
            Signal::send('model.created', $staff);
        }
    function cancelResetTokens() {
        // TODO: Drop password-reset tokens from the config table for
        //       this user id
        $sql = 'DELETE FROM '.CONFIG_TABLE.' WHERE `namespace`="pwreset"
            AND `value`='.db_input($this->getId());
        db_query($sql, false);
        unset($_SESSION['_staff']['reset-token']);
    }

    function sendResetEmail($template='pwreset-staff') {
        global $ost, $cfg;

        $content = Page::lookup(Page::getIdByType($template));
        $token = Misc::randCode(48); // 290-bits
            return new Error(/* @trans */ 'Unable to retrieve password reset email template');
        $vars = array(
            'url' => $ost->getConfig()->getBaseUrl(),
            'token' => $token,
            'recipient' => $this,
            'reset_link' => sprintf(
                "%s/scp/pwreset.php?token=%s",
                $ost->getConfig()->getBaseUrl(),
                $token),
        $vars['link'] = &$vars['reset_link'];
        if (!($email = $cfg->getAlertEmail()))
            $email = $cfg->getDefaultEmail();

        $info = array('email' => $email, 'vars' => &$vars, 'log'=>true);
        Signal::send('auth.pwreset.email', $this, $info);

        if ($info['log'])
            $ost->logWarning(_S('Agent Password Reset'), sprintf(
             _S('Password reset was attempted for agent: %1$s<br><br>
                Requested-User-Id: %2$s<br>
                Source-Ip: %3$s<br>
                Email-Sent-To: %4$s<br>
                Email-Sent-Via: %5$s'),
                $this->getName(),
                $_POST['userid'],
                $_SERVER['REMOTE_ADDR'],
                $this->getEmail(),
                $email->getEmail()
            ), false);

        $msg = $ost->replaceTemplateVariables(array(
            'subj' => $content->getName(),
            'body' => $content->getBody(),
        ), $vars);

        $_config = new Config('pwreset');
        $_config->set($vars['token'], $this->getId());
        $email->send($this->getEmail(), Format::striptags($msg['subj']),
    function save($id, $vars, &$errors) {
Jared Hancock's avatar
Jared Hancock committed
        $vars['username']=Format::striptags($vars['username']);
        $vars['firstname']=Format::striptags($vars['firstname']);
        $vars['lastname']=Format::striptags($vars['lastname']);

        if($id && $id!=$vars['id'])
            $errors['err']=__('Internal Error');
Jared Hancock's avatar
Jared Hancock committed
        if(!$vars['firstname'])
            $errors['firstname']=__('First name required');
Jared Hancock's avatar
Jared Hancock committed
        if(!$vars['lastname'])
            $errors['lastname']=__('Last name required');
        $error = '';
        if(!$vars['username'] || !Validator::is_username($vars['username'], $error))
            $errors['username']=($error) ? $error : __('Username is required');
Jared Hancock's avatar
Jared Hancock committed
        elseif(($uid=Staff::getIdByUsername($vars['username'])) && $uid!=$id)
            $errors['username']=__('Username already in use');
Jared Hancock's avatar
Jared Hancock committed
        if(!$vars['email'] || !Validator::is_email($vars['email']))
            $errors['email']=__('Valid email is required');
Jared Hancock's avatar
Jared Hancock committed
        elseif(Email::getIdByEmail($vars['email']))
            $errors['email']=__('Already in use system email');
Jared Hancock's avatar
Jared Hancock committed
        elseif(($uid=Staff::getIdByEmail($vars['email'])) && $uid!=$id)
            $errors['email']=__('Email already in use by another agent');
Jared Hancock's avatar
Jared Hancock committed

        if($vars['phone'] && !Validator::is_phone($vars['phone']))
            $errors['phone']=__('Valid phone number is required');
Jared Hancock's avatar
Jared Hancock committed
        if($vars['mobile'] && !Validator::is_phone($vars['mobile']))
            $errors['mobile']=__('Valid phone number is required');
        if($vars['passwd1'] || $vars['passwd2'] || !$id) {
Jared Hancock's avatar
Jared Hancock committed
            if($vars['passwd1'] && strcmp($vars['passwd1'], $vars['passwd2'])) {
                $errors['passwd2']=__('Passwords do not match');
            elseif ($vars['backend'] != 'local' || $vars['welcome_email']) {
Jared Hancock's avatar
Jared Hancock committed
                // Password can be omitted
            }
            elseif(!$vars['passwd1'] && !$id) {
                $errors['passwd1']=__('Temporary password is required');
                $errors['temppasswd']=__('Required');
            } elseif($vars['passwd1'] && strlen($vars['passwd1'])<6) {
                $errors['passwd1']=__('Password must be at least 6 characters');
Jared Hancock's avatar
Jared Hancock committed
        if(!$vars['dept_id'])
            $errors['dept_id']=__('Department is required');
Jared Hancock's avatar
Jared Hancock committed
        if(!$vars['group_id'])
            $errors['group_id']=__('Group is required');
Jared Hancock's avatar
Jared Hancock committed

        if(!$vars['timezone_id'])
            $errors['timezone_id']=__('Time zone selection is required');
        // Ensure we will still have an administrator with access
        if ($vars['isadmin'] !== '1' || $vars['isactive'] !== '1') {
            $sql = 'select count(*), max(staff_id) from '.STAFF_TABLE
                .' WHERE isadmin=1 and isactive=1';
            if (($res = db_query($sql))
                    && (list($count, $sid) = db_fetch_row($res))) {
                if ($count == 1 && $sid = $id) {
                    $errors['isadmin'] = __(
                        'Cowardly refusing to remove or lock out the only active administrator'
                    );
                }
            }
        }

Jared Hancock's avatar
Jared Hancock committed
        if($errors) return false;

        $sql='SET updated=NOW() '
            .' ,isadmin='.db_input($vars['isadmin'])
            .' ,isactive='.db_input($vars['isactive'])
            .' ,isvisible='.db_input(isset($vars['isvisible'])?1:0)
            .' ,onvacation='.db_input(isset($vars['onvacation'])?1:0)
            .' ,assigned_only='.db_input(isset($vars['assigned_only'])?1:0)
            .' ,dept_id='.db_input($vars['dept_id'])
            .' ,group_id='.db_input($vars['group_id'])
            .' ,timezone_id='.db_input($vars['timezone_id'])
            .' ,daylight_saving='.db_input(isset($vars['daylight_saving'])?1:0)
            .' ,username='.db_input($vars['username'])
            .' ,firstname='.db_input($vars['firstname'])
            .' ,lastname='.db_input($vars['lastname'])
            .' ,email='.db_input($vars['email'])
Jared Hancock's avatar
Jared Hancock committed
            .' ,backend='.db_input($vars['backend'])
            .' ,phone="'.db_input(Format::phone($vars['phone']),false).'"'
            .' ,phone_ext='.db_input($vars['phone_ext'])
            .' ,mobile="'.db_input(Format::phone($vars['mobile']),false).'"'
            .' ,signature='.db_input(Format::sanitize($vars['signature']))
            .' ,notes='.db_input(Format::sanitize($vars['notes']));
        if($vars['passwd1']) {
            $sql.=' ,passwd='.db_input(Passwd::hash($vars['passwd1']));
            if(isset($vars['change_passwd']))
                $sql.=' ,change_passwd=1';
        }
        elseif (!isset($vars['change_passwd']))
            $sql .= ' ,change_passwd=0';
Jared Hancock's avatar
Jared Hancock committed
        if($id) {
            $sql='UPDATE '.STAFF_TABLE.' '.$sql.' WHERE staff_id='.db_input($id);
            if(db_query($sql) && db_affected_rows())
                return true;
            $errors['err']=sprintf(__('Unable to update %s.'), __('this agent'))
               .' '.__('Internal error occurred');
        } else {
            $sql='INSERT INTO '.STAFF_TABLE.' '.$sql.', created=NOW()';
Jared Hancock's avatar
Jared Hancock committed
            if(db_query($sql) && ($uid=db_insert_id()))
                return $uid;
            $errors['err']=sprintf(__('Unable to create %s.'), __('this agent'))
               .' '.__('Internal error occurred');