golden hour
/home/doctorbruno/public_html/taeionline.com/support/include
⬆️ Go Up
Upload
File/Folder
Size
Actions
.MANIFEST
194.97 KB
Del
OK
.htaccess
14 B
Del
OK
JSON.php
33.13 KB
Del
OK
PasswordHash.php
6.92 KB
Del
OK
Spyc.php
31.74 KB
Del
OK
UniversalClassLoader.php
8.61 KB
Del
OK
ajax.admin.php
7.29 KB
Del
OK
ajax.config.php
4.61 KB
Del
OK
ajax.content.php
9.76 KB
Del
OK
ajax.draft.php
13.03 KB
Del
OK
ajax.email.php
2.33 KB
Del
OK
ajax.export.php
1006 B
Del
OK
ajax.filter.php
874 B
Del
OK
ajax.forms.php
13.84 KB
Del
OK
ajax.i18n.php
5.1 KB
Del
OK
ajax.kbase.php
2.93 KB
Del
OK
ajax.note.php
2.05 KB
Del
OK
ajax.orgs.php
11.73 KB
Del
OK
ajax.plugins.php
2.15 KB
Del
OK
ajax.schedule.php
4.29 KB
Del
OK
ajax.search.php
12.72 KB
Del
OK
ajax.sequence.php
3.2 KB
Del
OK
ajax.staff.php
11.62 KB
Del
OK
ajax.tasks.php
33.87 KB
Del
OK
ajax.thread.php
8.81 KB
Del
OK
ajax.tickets.php
79.7 KB
Del
OK
ajax.tips.php
1.66 KB
Del
OK
ajax.upgrader.php
2.24 KB
Del
OK
ajax.users.php
18.33 KB
Del
OK
api.cron.php
1.06 KB
Del
OK
api.tickets.php
10.36 KB
Del
OK
class.2fa.php
7.76 KB
Del
OK
class.ajax.php
1.45 KB
Del
OK
class.api.php
15.31 KB
Del
OK
class.app.php
1.49 KB
Del
OK
class.attachment.php
6.95 KB
Del
OK
class.auth.php
50.73 KB
Del
OK
class.avatar.php
6.44 KB
Del
OK
class.banlist.php
2.58 KB
Del
OK
class.base32.php
4.07 KB
Del
OK
class.businesshours.php
7.08 KB
Del
OK
class.canned.php
9.05 KB
Del
OK
class.captcha.php
1.73 KB
Del
OK
class.category.php
11.14 KB
Del
OK
class.charset.php
3.41 KB
Del
OK
class.cli.php
9.48 KB
Del
OK
class.client.php
15.39 KB
Del
OK
class.collaborator.php
5.65 KB
Del
OK
class.company.php
2.65 KB
Del
OK
class.config.php
60.36 KB
Del
OK
class.controller.php
1.15 KB
Del
OK
class.cron.php
3.6 KB
Del
OK
class.crypto.php
18.92 KB
Del
OK
class.csrf.php
2.38 KB
Del
OK
class.dept.php
33.21 KB
Del
OK
class.dispatcher.php
7.12 KB
Del
OK
class.draft.php
6.23 KB
Del
OK
class.dynamic_forms.php
64.98 KB
Del
OK
class.email.php
49 KB
Del
OK
class.error.php
1.69 KB
Del
OK
class.export.php
32.92 KB
Del
OK
class.faq.php
15.05 KB
Del
OK
class.file.php
34.59 KB
Del
OK
class.filter.php
31.9 KB
Del
OK
class.filter_action.php
23.67 KB
Del
OK
class.format.php
44.3 KB
Del
OK
class.forms.php
195.58 KB
Del
OK
class.http.php
7.16 KB
Del
OK
class.i18n.php
24.28 KB
Del
OK
class.import.php
6.9 KB
Del
OK
class.json.php
2.71 KB
Del
OK
class.knowledgebase.php
5.8 KB
Del
OK
class.list.php
42 KB
Del
OK
class.lock.php
4.05 KB
Del
OK
class.log.php
1.55 KB
Del
OK
class.mail.php
35.76 KB
Del
OK
class.mailer.php
25.75 KB
Del
OK
class.mailfetch.php
9.72 KB
Del
OK
class.mailparse.php
30.99 KB
Del
OK
class.message.php
6.42 KB
Del
OK
class.migrater.php
5.2 KB
Del
OK
class.misc.php
7.5 KB
Del
OK
class.model.php
2.3 KB
Del
OK
class.nav.php
14.15 KB
Del
OK
class.note.php
2.39 KB
Del
OK
class.oauth2.php
4.04 KB
Del
OK
class.organization.php
22.45 KB
Del
OK
class.orm.php
120.9 KB
Del
OK
class.osticket.php
20.64 KB
Del
OK
class.ostsession.php
21.86 KB
Del
OK
class.page.php
10.59 KB
Del
OK
class.pagenate.php
5.53 KB
Del
OK
class.passwd.php
1.21 KB
Del
OK
class.pdf.php
3.83 KB
Del
OK
class.plugin.php
36.13 KB
Del
OK
class.priority.php
1.81 KB
Del
OK
class.queue.php
103.51 KB
Del
OK
class.report.php
11.76 KB
Del
OK
class.role.php
11.27 KB
Del
OK
class.schedule.php
46.28 KB
Del
OK
class.search.php
61.66 KB
Del
OK
class.sequence.php
7.27 KB
Del
OK
class.session.php
19.25 KB
Del
OK
class.setup.php
3.55 KB
Del
OK
class.signal.php
4.16 KB
Del
OK
class.sla.php
9.11 KB
Del
OK
class.staff.php
60.21 KB
Del
OK
class.task.php
56.21 KB
Del
OK
class.team.php
12.31 KB
Del
OK
class.template.php
23.45 KB
Del
OK
class.thread.php
108.96 KB
Del
OK
class.thread_actions.php
17.08 KB
Del
OK
class.ticket.php
167.39 KB
Del
OK
class.timezone.php
21.94 KB
Del
OK
class.topic.php
20.06 KB
Del
OK
class.translation.php
34.79 KB
Del
OK
class.upgrader.php
13.76 KB
Del
OK
class.user.php
43.4 KB
Del
OK
class.usersession.php
7.55 KB
Del
OK
class.util.php
10.07 KB
Del
OK
class.validator.php
12.94 KB
Del
OK
class.variable.php
11.93 KB
Del
OK
class.xml.php
3.23 KB
Del
OK
class.yaml.php
1.15 KB
Del
OK
cli
-
Del
OK
client
-
Del
OK
config
-
Del
OK
fpdf
-
Del
OK
htmLawed.php
53.53 KB
Del
OK
html2text.php
33.71 KB
Del
OK
i18n
-
Del
OK
index.php
37 B
Del
OK
laminas-mail
-
Del
OK
mpdf
-
Del
OK
mysqli.php
9.55 KB
Del
OK
ost-config.php
5.63 KB
Del
OK
ost-sampleconfig.php
6.24 KB
Del
OK
pear
-
Del
OK
plugins
-
Del
OK
staff
-
Del
OK
tnef_decoder.php
19.82 KB
Del
OK
upgrader
-
Del
OK
Edit: class.staff.php
<?php /********************************************************************* class.staff.php Everything about staff. Peter Rotich <peter@osticket.com> Copyright (c) 2006-2013 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: **********************************************************************/ include_once(INCLUDE_DIR.'class.ticket.php'); include_once(INCLUDE_DIR.'class.dept.php'); include_once(INCLUDE_DIR.'class.error.php'); include_once(INCLUDE_DIR.'class.team.php'); include_once(INCLUDE_DIR.'class.role.php'); include_once(INCLUDE_DIR.'class.passwd.php'); include_once(INCLUDE_DIR.'class.user.php'); include_once(INCLUDE_DIR.'class.auth.php'); class Staff extends VerySimpleModel implements AuthenticatedUser, EmailContact, TemplateVariable, Searchable { static $meta = array( 'table' => STAFF_TABLE, 'pk' => array('staff_id'), 'joins' => array( 'dept' => array( 'constraint' => array('dept_id' => 'Dept.id'), ), 'role' => array( 'constraint' => array('role_id' => 'Role.id'), ), 'dept_access' => array( 'reverse' => 'StaffDeptAccess.staff', ), 'teams' => array( 'reverse' => 'TeamMember.staff', ), ), ); var $authkey; var $departments; var $stats = array(); var $_extra; var $passwd_change; var $_roles = null; var $_teams = null; var $_config = null; var $_perm; const PERM_STAFF = 'visibility.agents'; static protected $perms = array( self::PERM_STAFF => array( 'title' => /* @trans */ 'Agent', 'desc' => /* @trans */ 'Ability to see Agents in all Departments', 'primary' => true, ), ); function __onload() { } function get($field, $default=false) { // Check primary fields try { return parent::get($field, $default); } catch (Exception $e) {} // Autoload config if not loaded already if (!isset($this->_config)) $this->getConfig(); if (isset($this->_config[$field])) return $this->_config[$field]; } function getConfigObj() { return new Config('staff.'.$this->getId()); } function getConfig() { if (!isset($this->_config) && $this->getId()) { $_config = new Config('staff.'.$this->getId(), // Defaults array( 'default_from_name' => '', 'datetime_format' => '', 'thread_view_order' => '', 'default_ticket_queue_id' => 0, 'reply_redirect' => 'Ticket', 'img_att_view' => 'download', 'editor_spacing' => 'double', )); $this->_config = $_config->getInfo(); } return $this->_config; } function updateConfig($vars) { $config = $this->getConfigObj(); $config->updateAll($vars); $this->_config = null; } function __toString() { return (string) $this->getName(); } function asVar() { return $this->__toString(); } static function getVarScope() { return array( 'dept' => array('class' => 'Dept', 'desc' => __('Department')), 'email' => __('Email Address'), 'name' => array( 'class' => 'PersonsName', 'desc' => __('Agent name'), ), 'mobile' => __('Mobile Number'), 'phone' => __('Phone Number'), 'signature' => __('Signature'), 'timezone' => "Agent's configured timezone", 'username' => 'Access username', ); } function getVar($tag) { switch ($tag) { case 'mobile': return Format::phone($this->ht['mobile']); case 'phone': return Format::phone($this->ht['phone']); } } static function getSearchableFields() { return array( 'email' => new TextboxField(array( 'label' => __('Email Address'), )), ); } static function supportsCustomData() { return false; } function getHashtable() { $base = $this->ht; unset($base['teams']); unset($base['dept_access']); if ($this->getConfig()) $base += $this->getConfig(); return $base; } function getInfo() { return $this->getHashtable(); } // AuthenticatedUser implementation... // TODO: Move to an abstract class that extends Staff function getUserType() { return 'staff'; } function getAuthBackend() { list($bk, ) = explode(':', $this->getAuthKey()); // If administering a user other than yourself, fallback to the // agent's declared backend, if any if (!$bk && $this->backend) $bk = $this->backend; return StaffAuthenticationBackend::getBackend($bk); } function get2FABackendId() { return $this->default_2fa; } function get2FABackend() { return Staff2FABackend::getBackend($this->get2FABackendId()); } // gets configured backends function get2FAConfig($id) { $config = $this->getConfig(); return isset($config[$id]) ? JsonDataParser::decode($config[$id]) : array(); } function setAuthKey($key) { $this->authkey = $key; } function getAuthKey() { return $this->authkey; } // logOut the user function logOut() { if ($bk = $this->getAuthBackend()) return $bk->signOut($this); return false; } /*compares user password*/ function check_passwd($password, $autoupdate=true) { /*bcrypt based password match*/ if(Passwd::cmp($password, $this->getPasswd())) 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. $this->passwd = Passwd::hash($password); if(!$autoupdate || !$this->save()) $this->forcePasswdRest(); return true; } function cmp_passwd($password) { return $this->check_passwd($password, false); } function hasPassword() { return (bool) $this->passwd; } function forcePasswdRest() { $this->change_passwd = 1; return $this->save(); } function getPasswdResetTimestamp() { if (!isset($this->passwd_change)) { // WE have to patch info here to support upgrading from old versions. if (isset($this->passwdreset) && $this->passwdreset) $this->passwd_change = strtotime($this->passwdreset); elseif (isset($this->added) && $this->added) $this->passwd_change = strtotime($this->added); elseif (isset($this->created) && $this->created) $this->passwd_change = strtotime($this->created); } return $this->passwd_change; } static function checkPassword($new, $current=null) { osTicketStaffAuthentication::checkPassword($new, $current); } function setPassword($new, $current=false) { global $thisstaff; // Allow the backend to update the password. This is the preferred // method as it allows for integration with password policies and // also allows for remotely updating the password where possible and // supported. if (!($bk = $this->getAuthBackend()) || !$bk instanceof AuthBackend ) { // Fallback to osTicket authentication token udpates $bk = new osTicketStaffAuthentication(); } // And now for the magic if (!$bk->supportsPasswordChange()) { throw new PasswordUpdateFailed( __('Authentication backend does not support password updates')); } // Backend should throw PasswordUpdateFailed directly $rv = $bk->setPassword($this, $new, $current); // Successfully updated authentication tokens $this->change_passwd = 0; $this->cancelResetTokens(); $this->passwdreset = SqlFunction::NOW(); // Clean sessions Signal::send('auth.clean', $this, $thisstaff); return $rv; } function canAccess($something) { if ($something instanceof RestrictedAccess) return $something->checkStaffPerm($this); return true; } function getRefreshRate() { return $this->auto_refresh_rate; } function getPageLimit() { return $this->max_page_size; } function getId() { return $this->staff_id; } function getUserId() { return $this->getId(); } function getEmail() { return $this->email; } function getEmailAddress() { $emailaddr = (string) $this->getEmail(); if (($name=$this->getName())) $emailaddr = sprintf('"%s" <%s>', (string) $name, $emailaddr); return $emailaddr; } function getAvatar($size=null) { global $cfg; $source = $cfg->getStaffAvatarSource(); $avatar = $source->getAvatar($this); if (isset($size)) $avatar->setSize($size); return $avatar; } function getUserName() { return $this->username; } function getPasswd() { return $this->passwd; } function getName() { return new AgentsName(array('first' => $this->ht['firstname'], 'last' => $this->ht['lastname'])); } function getAvatarAndName() { return $this->getAvatar().Format::htmlchars((string) $this->getName()); } function getFirstName() { return $this->firstname; } function getLastName() { return $this->lastname; } function getSignature() { return $this->signature; } function getDefaultTicketQueueId() { return $this->default_ticket_queue_id; } function getDefaultSignatureType() { return $this->default_signature_type; } function getReplyFromNameType() { return $this->default_from_name; } function getDefaultPaperSize() { return $this->default_paper_size; } function getReplyRedirect() { return $this->reply_redirect; } function getImageAttachmentView() { return $this->img_att_view; } function editorSpacing() { return $this->editor_spacing; } function forcePasswdChange() { return $this->change_passwd; } function force2faConfig() { global $cfg; $id = $this->get2FABackendId(); $config = $this->get2FAConfig($id); //2fa is required and //1. agent doesn't have default_2fa or //2. agent has default_2fa, but that default_2fa is not configured return ($cfg->require2FAForAgents() && !$id || ($id && empty($config))); } function getDepartments() { // TODO: Cache this in the agent's session as it is unlikely to // change while logged in if (!isset($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.id FROM '.STAFF_TABLE.' s ' .' LEFT JOIN '.STAFF_DEPT_TABLE.' g ON (s.staff_id=g.staff_id) ' .' INNER JOIN '.DEPT_TABLE.' d ON (LOCATE(CONCAT("/", s.dept_id, "/"), d.path) OR d.manager_id=s.staff_id OR LOCATE(CONCAT("/", g.dept_id, "/"), d.path)) ' .' 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[] = (int) $id; } /* ORM method — about 2.0ms slower $q = Q::any(array( 'path__contains' => '/'.$this->dept_id.'/', 'manager_id' => $this->getId(), )); // Add in extended access foreach ($this->dept_access->depts->values_flat('dept_id') as $row) { // Skip primary dept if ($row[0] == $this->dept_id) continue; $q->add(new Q(array('path__contains'=>'/'.$row[0].'/'))); } $dept_ids = Dept::objects() ->filter($q) ->distinct('id') ->values_flat('id'); foreach ($dept_ids as $row) $depts[] = $row[0]; */ $this->departments = $depts; } return $this->departments; } function getDepts() { return $this->getDepartments(); } function getDepartmentNames($activeonly=false) { $depts = Dept::getDepartments(array('activeonly' => $activeonly)); //filter out departments the agent does not have access to if (!$this->hasPerm(Dept::PERM_DEPT) && $staffDepts = $this->getDepts()) { foreach ($depts as $id => $name) { if (!in_array($id, $staffDepts)) unset($depts[$id]); } } return $depts; } function getTopicNames($publicOnly=false, $disabled=false) { $allInfo = !$this->hasPerm(Dept::PERM_DEPT) ? true : false; $topics = Topic::getHelpTopics($publicOnly, $disabled, true, array(), $allInfo); $topicsClean = array(); if (!$this->hasPerm(Dept::PERM_DEPT) && $staffDepts = $this->getDepts()) { foreach ($topics as $id => $info) { if ($info['pid']) { $childDeptId = $info['dept_id']; //show child if public, has access to topic dept_id, or no dept at all if ($info['public'] || !$childDeptId || ($childDeptId && in_array($childDeptId, $staffDepts))) $topicsClean[$id] = $info['topic']; $parent = Topic::lookup($info['pid']); if (!$parent->isPublic() && $parent->getDeptId() && !in_array($parent->getDeptId(), $staffDepts)) { //hide child if parent topic is private and no access to parent topic dept_id unset($topicsClean[$id]); } } elseif ($info['public']) { //show all public topics $topicsClean[$id] = $info['topic']; } else { //show private topics if access to topic dept_id or no dept at all if ($info['dept_id'] && in_array($info['dept_id'], $staffDepts) || !$info['dept_id']) $topicsClean[$id] = $info['topic']; } } return $topicsClean; } return $topics; } function getManagedDepartments() { return ($depts=Dept::getDepartments( array('manager' => $this->getId()) ))?array_keys($depts):array(); } function getDeptId() { return $this->dept_id; } function getDept() { return $this->dept; } function setDepartmentId($dept_id, $eavesdrop=false) { // Grant access to the current department $old = $this->dept_id; if ($eavesdrop) { $da = new StaffDeptAccess(array( 'dept_id' => $old, 'role_id' => $this->role_id, )); $da->setAlerts(true); $this->dept_access->add($da); } // Drop extended access to new department $this->dept_id = $dept_id; if ($da = $this->dept_access->findFirst(array( 'dept_id' => $dept_id)) ) { $this->dept_access->remove($da); } $this->save(); } function usePrimaryRoleOnAssignment() { return $this->getExtraAttr('def_assn_role', true); } function getLanguage() { return (isset($this->lang)) ? $this->lang : false; } function getTimezone() { if (isset($this->timezone)) return $this->timezone; } function getLocale() { //XXX: isset is required here to avoid possible crash when upgrading // installation where locale column doesn't exist yet. return isset($this->locale) ? $this->locale : 0; } function getRoles() { if (!isset($this->_roles)) { $this->_roles = array($this->dept_id => $this->role); foreach($this->dept_access as $da) $this->_roles[$da->dept_id] = $da->role; } return $this->_roles; } function getRole($dept=null, $assigned=false) { if (is_null($dept)) return $this->role; if (is_numeric($dept)) $deptId = $dept; elseif($dept instanceof Dept) $deptId = $dept->getId(); else return null; $roles = $this->getRoles(); if (isset($roles[$deptId])) return $roles[$deptId]; // Default to primary role. if ($assigned && $this->usePrimaryRoleOnAssignment()) return $this->role; // Ticket Create & View only access $perms = JSONDataEncoder::encode(array( Ticket::PERM_CREATE => 1)); return new Role(array('permissions' => $perms)); } function hasPerm($perm, $global=true) { if ($global) return $this->getPermission()->has($perm); if ($this->getRole()->hasPerm($perm)) return true; foreach ($this->dept_access as $da) if ($da->role->hasPerm($perm)) return true; return false; } function canSearchEverything() { return $this->hasPerm(SearchBackend::PERM_EVERYTHING); } function canManageTickets() { return $this->hasPerm(Ticket::PERM_DELETE, false) || $this->hasPerm(Ticket::PERM_TRANSFER, false) || $this->hasPerm(Ticket::PERM_ASSIGN, false) || $this->hasPerm(Ticket::PERM_CLOSE, false); } function isManager($dept=null) { return (($dept=$dept?:$this->getDept()) && $dept->getManagerId()==$this->getId()); } function isStaff() { return TRUE; } function isActive() { return $this->isactive; } function getStatus() { return $this->isActive() ? __('Active') : __('Locked'); } function isVisible() { return $this->isvisible; } function onVacation() { return $this->onvacation; } function isAvailable() { return ($this->isActive() && !$this->onVacation()); } function showAssignedOnly() { return $this->assigned_only; } function isAccessLimited() { return $this->showAssignedOnly(); } function isAdmin() { return $this->isadmin; } function isTeamMember($teamId) { return ($teamId && in_array($teamId, $this->getTeams())); } function canAccessDept($dept) { if (!$dept instanceof Dept) return false; return (!$this->isAccessLimited() && in_array($dept->getId(), $this->getDepts())); } function getTeams() { if (!isset($this->_teams)) { $this->_teams = array(); foreach ($this->teams as $team) $this->_teams[] = (int) $team->team_id; } return $this->_teams; } function getTicketsVisibility($exclude_archived=false) { // -- Open and assigned to me $assigned = Q::any(array( 'staff_id' => $this->getId(), )); $assigned->add(array('thread__referrals__agent__staff_id' => $this->getId())); $childRefAgent = Q::all(new Q(array('child_thread__object_type' => 'C', 'child_thread__referrals__agent__staff_id' => $this->getId()))); $assigned->add($childRefAgent); // -- Open and assigned to a team of mine if (($teams = array_filter($this->getTeams()))) { $assigned->add(array('team_id__in' => $teams)); $assigned->add(array('thread__referrals__team__team_id__in' => $teams)); $childRefTeam = Q::all(new Q(array('child_thread__object_type' => 'C', 'child_thread__referrals__team__team_id__in' => $teams))); $assigned->add($childRefTeam); } $visibility = Q::any(new Q(array('status__state__in'=>['open', 'closed'], $assigned))); // -- If access is limited to assigned only, return assigned if ($this->isAccessLimited()) return $visibility; // -- Routed to a department of mine if (($depts=$this->getDepts()) && count($depts)) { $in_dept = Q::any(array( 'dept_id__in' => $depts, 'thread__referrals__dept__id__in' => $depts, )); if ($exclude_archived) { $in_dept = Q::all(array( 'status__state__in' => ['open', 'closed'], $in_dept, )); } $visibility->add($in_dept); $childRefDept = Q::all(new Q(array('child_thread__object_type' => 'C', 'child_thread__referrals__dept__id__in' => $depts))); $visibility->add($childRefDept); } return $visibility; } function applyVisibility($query, $exclude_archived=false) { return $query->filter($this->getTicketsVisibility($exclude_archived))->distinct('ticket_id'); } function applyDeptVisibility($qs) { // Restrict agents based on visibility of the assigner if (!$this->hasPerm(Staff::PERM_STAFF) && ($depts=$this->getDepts())) { return $qs->filter(Q::any(array( 'dept_id__in' => $depts, 'dept_access__dept_id__in' => $depts, ))); } return $qs; } /* stats */ function resetStats() { $this->stats = array(); } function getTasksStats() { if (!$this->stats['tasks']) $this->stats['tasks'] = Task::getStaffStats($this); return $this->stats['tasks']; } function getNumAssignedTasks() { return ($stats=$this->getTasksStats()) ? $stats['assigned'] : 0; } function getNumClosedTasks() { return ($stats=$this->getTasksStats()) ? $stats['closed'] : 0; } function getExtraAttr($attr=false, $default=null) { if (!isset($this->_extra) && isset($this->extra)) $this->_extra = JsonDataParser::decode($this->extra); return $attr ? (isset($this->_extra[$attr]) ? $this->_extra[$attr] : $default) : $this->_extra; } function setExtraAttr($attr, $value, $commit=true) { $this->getExtraAttr(); $this->_extra[$attr] = $value; $this->extra = JsonDataEncoder::encode($this->_extra); if ($commit) { $this->save(); } } function getPermission() { if (!isset($this->_perm)) { $this->_perm = new RolePermission($this->permissions); } return $this->_perm; } function getPermissionInfo() { return $this->getPermission()->getInfo(); } function onLogin($bk) { // Update last apparent language preference $this->setExtraAttr('browser_lang', Internationalization::getCurrentLanguage(), false); $this->lastlogin = SqlFunction::NOW(); $this->save(); } //Staff profile update...unfortunately we have to separate it from admin update to avoid potential issues function updateProfile($vars, &$errors) { global $cfg; $vars['firstname']=Format::striptags($vars['firstname']); $vars['lastname']=Format::striptags($vars['lastname']); if (isset($this->staff_id) && $this->getId() != $vars['id']) $errors['err']=__('Internal error occurred'); if(!$vars['firstname']) $errors['firstname']=__('First name is required'); if(!$vars['lastname']) $errors['lastname']=__('Last name is required'); if(!$vars['email'] || !Validator::is_valid_email($vars['email'])) $errors['email']=__('Valid email is required'); elseif(Email::getIdByEmail($vars['email'])) $errors['email']=__('Already in-use as system email'); elseif (($uid=static::getIdByEmail($vars['email'])) && (!isset($this->staff_id) || $uid!=$this->getId())) $errors['email']=__('Email already in use by another agent'); if($vars['phone'] && !Validator::is_phone($vars['phone'])) $errors['phone']=__('Valid phone number is required'); if($vars['mobile'] && !Validator::is_phone($vars['mobile'])) $errors['mobile']=__('Valid phone number is required'); if($vars['default_signature_type']=='mine' && !$vars['signature']) $errors['default_signature_type'] = __("You don't have a signature"); // Update the user's password if requested if ($vars['passwd1']) { try { $this->setPassword($vars['passwd1'], $vars['cpasswd']); } catch (BadPassword $ex) { $errors['passwd1'] = $ex->getMessage(); } catch (PasswordUpdateFailed $ex) { // TODO: Add a warning banner or crash the update } } $vars['onvacation'] = isset($vars['onvacation']) ? 1 : 0; $this->firstname = $vars['firstname']; $this->lastname = $vars['lastname']; $this->email = $vars['email']; $this->phone = Format::phone($vars['phone']); $this->phone_ext = $vars['phone_ext']; $this->mobile = Format::phone($vars['mobile']); $this->signature = Format::sanitize($vars['signature']); $this->timezone = $vars['timezone']; $this->locale = $vars['locale']; $this->max_page_size = $vars['max_page_size']; $this->auto_refresh_rate = $vars['auto_refresh_rate']; $this->default_signature_type = $vars['default_signature_type']; $this->default_paper_size = $vars['default_paper_size']; $this->lang = $vars['lang']; $this->onvacation = $vars['onvacation']; if (isset($vars['avatar_code'])) $this->setExtraAttr('avatar', $vars['avatar_code']); if ($errors) return false; $_SESSION['::lang'] = null; TextDomain::configureForUser($this); // Update the config information $_config = new Config('staff.'.$this->getId()); $_config->updateAll(array( 'datetime_format' => $vars['datetime_format'], 'default_from_name' => $vars['default_from_name'], 'default_2fa' => $vars['default_2fa'], 'thread_view_order' => $vars['thread_view_order'], 'default_ticket_queue_id' => $vars['default_ticket_queue_id'], 'reply_redirect' => ($vars['reply_redirect'] == 'Queue') ? 'Queue' : 'Ticket', 'img_att_view' => ($vars['img_att_view'] == 'inline') ? 'inline' : 'download', 'editor_spacing' => ($vars['editor_spacing'] == 'double') ? 'double' : 'single' ) ); $this->_config = $_config->getInfo(); return $this->save(); } function updateTeams($membership, &$errors) { $dropped = array(); foreach ($this->teams as $TM) $dropped[$TM->team_id] = 1; reset($membership); foreach ($membership as $mem) { list($team_id, $alerts) = $mem; $member = $this->teams->findFirst(array('team_id' => $team_id)); if (!$member) { $this->teams->add($member = new TeamMember(array( 'team_id' => $team_id, ))); } $member->setAlerts($alerts); if (!$errors) $member->save(); unset($dropped[$member->team_id]); } if (!$errors && $dropped) { $member = $this->teams ->filter(array('team_id__in' => array_keys($dropped))) ->delete(); $this->teams->reset(); } return true; } function delete() { global $thisstaff; if (!$thisstaff || $this->getId() == $thisstaff->getId()) return false; if (!parent::delete()) return false; $type = array('type' => 'deleted'); Signal::send('object.deleted', $this, $type); // DO SOME HOUSE CLEANING //Move remove any ticket assignments...TODO: send alert to Dept. manager? Ticket::objects() ->filter(array('staff_id' => $this->getId())) ->update(array('staff_id' => 0)); //Update the poster and clear staff_id on ticket thread table. ThreadEntry::objects() ->filter(array('staff_id' => $this->getId())) ->update(array( 'staff_id' => 0, 'poster' => $this->getName()->getOriginal(), )); // Cleanup Team membership table. TeamMember::objects() ->filter(array('staff_id'=>$this->getId())) ->delete(); // Cleanup staff dept access StaffDeptAccess::objects() ->filter(array('staff_id'=>$this->getId())) ->delete(); return true; } /**** Static functions ********/ static function lookup($var) { if (is_array($var)) return parent::lookup($var); elseif (is_numeric($var)) return parent::lookup(array('staff_id' => (int) $var)); elseif (Validator::is_email($var)) return parent::lookup(array('email' => $var)); elseif (is_string($var) && Validator::is_username($var)) return parent::lookup(array('username' => (string) $var)); else return null; } static function getStaffMembers($criteria=array()) { global $cfg; $members = static::objects(); if (isset($criteria['available'])) { $members = $members->filter(array( 'onvacation' => 0, 'isactive' => 1, )); } // Restrict agents based on visibility of the assigner if (($staff=$criteria['staff'])) $members = $staff->applyDeptVisibility($members); $members = self::nsort($members); $users=array(); foreach ($members as $M) { $users[$M->getId()] = $M->getName(); } return $users; } static function getAvailableStaffMembers() { return self::getStaffMembers(array('available'=>true)); } //returns agents in departments this agent has access to function getDeptAgents($criteria=array()) { $agents = static::objects() ->distinct('staff_id') ->select_related('dept') ->select_related('dept_access'); $agents = $this->applyDeptVisibility($agents); if (isset($criteria['available'])) { $agents = $agents->filter(array( 'onvacation' => 0, 'isactive' => 1, )); } $agents = self::nsort($agents); if (isset($criteria['namesOnly'])) { $clean = array(); foreach ($agents as $a) { $clean[$a->getId()] = $a->getName(); } return $clean; } return $agents; } static function getsortby($path='', $format=null) { global $cfg; $format = $format ?: $cfg->getAgentNameFormat(); switch ($format) { case 'last': case 'lastfirst': case 'legal': $fields = array("{$path}lastname", "{$path}firstname"); break; default: $fields = array("${path}firstname", "${path}lastname"); } return $fields; } static function nsort(QuerySet $qs, $path='', $format=null) { $fields = self::getsortby($path, $format); $qs->order_by($fields); return $qs; } static function getIdByUsername($username) { $row = static::objects()->filter(array('username' => $username)) ->values_flat('staff_id')->first(); return $row ? $row[0] : 0; } static function getIdByEmail($email) { $row = static::objects()->filter(array('email' => $email)) ->values_flat('staff_id')->first(); return $row ? $row[0] : 0; } static function create($vars=false) { $staff = new static($vars); $staff->created = SqlFunction::NOW(); return $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', $log=true) { global $ost, $cfg; $content = Page::lookupByType($template); $token = Misc::randCode(48); // 290-bits if (!$content) return new BaseError(/* @trans */ 'Unable to retrieve password reset email template'); $vars = array( 'url' => $ost->getConfig()->getBaseUrl(), 'token' => $token, 'staff' => $this, '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'=>$log); 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); $lang = $this->lang ?: $this->getExtraAttr('browser_lang'); $msg = $ost->replaceTemplateVariables(array( 'subj' => $content->getLocalName($lang), 'body' => $content->getLocalBody($lang), ), $vars); $_config = new Config('pwreset'); $_config->set($vars['token'], $this->getId()); $email->send($this->getEmail(), Format::striptags($msg['subj']), $msg['body']); } static function importCsv($stream, $defaults=array(), $callback=false) { require_once INCLUDE_DIR . 'class.import.php'; $importer = new CsvImporter($stream); $imported = 0; $fields = array( 'firstname' => new TextboxField(array( 'label' => __('First Name'), )), 'lastname' => new TextboxField(array( 'label' => __('Last Name'), )), 'email' => new TextboxField(array( 'label' => __('Email Address'), 'configuration' => array( 'validator' => 'email', ), )), 'username' => new TextboxField(array( 'label' => __('Username'), 'validators' => function($self, $value) { if (!Validator::is_username($value)) $self->addError('Not a valid username'); }, )), ); $form = new SimpleForm($fields); try { db_autocommit(false); $errors = array(); $records = $importer->importCsv($form->getFields(), $defaults); foreach ($records as $data) { if (!isset($data['email']) || !isset($data['username'])) throw new ImportError('Both `username` and `email` fields are required'); if ($agent = self::lookup(array('username' => $data['username']))) { // TODO: Update the user } elseif ($agent = self::create($data, $errors)) { if ($callback) $callback($agent, $data); $agent->save(); } else { throw new ImportError(sprintf(__('Unable to import (%s): %s'), Format::htmlchars($data['username']), print_r(Format::htmlchars($errors), true) )); } $imported++; } db_autocommit(true); } catch (Exception $ex) { db_rollback(); return $ex->getMessage(); } return $imported; } function save($refetch=false) { if ($this->dirty) $this->updated = SqlFunction::NOW(); return parent::save($refetch || $this->dirty); } function update($vars, &$errors) { $vars['username']=Format::striptags($vars['username']); $vars['firstname']=Format::striptags($vars['firstname']); $vars['lastname']=Format::striptags($vars['lastname']); if (isset($this->staff_id) && $this->getId() != $vars['id']) $errors['err']=__('Internal error occurred'); if(!$vars['firstname']) $errors['firstname']=__('First name required'); 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'); elseif (($uid=static::getIdByUsername($vars['username'])) && (!isset($this->staff_id) || $uid!=$this->getId())) $errors['username']=__('Username already in use'); if(!$vars['email'] || !Validator::is_valid_email($vars['email'])) $errors['email']=__('Valid email is required'); elseif(Email::getIdByEmail($vars['email'])) $errors['email']=__('Already in use system email'); elseif (($uid=static::getIdByEmail($vars['email'])) && (!isset($this->staff_id) || $uid!=$this->getId())) $errors['email']=__('Email already in use by another agent'); if($vars['phone'] && !Validator::is_phone($vars['phone'])) $errors['phone']=__('Valid phone number is required'); if($vars['mobile'] && !Validator::is_phone($vars['mobile'])) $errors['mobile']=__('Valid phone number is required'); if(!$vars['dept_id']) $errors['dept_id']=__('Department is required'); if(!$vars['role_id']) $errors['role_id']=__('Role for primary department is required'); $dept = Dept::lookup($vars['dept_id']); if($dept && !$dept->isActive()) $errors['dept_id'] = sprintf(__('%s selected must be active'), __('Department')); // Ensure we will still have an administrator with access if ($vars['isadmin'] !== '1' || $vars['islocked'] === '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 == $uid) { $errors['isadmin'] = __( 'Cowardly refusing to remove or lock out the only active administrator' ); } } } // Update the local permissions $this->updatePerms($vars['perms'], $errors); //checkboxes $vars['isadmin'] = isset($vars['isadmin']) ? 1 : 0; $vars['islocked'] = isset($vars['islocked']) ? 0 : 1; $vars['isvisible'] = isset($vars['isvisible']) ? 1 : 0; $vars['onvacation'] = isset($vars['onvacation']) ? 1 : 0; $vars['assigned_only'] = isset($vars['assigned_only']) ? 1 : 0; $this->isadmin = $vars['isadmin']; $this->isactive = $vars['islocked']; $this->isvisible = $vars['isvisible']; $this->onvacation = $vars['onvacation']; $this->assigned_only = $vars['assigned_only']; $this->role_id = $vars['role_id']; $this->username = $vars['username']; $this->firstname = $vars['firstname']; $this->lastname = $vars['lastname']; $this->email = $vars['email']; $this->backend = $vars['backend']; $this->phone = Format::phone($vars['phone']); $this->phone_ext = $vars['phone_ext']; $this->mobile = Format::phone($vars['mobile']); $this->notes = Format::sanitize($vars['notes']); // Set staff password if exists if (!$vars['welcome_email'] && $vars['passwd1']) { $this->setPassword($vars['passwd1'], null); $this->change_passwd = $vars['change_passwd'] ? 1 : 0; } if ($errors) return false; if ($this->save()) { // Update some things for ::updateAccess to inspect $this->setDepartmentId($vars['dept_id']); // Format access update as [array(dept_id, role_id, alerts?)] $access = array(); if (isset($vars['dept_access'])) { foreach (@$vars['dept_access'] as $dept_id) { $access[] = array($dept_id, $vars['dept_access_role'][$dept_id], @$vars['dept_access_alerts'][$dept_id]); } } $this->updateAccess($access, $errors); $this->setExtraAttr('def_assn_role', isset($vars['assign_use_pri_role']), true); // Format team membership as [array(team_id, alerts?)] $teams = array(); if (isset($vars['teams'])) { foreach (@$vars['teams'] as $team_id) { $teams[] = array($team_id, @$vars['team_alerts'][$team_id]); } } $this->updateTeams($teams, $errors); if ($vars['welcome_email']) $this->sendResetEmail('registration-staff', false); return true; } if (isset($this->staff_id)) { $errors['err']=sprintf(__('Unable to update %s.'), __('this agent')) .' '.__('Internal error occurred'); } else { $errors['err']=sprintf(__('Unable to create %s.'), __('this agent')) .' '.__('Internal error occurred'); } return false; } /** * Parameters: * $access - (<array($dept_id, $role_id, $alerts)>) a list of the complete, * extended access for this agent. Any the agent currently has, which * is not listed will be removed. * $errors - (<array>) list of error messages from the process, which will * be indexed by the dept_id number. */ function updateAccess($access, &$errors) { reset($access); $dropped = array(); foreach ($this->dept_access as $DA) $dropped[$DA->dept_id] = 1; foreach ($access as $acc) { list($dept_id, $role_id, $alerts) = $acc; unset($dropped[$dept_id]); if (!$role_id || !Role::lookup($role_id)) $errors['dept_access'][$dept_id] = __('Select a valid role'); if (!$dept_id || !($dept=Dept::lookup($dept_id))) $errors['dept_access'][$dept_id] = __('Select a valid department'); if ($dept_id == $this->getDeptId()) $errors['dept_access'][$dept_id] = sprintf(__('Agent already has access to %s'), __('this department')); $da = $this->dept_access->findFirst(array('dept_id' => $dept_id)); if (!isset($da)) { $da = new StaffDeptAccess(array( 'dept_id' => $dept_id, 'role_id' => $role_id )); $this->dept_access->add($da); $type = array('type' => 'edited', 'key' => sprintf('%s Department Access Added', $dept->getName())); Signal::send('object.edited', $this, $type); } else { $da->role_id = $role_id; } $da->setAlerts($alerts); if (!$errors) $da->save(); } if (!$errors && $dropped) { $this->dept_access ->filter(array('dept_id__in' => array_keys($dropped))) ->delete(); $this->dept_access->reset(); foreach (array_keys($dropped) as $dept_id) { $deptName = Dept::getNameById($dept_id); $type = array('type' => 'edited', 'key' => sprintf('%s Department Access Removed', $deptName)); Signal::send('object.edited', $this, $type); } } return !$errors; } function updatePerms($vars, &$errors=array()) { if (!$vars) { $this->permissions = ''; return; } $permissions = $this->getPermission(); foreach ($vars as $k => $val) { if (!$permissions->exists($val)) { $type = array('type' => 'edited', 'key' => $val); Signal::send('object.edited', $this, $type); } } foreach (RolePermission::allPermissions() as $g => $perms) { foreach ($perms as $k => $v) { if (!in_array($k, $vars) && $permissions->exists($k)) { $type = array('type' => 'edited', 'key' => $k); Signal::send('object.edited', $this, $type); } $permissions->set($k, in_array($k, $vars) ? 1 : 0); } } $this->permissions = $permissions->toJson(); return true; } static function export($criteria=null, $filename='') { include_once(INCLUDE_DIR.'class.error.php'); $agents = Staff::objects(); // Sort based on name formating $agents = self::nsort($agents); Export::agents($agents, $filename); } static function getPermissions() { return self::$perms; } } RolePermission::register(/* @trans */ 'Miscellaneous', Staff::getPermissions()); interface RestrictedAccess { function checkStaffPerm($staff); } class StaffDeptAccess extends VerySimpleModel { static $meta = array( 'table' => STAFF_DEPT_TABLE, 'pk' => array('staff_id', 'dept_id'), 'select_related' => array('dept', 'role'), 'joins' => array( 'dept' => array( 'constraint' => array('dept_id' => 'Dept.id'), ), 'staff' => array( 'constraint' => array('staff_id' => 'Staff.staff_id'), ), 'role' => array( 'constraint' => array('role_id' => 'Role.id'), ), ), ); const FLAG_ALERTS = 0x0001; function isAlertsEnabled() { return $this->flags & self::FLAG_ALERTS != 0; } function setFlag($flag, $value) { if ($value) $this->flags |= $flag; else $this->flags &= ~$flag; } function setAlerts($value) { $this->setFlag(self::FLAG_ALERTS, $value); } } /** * This form is used to administratively change the password. The * ChangePasswordForm is used for an agent to change their own password. */ class PasswordResetForm extends AbstractForm { function buildFields() { return array( 'welcome_email' => new BooleanField(array( 'default' => true, 'configuration' => array( 'desc' => __('Send the agent a password reset email'), ), )), 'passwd1' => new PasswordField(array( 'placeholder' => __('New Password'), 'required' => true, 'configuration' => array( 'classes' => 'span12', 'length' => '128', ), 'visibility' => new VisibilityConstraint( new Q(array('welcome_email' => false)), VisibilityConstraint::HIDDEN ), 'validator' => '', 'validators' => function($self, $v) { try { Staff::checkPassword($v, null); } catch (BadPassword $ex) { $self->addError($ex->getMessage()); } }, )), 'passwd2' => new PasswordField(array( 'placeholder' => __('Confirm Password'), 'required' => true, 'configuration' => array( 'classes' => 'span12', 'length' => '128', ), 'visibility' => new VisibilityConstraint( new Q(array('welcome_email' => false)), VisibilityConstraint::HIDDEN ), 'validator' => '', 'validators' => function($self, $v) { try { Staff::checkPassword($v, null); } catch (BadPassword $ex) { $self->addError($ex->getMessage()); } }, )), 'change_passwd' => new BooleanField(array( 'default' => true, 'configuration' => array( 'desc' => __('Require password change at next login'), 'classes' => 'form footer', ), 'visibility' => new VisibilityConstraint( new Q(array('welcome_email' => false)), VisibilityConstraint::HIDDEN ), )), ); } function validate($clean) { if ($clean['passwd1'] != $clean['passwd2']) $this->getField('passwd1')->addError(__('Passwords do not match')); } } class PasswordChangeForm extends AbstractForm { function buildFields() { $fields = array( 'current' => new PasswordField(array( 'placeholder' => __('Current Password'), 'required' => true, 'configuration' => array( 'autofocus' => true, 'length' => '128', ), 'validator' => 'noop', )), 'passwd1' => new PasswordField(array( 'label' => __('Enter a new password'), 'placeholder' => __('New Password'), 'required' => true, 'configuration' => array( 'length' => '128', ), 'validator' => '', 'validators' => function($self, $v) { try { Staff::checkPassword($v, null); } catch (BadPassword $ex) { $self->addError($ex->getMessage()); } }, )), 'passwd2' => new PasswordField(array( 'placeholder' => __('Confirm Password'), 'required' => true, 'configuration' => array( 'length' => '128', ), 'validator' => '', 'validators' => function($self, $v) { try { Staff::checkPassword($v, null); } catch (BadPassword $ex) { $self->addError($ex->getMessage()); } }, )), ); // When using the password reset system, the current password is not // required for agents. if (isset($_SESSION['_staff']['reset-token'])) { unset($fields['current']); $fields['passwd1']->set('configuration', array('autofocus' => true)); } else { $fields['passwd1']->set('layout', new GridFluidCell(12, array('style' => 'padding-top: 20px')) ); } return $fields; } function getInstructions() { return __('Confirm your current password and enter a new password to continue'); } function validate($clean) { global $thisstaff; if (isset($clean['current']) && !$thisstaff->cmp_passwd($clean['current'])) $this->getField('current')->addError(__('Current password is incorrect.')); if ($clean['passwd1'] != $clean['passwd2']) $this->getField('passwd1')->addError(__('Passwords do not match')); } } class ResetAgentPermissionsForm extends AbstractForm { function buildFields() { $permissions = array(); foreach (RolePermission::allPermissions() as $g => $perms) { foreach ($perms as $k => $v) { if (!$v['primary']) continue; $permissions[$g][$k] = "{$v['title']} — {$v['desc']}"; } } return array( 'clone' => new ChoiceField(array( 'default' => 0, 'choices' => array(0 => '— '.__('Clone an existing agent').' —') + Staff::getStaffMembers(), 'configuration' => array( 'classes' => 'span12', ), )), 'perms' => new ChoiceField(array( 'choices' => $permissions, 'widget' => 'TabbedBoxChoicesWidget', 'configuration' => array( 'multiple' => true, ), )), ); } function getClean($validate = true) { $clean = parent::getClean(); // Index permissions as ['ticket.edit' => 1] $clean['perms'] = array_keys($clean['perms']); return $clean; } function render($staff=true, $title=false, $options=array()) { return parent::render($staff, $title, $options + array('template' => 'dynamic-form-simple.tmpl.php')); } } class ChangeDepartmentForm extends AbstractForm { function buildFields() { return array( 'dept_id' => new ChoiceField(array( 'default' => 0, 'required' => true, 'label' => __('Primary Department'), 'choices' => array(0 => '— '.__('Primary Department').' —') + Dept::getDepartments(), 'configuration' => array( 'classes' => 'span12', ), )), 'role_id' => new ChoiceField(array( 'default' => 0, 'required' => true, 'label' => __('Primary Role'), 'choices' => array(0 => '— '.__('Corresponding Role').' —') + Role::getRoles(), 'configuration' => array( 'classes' => 'span12', ), )), 'eavesdrop' => new BooleanField(array( 'configuration' => array( 'desc' => __('Maintain access to current primary department'), 'classes' => 'form footer', ), )), // alerts? ); } function getInstructions() { return __('Change the primary department and primary role of the selected agents'); } function getClean($validate = true) { $clean = parent::getClean(); $clean['eavesdrop'] = $clean['eavesdrop'] ? 1 : 0; return $clean; } function render($staff=true, $title=false, $options=array()) { return parent::render($staff, $title, $options + array('template' => 'dynamic-form-simple.tmpl.php')); } } class StaffQuickAddForm extends AbstractForm { static $layout = 'GridFormLayout'; function buildFields() { global $cfg; return array( 'firstname' => new TextboxField(array( 'required' => true, 'configuration' => array( 'placeholder' => __("First Name"), 'autofocus' => true, ), 'layout' => new GridFluidCell(6), )), 'lastname' => new TextboxField(array( 'required' => true, 'configuration' => array( 'placeholder' => __("Last Name"), ), 'layout' => new GridFluidCell(6), )), 'email' => new TextboxField(array( 'required' => true, 'configuration' => array( 'validator' => 'email', 'placeholder' => __('Email Address — e.g. me@mycompany.com'), 'length' => 128, 'autocomplete' => 'email', ), )), 'dept_id' => new ChoiceField(array( 'label' => __('Department'), 'required' => true, 'choices' => Dept::getDepartments(), 'default' => $cfg->getDefaultDeptId(), 'layout' => new GridFluidCell(6), )), 'role_id' => new ChoiceField(array( 'label' => __('Primary Role'), 'required' => true, 'choices' => Role::getRoles(), 'layout' => new GridFluidCell(6), )), 'isadmin' => new BooleanField(array( 'label' => __('Account Type'), 'configuration' => array( 'desc' => __('Agent has access to the admin panel'), ), 'layout' => new GridFluidCell(6), )), 'welcome_email' => new BooleanField(array( 'configuration' => array( 'desc' => __('Send a welcome email with login information'), ), 'default' => true, 'layout' => new GridFluidCell(12, array('style' => 'padding-top: 50px')), )), 'passwd1' => new PasswordField(array( 'required' => true, 'configuration' => array( 'placeholder' => __("Temporary Password"), 'autocomplete' => 'new-password', ), 'validator' => '', 'validators' => function($self, $v) { try { Staff::checkPassword($v, null); } catch (BadPassword $ex) { $self->addError($ex->getMessage()); } }, 'visibility' => new VisibilityConstraint( new Q(array('welcome_email' => false)) ), 'layout' => new GridFluidCell(6), )), 'passwd2' => new PasswordField(array( 'required' => true, 'configuration' => array( 'placeholder' => __("Confirm Password"), 'autocomplete' => 'new-password', ), 'visibility' => new VisibilityConstraint( new Q(array('welcome_email' => false)) ), 'layout' => new GridFluidCell(6), )), // TODO: Add role_id drop-down ); } function getClean($validate = true) { $clean = parent::getClean(); list($clean['username'],) = preg_split('/[^\w.-]/u', $clean['email'], 2); if (mb_strlen($clean['username']) < 3 || Staff::lookup($clean['username'])) $clean['username'] = mb_strtolower($clean['firstname']); // Inherit default dept's role as primary role $clean['assign_use_pri_role'] = true; // Default permissions $clean['perms'] = array( User::PERM_CREATE, User::PERM_EDIT, User::PERM_DELETE, User::PERM_MANAGE, User::PERM_DIRECTORY, Organization::PERM_CREATE, Organization::PERM_EDIT, Organization::PERM_DELETE, FAQ::PERM_MANAGE, Dept::PERM_DEPT, Staff::PERM_STAFF, ); return $clean; } }
Save