classes/Gems/User/User.php
<?php
/**
*
* @package Gems
* @subpackage user
* @author Matijs de Jong <mjong@magnafacta.nl>
* @copyright Copyright (c) 2011 Erasmus MC
* @license New BSD License
*/
use Gems\User\Group;
use Gems\User\Embed\EmbeddedAuthInterface;
use Gems\User\Embed\EmbeddedUserData;
use Gems\User\TwoFactor\TwoFactorAuthenticatorInterface;
use Laminas\Authentication\Result;
use Laminas\Authentication\Adapter\AdapterInterface;
/**
* User object that mimmicks the old $this->session behaviour
*
* @package Gems
* @subpackage User
* @copyright Copyright (c) 2011 Erasmus MC
* @license New BSD License
* @since Class available since version 1.5
*/
class Gems_User_User extends \MUtil_Translate_TranslateableAbstract
{
/**
*
* @var TwoFactorAuthenticatorInterface
*/
protected $_authenticator;
/**
*
* @var Laminas\Authentication\Result
*/
protected $_authResult;
/**
*
* @var Gems\User\Embed\EmbeddedUserData
*/
protected $_embedderData;
/**
*
* @var \Gems\User\Group
*/
protected $_group;
/**
*
* @var \ArrayObject or \Zend_Session_Namespace
*/
private $_vars;
/**
* Required
*
* @var \MUtil_Acl
*/
protected $acl;
/**
*
* @var \Gems_Util_BasePath
*/
protected $basepath;
/**
* Required
*
* @var \Zend_Db_Adapter_Abstract
*/
protected $db;
/**
*
* @var string
*/
protected $defaultAuthenticatorClass = 'GoogleAuthenticator';
/**
* Required, set in constructor
*
* @var \Gems_User_UserDefinitionInterface
*/
protected $definition;
/**
* Sets number failed accounts that trigger a block
*
* @var int
*/
protected $failureBlockCount = 6;
/**
* Sets number of seconds until a previous failed login can be ignored
*
* @var int
*/
protected $failureIgnoreTime = 600;
/**
*
* @var \Gems_Loader
*/
protected $loader;
/**
*
* @var \Zend_Locale
*/
protected $locale;
/**
* Array containing the parameter names that may point to an organization
*
* @var array
*/
public $possibleOrgIds = array(
\MUtil_Model::REQUEST_ID2,
'gr2o_id_organization',
'gr2t_id_organization',
'gap_id_organization',
'gto_id_organization',
'gor_id_organization',
'gla_organization',
'grco_organization',
);
/**
*
* @var \Gems_Project_ProjectSettings
*/
protected $project;
/**
*
* @var \Zend_Controller_Request_Abstract
*/
protected $request;
/**
* Required
*
* @var \Zend_Session_Namespace
*/
protected $session;
/**
* Required
*
* @var \Gems_User_UserLoader
*/
protected $userLoader;
/**
*
* @var \Gems_Util
*/
protected $util;
/**
* Creates the class for this user.
*
* @param mixed $settings Array, \Zend_Session_Namespace or \ArrayObject for this user.
* @param \Gems_User_UserDefinitionInterface $definition The user class definition.
*/
public function __construct($settings, \Gems_User_UserDefinitionInterface $definition)
{
if (is_array($settings)) {
$this->_vars = new \ArrayObject($settings);
$this->_vars->setFlags(\ArrayObject::STD_PROP_LIST);
} else {
$this->_vars = $settings;
}
$this->definition = $definition;
// \MUtil_Echo::track($settings);
}
/**
* Helper function for setcurrentOrganization
*
* Change value to $newId in an array if the key is in the $keys array (as key) and value is $oldId
*
* @param array $array
* @param int $oldId
* @param int $newId
* @param array $keys
* @return array
*/
protected function _changeIds($array, $oldId, $newId, $keys) {
if (!is_array($array)) {
return $array;
}
$matches = array_intersect_key($array, $keys);
foreach($matches as $key => &$curId) {
if ($curId == $oldId) {
$array[$key] = $newId;
}
}
return $array;
}
/**
* Get a role with a check on the value in case of integers
*
* @param string $roleField
* @return mixed
*/
protected function _getRole($roleField)
{
$role = $this->_getVar($roleField);
if (intval($role)) {
$role = \Gems_Roles::getInstance()->translateToRoleName($role);
$this->_setVar($roleField, $role);
}
return $role;
}
/**
* Get a value in whatever store is used by this object.
*
* @param string $name
* @return mixed
*/
protected function _getVar($name)
{
$store = $this->_getVariableStore();
if ($store instanceof \Zend_Session_Namespace) {
if ($store->__isset($name)) {
return $store->__get($name);
}
} else {
if ($store->offsetExists($name)) {
return $store->offsetGet($name);
}
}
return null;
}
/**
* The store currently used.
*
* @return \ArrayObject or \Zend_Session_Namespace
*/
private function _getVariableStore()
{
return $this->_vars;
}
/**
* Checks for existence of a value in whatever store is used by this object.
*
* @param string $name
* @return boolean
*/
protected function _hasVar($name)
{
$store = $this->_getVariableStore();
if ($store instanceof \Zend_Session_Namespace) {
return $store->__isset($name);
} else {
return $store->offsetExists($name);
}
}
/**
* Sets a value in whatever store is used by this object.
*
* @param string $name
* @param mixed $value
* @return void
*/
protected function _setVar($name, $value)
{
$store = $this->_getVariableStore();
if ($store instanceof \Zend_Session_Namespace) {
$store->__set($name, $value);
} else {
$store->offsetSet($name, $value);
}
}
/**
* Sets a value in whatever store is used by this object.
*
* @param string $name
* @return void
*/
protected function _unsetVar($name)
{
$store = $this->_getVariableStore();
if ($store instanceof \Zend_Session_Namespace) {
$store->__unset($name);
} else {
if ($store->offsetExists($name)) {
$store->offsetUnset($name);
}
}
}
/**
* Process everything after authentication.
*
* @param Laminas\Authentication\Result $result
*/
protected function afterAuthorization(Result $result, $lastAuthorizer = null)
{
try {
$select = $this->db->select();
$select->from('gems__user_login_attempts', array('gula_failed_logins', 'gula_last_failed', 'gula_block_until', new \Zend_Db_Expr('UNIX_TIMESTAMP() - UNIX_TIMESTAMP(gula_last_failed) AS since_last')))
->where('gula_login = ?', $this->getLoginName())
->where('gula_id_organization = ?', $this->getCurrentOrganizationId())
->limit(1);
$values = $this->db->fetchRow($select);
// The first login attempt
if (! $values) {
$values['gula_login'] = $this->getLoginName();
$values['gula_id_organization'] = $this->getCurrentOrganizationId();
$values['gula_failed_logins'] = 0;
$values['gula_last_failed'] = null;
$values['gula_block_until'] = null;
$values['since_last'] = $this->failureIgnoreTime + 1;
}
if ($result->isValid()) {
// Reset login failures
$values['gula_failed_logins'] = 0;
$values['gula_last_failed'] = null;
$values['gula_block_until'] = null;
} else {
// Reset the counters when the last login was longer ago than the delay factor
if ($values['since_last'] > $this->failureIgnoreTime) {
$values['gula_failed_logins'] = 1;
} elseif ($lastAuthorizer === 'pwd') {
// Only increment failed login when password failed
$values['gula_failed_logins'] += 1;
}
// If block is already set
if ($values['gula_block_until']) {
// Do not change it anymore
unset($values['gula_block_until']);
} else {
// Only set the block when needed
if ($this->failureBlockCount <= $values['gula_failed_logins']) {
$values['gula_block_until'] = new \Zend_Db_Expr('DATE_ADD(CURRENT_TIMESTAMP, INTERVAL ' . $this->failureIgnoreTime . ' SECOND)');
}
}
// Always record the last fail
$values['gula_last_failed'] = new \MUtil_Db_Expr_CurrentTimestamp();
$values['gula_failed_logins'] = max(1, $values['gula_failed_logins']);
// Response gets slowly slower
$sleepTime = min($values['gula_failed_logins'] - 1, 10) * 2;
sleep($sleepTime);
// \MUtil_Echo::track($sleepTime, $values, $result->getMessages());
}
// Value not saveable
unset($values['since_last']);
if (isset($values['gula_login'])) {
$this->db->insert('gems__user_login_attempts', $values);
} else {
$where = $this->db->quoteInto('gula_login = ? AND ', $this->getLoginName());
$where .= $this->db->quoteInto('gula_id_organization = ?', $this->getCurrentOrganizationId());
$this->db->update('gems__user_login_attempts', $values, $where);
}
} catch (\Zend_Db_Exception $e) {
// Fall through as this does not work if the database upgrade did not yet run
// \MUtil_Echo::r($e);
}
}
/**
*
* @param array $row
* @return array $row
*/
public function applyGroupMask(array $row)
{
$group = $this->getGroup();
if (! $group) {
return $row;
}
return $group->applyGroupToData($row);
}
/**
* Function where the layout and style can be set, called in GemsEscort->prepareController()
*
* @param \GemsEscort $escort
* @return $this
*/
public function applyLayoutSettings(\GemsEscort $escort)
{
if ($this->_hasVar('current_user_crumbs')) {
// \MUtil_Echo::track($this->_getVar('current_user_crumbs'));
switch ($this->_getVar('current_user_crumbs')) {
case 'no_display':
$this->project['layoutPrepare']['crumbs'] = null;
break;
case 'no_top':
$this->project['layoutPrepareArgs']['crumbs']['always' ] = 1;
$this->project['layoutPrepareArgs']['crumbs']['hideTop' ] = 1;
break;
}
}
if ($this->_hasVar('current_user_layout')) {
$layout = $escort->layout;
$usedLayout = $this->_getVar('current_user_layout');
if ($usedLayout && $layout instanceof \Zend_Layout) {
$layout->setLayout($usedLayout);
}
}
if ($escort instanceof \Gems_Project_Layout_MultiLayoutInterface) {
if ($this->_hasVar('current_user_style')) {
$style = $this->_getVar('current_user_style');
} else {
$style = null;
}
// Cookie org is often either \Gems_User_UserLoader::SYSTEM_NO_ORG (-1) or 0 if not set
if (! ($style || \Gems_Cookies::getOrganization($this->getRequest()) > 0)) {
$site = $this->util->getSites()->getSiteForCurrentUrl();
if ($site) {
$style = $site->getStyle();
}
}
if (! $style) {
$style = $this->getCurrentOrganization()->getStyle();
}
$escort->layoutSwitch($style);
}
return $this;
}
/**
* Set menu parameters from this user
*
* @param \Gems_Menu_ParameterSource $source
* @return \Gems_User_User
*/
public function applyToMenuSource(\Gems_Menu_ParameterSource $source)
{
$source->offsetSet('gsf_id_organization', $this->getBaseOrganizationId());
$source->offsetSet('gsf_active', $this->isActive() ? 1 : 0);
$source->offsetSet('accessible_role', $this->inAllowedGroup() ? 1 : 0);
$source->offsetSet('can_mail', $this->hasEmailAddress() ? 1 : 0);
$source->offsetSet('has_2factor', $this->isTwoFactorEnabled() ? 2 : 0);
}
/**
*
* @param string $fieldName1 First of unlimited number of field names
* @return boolean True if this field is invisible
*/
public function areAllFieldsInvisible($fieldName1, $fieldName2 = null)
{
$group = $this->getGroup();
if (! $group) {
return false;
}
foreach (func_get_args() as $fieldName) {
if (! $group->isFieldInvisible($fieldName)) {
return false;
}
}
return true;
}
/**
*
* @param string $fieldName1 First of unlimited number of field names
* @return boolean True if this field is partially (or wholly) masked (or invisible)
*/
public function areAllFieldsMaskedPartial($fieldName1, $fieldName2 = null)
{
$group = $this->getGroup();
if (! $group) {
return false;
}
foreach (func_get_args() as $fieldName) {
if (! $group->isFieldMaskedPartial($fieldName)) {
return false;
}
}
return true;
}
/**
*
* @param string $fieldName1 First of unlimited number of field names
* @return boolean True if this field is wholly masked (or invisible)
*/
public function areAllFieldsMaskedWhole($fieldName1, $fieldName2 = null)
{
$group = $this->getGroup();
if (! $group) {
return false;
}
foreach (func_get_args() as $fieldName) {
if (! $group->isFieldMaskedWhole($fieldName)) {
return false;
}
}
return true;
}
/**
* Authenticate a users credentials using the submitted form
*
* @param string $password The password to test
* @param boolean $testPassword Set to false to test the non-password checks only
* @return Laminas\Authentication\Result
*/
public function authenticate($password, $testPassword = true)
{
$auths = $this->loadAuthorizers($password, $testPassword);
$lastAuthorizer = null;
foreach ($auths as $lastAuthorizer => $result) {
if (is_callable($result)) {
$result = call_user_func($result);
}
if ($result instanceof AdapterInterface) {
$result = $result->authenticate();
}
if ($result instanceof Result) {
if (! $result->isValid()) {
break;
}
} else {
if (true === $result) {
$result = new Result(Result::SUCCESS, $this->getLoginName());
} else {
// Always a fail when not true
if ($result === false) {
$code = Result::FAILURE_CREDENTIAL_INVALID;
$result = array();
} else {
$code = Result::FAILURE_UNCATEGORIZED;
if (is_string($result)) {
$result = array($result);
}
}
$result = new Result($code, $this->getLoginName(), $result);
break;
}
}
}
if ($result->isValid() && $this->definition instanceof \Gems_User_DbUserDefinitionAbstract) {
$this->definition->checkRehash($this, $password);
}
$this->afterAuthorization($result, $lastAuthorizer);
// \MUtil_Echo::track($result);
$this->_authResult = $result;
return $result;
}
/**
* Checks if the user is allowed to login or is blocked
*
* An adapter authorizes and if the end resultis boolean, string or array
* it is converted into a Laminas\Authenticate\Result.
*
* @return mixed Laminas\Authentication\Adapter\AdapterInterface|Laminas\Authenticate\Result|boolean|string|array
*/
protected function authorizeBlock()
{
try {
$select = $this->db->select();
$select->from('gems__user_login_attempts', new \Zend_Db_Expr('UNIX_TIMESTAMP(gula_block_until) - UNIX_TIMESTAMP() AS wait'))
->where('gula_block_until is not null')
->where('gula_login = ?', $this->getLoginName())
->where('gula_id_organization = ?', $this->getCurrentOrganizationId())
->limit(1);
// Not the first login
if ($block = $this->db->fetchOne($select)) {
if ($block > 0) {
$minutes = intval($block / 60) + 1;
// Report all is not well
return sprintf($this->plural('Your account is temporarily blocked, please wait a minute.', 'Your account is temporarily blocked, please wait %d minutes.', $minutes), $minutes);
} else {
// Clean the block once it's past
$values['gula_failed_logins'] = 0;
$values['gula_last_failed'] = null;
$values['gula_block_until'] = null;
$where = $this->db->quoteInto('gula_login = ? AND ', $this->getLoginName());
$where .= $this->db->quoteInto('gula_id_organization = ?', $this->getCurrentOrganizationId());
$this->db->update('gems__user_login_attempts', $values, $where);
}
}
} catch (\Zend_Db_Exception $e) {
// Fall through as this does not work if the database upgrade did not run
// \MUtil_Echo::r($e);
}
return true;
}
/**
* Checks if the user is allowed to login using the current IP address
* according to the group he is in
*
* An adapter authorizes and if the end resultis boolean, string or array
* it is converted into a Laminas\Authenticate\Result.
*
* @return mixed Laminas\Authentication\Adapter\AdapterInterface|Laminas\Authenticate\Result|boolean|string|array
*/
protected function authorizeIp()
{
//In unit test REMOTE_ADDR is not available and will return null
$request = $this->getRequest();
// E.g. command line user
if (! $request instanceof \Zend_Controller_Request_Http) {
return true;
}
$remoteIp = $request->getClientIp();
if ($this->util->isAllowedIP($remoteIp, $this->getAllowedIPRanges())) {
return true;
}
return $this->_('You are not allowed to login from this location.');
}
/**
* Checks if the user is allowed to login using the current IP address
* according to his BASE organization
*
* An adapter authorizes and if the end resultis boolean, string or array
* it is converted into a Laminas\Authenticate\Result.
*
* @return mixed Laminas\Authentication\Adapter\AdapterInterface|Laminas\Authenticate\Result|boolean|string|array
*/
protected function authorizeOrgIp()
{
//special case: project user should have no restriction
if ($this->project->getSuperAdminName() == $this->getLoginName()) {
return true;
}
//In unit test REMOTE_ADDR is not available and will return null
$request = $this->getRequest();
// E.g. command line user
if (! $request instanceof \Zend_Controller_Request_Http) {
return true;
}
$remoteIp = $request->getClientIp();
if ($this->util->isAllowedIP($remoteIp, $this->getBaseOrganization()->getAllowedIpRanges())) {
return true;
}
return $this->_('You are not allowed to login from this location.');
}
/**
* True when the current url is one where this user is allowed to login.
*
* If the url is a fixed organization url and the user is not allowed to
* access this organization, then this function returns false.
*
* @return boolean
*/
public function canLoginHere()
{
if (! $this->_hasVar('can_login_here')) {
$site = $this->util->getSites()->getSiteForCurrentUrl();
$this->_setVar('can_login_here', $site->hasUrlOrganizationsId($this->getCurrentOrganizationId()));
}
return $this->_getVar('can_login_here');
}
/**
* Return true if a password reset key can be created.
*
* @return boolean
*/
public function canResetPassword()
{
return $this->isActive() && $this->definition->canResetPassword($this);
}
/**
* Return true if the two factor can be set.
*
* @return boolean
*/
public function canSaveTwoFactorKey()
{
return $this->definition->canSaveTwoFactorKey();
}
/**
* Return true if the password can be set.
*
* @return boolean
*/
public function canSetPassword()
{
return $this->isActive() && $this->definition->canSetPassword();
}
/**
* Should be called after answering the request to allow the Target
* to check if all required registry values have been set correctly.
*
* @return boolean False if required values are missing.
*/
public function checkRegistryRequestsAnswers()
{
if (! (($this->db instanceof \Zend_Db_Adapter_Abstract) && ($this->session instanceof \Zend_Session_Namespace))) {
return false;
}
// Checks if this is the current user
if (! $this->_vars instanceof \Zend_Session_Namespace) {
$sessionStore = $this->session;
$notCurrent = true;
foreach (array('user_id', 'user_organization_id') as $key) {
if ($sessionStore->__isset($key) && $this->_vars->offsetExists($key)) {
$notCurrent = $sessionStore->__get($key) != $this->_vars->offsetGet($key);
} else {
$notCurrent = $sessionStore->__isset($key) || $this->_vars->offsetExists($key);
}
if ($notCurrent) {
break;
}
}
if (! $notCurrent) {
// When this is the case, use the \Zend_Session_Namespace object with the current set values
// This way changes to this user object are reflected in the CurrentUser object and vice versa.
$this->setAsCurrentUser();
}
}
// Change a numeric role id to it's string value
$this->_getRole('user_role');
if ($this->_hasVar('current_user_role')) {
$this->_getRole('current_user_role');
}
return (boolean) $this->acl && $this->userLoader;
}
/**
* Clear the two factor authentication key
*
* @return $this
*/
public function clearTwoFactorKey()
{
$this->_setVar('user_two_factor_key', null);
$this->definition->setTwoFactorKey($this, null);
return $this;
}
/**
* Disable mask usage (call before any applyGroupToData() or applyGroupToModel()
* calls: doesn't work retroactively
*
* @return $this
*/
public function disableMask()
{
$group = $this->getGroup();
if ($group instanceof Group) {
$group->disableMask();
}
return $this;
}
/**
* Enable mask usage (call before any applyGroupToData() or applyGroupToModel()
* calls: doesn't work retroactively
*
* @return $this
*/
public function enableMask()
{
$group = $this->getGroup();
if ($group instanceof Group) {
$group->enableMask();
}
return $this;
}
/**
* Returns the list of allowed IP ranges (separated by colon)
*
* @return string
*/
public function getAllowedIPRanges()
{
return $this->_getVar('user_allowed_ip_ranges');
}
/**
* Get an array of OrgId => Org Name for all allowed organizations for the current loggedin user
*
* @return array
*/
public function getAllowedOrganizations()
{
if (! $this->_hasVar('__allowedOrgs')) {
$this->refreshAllowedOrganizations();
}
// \MUtil_Echo::track($this->_getVar('__allowedOrgs'));
return $this->_getVar('__allowedOrgs');
}
/**
* Returns the current roles a user may set.
*
* NOTE! A user can set a role, unless it <em>requires a higher role level</em>.
*
* I.e. an admin is not allowed to set a super role as super inherits and expands admin. But it is
* allowed to set the nologin and respondent roles that are not inherited by the admin as they are
* in a different hierarchy.
*
* An exception is the role master as it is set by the system. You gotta be a master to set the master
* role.
*
* @return array With identical keys and values roleId => roleId
*/
public function getAllowedRoles()
{
$userRole = $this->getRole();
if ($userRole === 'master') {
$output = $this->acl->getRoles();
return array_combine($output, $output);
}
$output = array($userRole => $userRole);
foreach ($this->acl->getRoles() as $role) {
if (! $this->acl->inheritsRole($role, $userRole, true)) {
$output[$role] = $role;
}
}
unset($output['master']);
return $output;
}
/**
* Retrieve an array of groups the user is allowed to assign: his own group and all groups
* he/she inherits rights from
*
* @param boolean $current Return the current list or the original list when true
* @return array
*/
public function getAllowedStaffGroups($current = true)
{
// Always refresh because these values are otherwise not responsive to change
$dbLookup = $this->util->getDbLookup();
$groupId = $this->getGroupId($current);
$groups = $dbLookup->getActiveStaffGroups();
if ('master' === $this->getRole($current)) {
$groups[-1] = $this->_('Project \'master\'');
return $groups;
}
try {
$setGroups = $this->db->fetchOne(
"SELECT ggp_may_set_groups FROM gems__groups WHERE ggp_id_group = ?",
$groupId
);
$groupsAllowed = explode(',', $setGroups);
} catch (\Zend_Db_Exception $e) {
// The database might not be updated
$groupsAllowed = [];
}
$result = array();
foreach ($groups as $id => $label) {
if ((in_array($id, $groupsAllowed))) {
$result[$id] = $groups[$id];
}
}
natsort($result);
return $result;
}
/**
* Returns the original (not the current) organization used by this user.
*
* @return \Gems_User_Organization
*/
public function getBaseOrganization()
{
return $this->userLoader->getOrganization($this->getBaseOrganizationId());
}
/**
* Returns the original (not the current) organization id of this user.
*
* @return int
*/
public function getBaseOrganizationId()
{
return $this->_getVar('user_base_org_id');
}
/**
* Returns a form to change the possword for this user.
*
* @param boolean $askOld Ask for the old password, calculated when not set.
* @return \Gems_Form
*/
public function getChangePasswordForm($args_array = null)
{
if (! $this->canSetPassword()) {
return;
}
$args = \MUtil_Ra::args(func_get_args());
if (isset($args['askCheck']) && $args['askCheck']) {
$args['checkFields'] = $this->loadResetPasswordCheckFields();
}
return $this->userLoader->getChangePasswordForm($this, $args);
}
/**
* Returns the organization that is currently used by this user.
*
* @return \Gems_User_Organization
*/
public function getCurrentOrganization()
{
return $this->userLoader->getOrganization($this->getCurrentOrganizationId());
}
/**
* Returns the organization id that is currently used by this user.
*
* @return int
*/
public function getCurrentOrganizationId()
{
$orgId = $this->_getVar('user_organization_id');
//If not set, read it from the cookie
if ($this->isCurrentUser() && ((null === $orgId) || (\Gems_User_UserLoader::SYSTEM_NO_ORG === $orgId))) {
$request = $this->getRequest();
if ($request) {
$orgId = \Gems_Cookies::getOrganization($this->getRequest());
}
if (! $orgId) {
$orgId = 0;
}
$this->_setVar('user_organization_id', $orgId);
}
return $orgId;
}
/**
* Get the propper Dear mr./mrs/ greeting of respondent
* @return string
*/
public function getDearGreeting()
{
$genderDears = $this->util->getTranslated()->getGenderDear();
$gender = $this->_getVar('user_gender');
if (isset($genderDears[$gender])) {
$greeting = $genderDears[$gender] . ' ';
} else {
$greeting = '';
}
return $greeting . $this->getLastName();
}
/**
* Return default new use group, if it exists
*
* @return string
*/
public function getDefaultNewStaffGroup()
{
$group = $this->getGroup();
if ($group) {
return $group->getDefaultNewStaffGroup();
}
}
/**
* Return true if this user has a password.
*
* @return string
*/
public function getEmailAddress()
{
return $this->_getVar('user_email');
}
/**
* If this is an embedder, return the EmbedderUserData object
*
* @return Gems\User\Embed\EmbeddedUserData
*/
public function getEmbedderData()
{
if (! $this->isEmbedded()) {
return null;
}
if ($this->_embedderData) {
return $this->_embedderData;
}
$this->_embedderData = $this->loader->getEmbedDataObject($this->getUserId(), $this->db);
return $this->_embedderData;
}
/**
* Returns the from address
*
* @return string E-Mail address
*/
public function getFrom()
{
// Gather possible sources of a from address
$sources[] = $this->getBaseOrganization();
if ($this->getBaseOrganizationId() != $this->getCurrentOrganizationId()) {
$sources[] = $this->getCurrentOrganization();
}
$sources[] = $this->project;
foreach ($sources as $source) {
if ($from = $source->getFrom()) {
return $from;
}
}
// We really don't like it, but sometimes the only way to get a from address.
return $this->getEmailAddress();
}
/**
* Returns the full user name (first, prefix, last).
*
* @return string
*/
public function getFullName()
{
if (! $this->_getVar('user_name')) {
$name = ltrim($this->_getVar('user_first_name') . ' ') .
ltrim($this->_getVar('user_surname_prefix') . ' ') .
$this->_getVar('user_last_name');
if (! $name) {
// Use obfuscated login name
$name = $this->getLoginName();
$name = substr($name, 0, 3) . str_repeat('*', max(5, strlen($name) - 2));
}
$this->_setVar('user_name', $name);
// \MUtil_Echo::track($name);
}
return $this->_getVar('user_name');
}
/**
* Returns the gender for use as part of a sentence, e.g. Dear Mr/Mrs
*
* In practice: starts lowercase
*
* @param string $locale
* @return array gender => string
*/
protected function getGenderGreeting($locale = null)
{
$greetings = $this->util->getTranslated()->getGenderGreeting($locale);
if (isset($greetings[$this->_getVar('user_gender')])) {
return $greetings[$this->_getVar('user_gender')];
}
}
/**
* Returns the gender for use in stand-alone name display
*
* In practice: starts uppercase
*
* @param string $locale
* @return array gender => string
*/
protected function getGenderHello($locale = null)
{
$greetings = $this->util->getTranslated()->getGenderHello($locale);
if (isset($greetings[$this->_getVar('user_gender')])) {
return $greetings[$this->_getVar('user_gender')];
}
}
/**
* Returns a standard greeting for the current user.
*
* @param string $locale
* @return int
*/
public function getGreeting($locale = null)
{
if (! $this->_getVar('user_greeting')) {
$greeting[] = $this->getGenderGreeting($locale);
if ($this->_getVar('user_last_name')) {
$greeting[] = $this->_getVar('user_surname_prefix');
$greeting[] = $this->_getVar('user_last_name');
} else {
$name = $this->getLoginName();
if ($name) {
$name = substr($name, 0, 3) . str_repeat('*', strlen($name) - 2);
$greeting[] = $name;
}
}
array_filter($greeting);
$this->_setVar('user_greeting', implode(' ', $greeting));
}
return $this->_getVar('user_greeting');
}
/**
* Returns the group of this user.
*
* @return \Gems\User\Group
*/
public function getGroup()
{
if (! $this->_group) {
$groupId = $this->getGroupId();
if ($groupId) {
$this->_group = $this->userLoader->getGroup($groupId);
}
}
return $this->_group;
}
/**
* Returns the group number of this user.
*
* @param boolean $current Checks value for current role (when false for normal role);
* @return int
*/
public function getGroupId($current = true)
{
if ($current && $this->_hasVar('current_user_group')) {
return $this->_getVar('current_user_group');
}
return $this->_getVar('user_group');
}
/**
* Returns the user last name (prefix, last).
*
* @return string
*/
public function getLastName()
{
if (! $this->_getVar('last_name')) {
$name = ltrim($this->_getVar('user_surname_prefix') . ' ') .
$this->_getVar('user_last_name');
if (! $name) {
// Use obfuscated login name
$name = $this->getLoginName();
$name = substr($name, 0, 3) . str_repeat('*', max(5, strlen($name) - 2));
}
$this->_setVar('last_name', $name);
// \MUtil_Echo::track($name);
}
return $this->_getVar('last_name');
}
/**
* The locale set for this user.
*
* @return string
*/
public function getLocale()
{
return $this->_getVar('user_locale');
}
/**
*
* @return string
*/
public function getLoginName()
{
return $this->_getVar('user_login');
}
/**
* Array of field name => values for sending E-Mail
*
* @param string $locale
* @return array
*/
public function getMailFields($locale = null)
{
$org = $this->getBaseOrganization();
$orgResults = $org->getMailFields();
$projResults = $this->project->getMailFields();
// $result['bcc'] = $projResults['project_bcc'];
$result['dear'] = $this->getDearGreeting();
$result['email'] = $this->getEmailAddress();
$result['first_name'] = $this->_getVar('user_first_name');
$result['from'] = $this->getFrom();
$result['full_name'] = trim($this->getGenderHello($locale) . ' ' . $this->getFullName());
$result['greeting'] = $this->getGreeting($locale);
$result['last_name'] = ltrim($this->_getVar('user_surname_prefix') . ' ') . $this->_getVar('user_last_name');
$result['login_url'] = $orgResults['organization_login_url'];
$result['name'] = $this->getFullName();
$result['login_name'] = $this->getLoginName();
$result = $result + $orgResults + $projResults;
$result['reset_ask'] = $orgResults['organization_login_url'] . '/index/resetpassword';
$result['reset_in_hours'] = $this->definition->getResetKeyDurationInHours();
$result['reply_to'] = $result['from'];
$result['to'] = $result['email'];
return $result;
}
/**
* Get the HOTP count
*/
public function getOtpCount()
{
return $this->_getVar('user_otp_count');
}
/**
* Get the HOTP requested time
*/
public function getOtpRequested()
{
return \MUtil_Date::ifDate(
$this->_getVar('user_otp_requested'),
[\Gems_Tracker::DB_DATETIME_FORMAT, \Gems_Tracker::DB_DATE_FORMAT, \Zend_Date::ISO_8601]
);
}
/**
* Return the number of days since last change of password
*
* @return int
*/
public function getPasswordAge()
{
$date = \MUtil_Date::ifDate(
$this->_getVar('user_password_last_changed'),
array(\Gems_Tracker::DB_DATETIME_FORMAT, \Gems_Tracker::DB_DATE_FORMAT, \Zend_Date::ISO_8601)
);
if ($date instanceof \MUtil_Date) {
return abs($date->diffDays());
} else {
return 0;
}
}
/**
* Return a password reset key
*
* @return string
*/
public function getPasswordResetKey()
{
return $this->definition->getPasswordResetKey($this);
}
/**
* Return the (unfiltered) phonenumber if the user has one
*
* @return string|null
*/
public function getPhonenumber()
{
return $this->_getVar('user_phonenumber');
}
/**
* Return the Request object
*
* @return \Zend_Controller_Request_Abstract
*/
public function getRequest()
{
if (! $this->request) {
$this->request = \Zend_Controller_Front::getInstance()->getRequest();
}
return $this->request;
}
/**
* Array of field name => values for sending a reset password E-Mail
*
* @param string $locale
* @return array
*/
public function getResetPasswordMailFields($locale = null)
{
$result['reset_key'] = $this->getPasswordResetKey();
$result['reset_url'] = $this->getBaseOrganization()->getLoginUrl() . '/index/resetpassword/key/' . $result['reset_key'];
$result['reset_in_hours'] = $this->definition->getResetKeyDurationInHours();
return $result + $this->getMailFields($locale);
}
/**
* Get an array of OrgId => Org Name for all allowed organizations that can have
* respondents for the current logged in user
*
* @return array
*/
public function getRespondentOrganizations()
{
if (! $this->_hasVar('__allowedRespOrgs')) {
$availableOrganizations = $this->util->getDbLookup()->getOrganizationsWithRespondents();
$allowedOrganizations = $this->getAllowedOrganizations();
$this->_setVar('__allowedRespOrgs', array_intersect($availableOrganizations, $allowedOrganizations));
}
// \MUtil_Echo::track($this->_getVar('__allowedOrgs'));
return $this->_getVar('__allowedRespOrgs');
}
/**
* Get an array of OrgId's for filtering on all allowed organizations that can have
* respondents for the current logged in user
*
* @return array
*/
public function getRespondentOrgFilter()
{
return array_keys($this->getRespondentOrganizations());
}
/**
* Get a where statement containing orgId's for combi field where statements on all
* allowed organizations that can have respondents for the current logged in user
*
* @param string $fieldName Field name separator
* @param string $sep Optional different value seperator
* @return string
*/
public function getRespondentOrgWhere($fieldName, $sep = '|')
{
return "(INSTR($fieldName, '$sep" .
implode("$sep') > 0 OR INSTR($fieldName, '$sep", $this->getRespondentOrgFilter()) .
"$sep') > 0)";
}
/**
* Returns the current user role.
*
* @param boolean $current Checks value for current role (when false for normal role);
* @return string
*/
public function getRole($current = true)
{
if ($current && $this->_hasVar('current_user_role')) {
return $this->_getRole('current_user_role');
}
return $this->_getRole('user_role');
}
/**
* Returns the current user roles.
*
* @return array With identical keys and values roleId => roleId
*/
public function getRoles()
{
return $this->acl->getRoleAndParents($this->getRole());
}
/**
* Return the secret key for embedded login
*
* @return array
*/
public function getSecretKey()
{
if ($this->isEmbedded()) {
if (! $this->_hasVar('secretKey')) {
if (! $this->_hasVar('gsus_secret_key')) {
$this->refreshEmbeddingData();
}
$key = $this->_getVar('gsus_secret_key');
$this->_setVar('secretKey', $key ? $this->project->decrypt($key) : null);
}
return $this->_getVar('secretKey', null);
}
}
/**
* @return int or null
*/
public function getSessionOrganizionId()
{
return $this->_getVar('current_user_orgId', null);
}
/**
* @return string or null
*/
public function getSessionPatientNr()
{
return $this->_getVar('current_user_patNr', null);
}
/**
* get the parameters where the survey should return to
*
* @return array
*/
public function getSurveyReturn()
{
return $this->_getVar('surveyReturn', array());
}
/**
*
* @return TwoFactorAuthenticatorInterface
*/
public function getTwoFactorAuthenticator()
{
if (! $this->_authenticator instanceof TwoFactorAuthenticatorInterface) {
if ($this->_hasVar('user_two_factor_key')) {
$authClass = \MUtil_String::beforeChars(
$this->_getVar('user_two_factor_key'),
TwoFactorAuthenticatorInterface::SEPERATOR
);
} else {
$authClass = $this->defaultAuthenticatorClass;
}
$this->_authenticator = $this->userLoader->getTwoFactorAuthenticator($authClass);
if ($this->_authenticator instanceof \Gems\User\TwoFactor\UserOtpInterface) {
$this->_authenticator->setUserId($this->getUserLoginId());
$this->_authenticator->setUserOtpCount($this->getOtpCount());
$this->_authenticator->setUserOtpRequested($this->getOtpRequested());
}
}
return $this->_authenticator;
}
/**
*
* @return string
*/
public function getTwoFactorKey()
{
if ($this->_hasVar('user_two_factor_key')) {
list($class, $key) = explode(
TwoFactorAuthenticatorInterface::SEPERATOR,
$this->_getVar('user_two_factor_key'),
2
);
} else {
$key = null;
}
return $key;
}
/**
*
* @return string
*/
public function getUserDefinitionClass()
{
return $this->_getVar('__user_definition');
}
/**
* Returns the user id, that identifies this user within this installation.
*
* One user id might be connected to multiple logins for multiple organizations.
*
* YES! This is the one you need, not getUserLoginId().
*
* @return int
*/
public function getUserId()
{
return (int) $this->_getVar('user_id');
}
/**
* Use ONLY in User package.
*
* Returns the User package user id, that is unique for each login / organization id
* combination, but does not directly identify this person.
*
* In other words, this is not the id you use to track who changed what. It is only
* used by parts of the User package.
*
* @return int
*/
public function getUserLoginId()
{
if ($this->_hasVar('user_login_id')) {
return $this->_getVar('user_login_id');
}
return 0;
}
/**
* Redirects the user to his/her start page.
*
* @param \Gems_Menu $menu
* @param \Zend_Controller_Request_Abstract $request
* @return \Gems_Menu_SubMenuItem
*/
public function gotoStartPage(\Gems_Menu $menu, \Zend_Controller_Request_Abstract $request)
{
if (false && $this->isPasswordResetRequired()) {
// Set menu OFF
// This code may be obsolete from 1.8.4
$menu->setVisible(false);
$menuItem = $menu->findController('option', 'change-password');
// This may not yet be true, but is needed for the redirect.
$menuItem->set('allowed', true);
$menuItem->set('visible', true);
} else {
$menuItem = $menu->findFirst(array('allowed' => true, 'visible' => true));
}
if ($menuItem) {
// Prevent redirecting to the current page.
if (! ($menuItem->is('controller', $request->getControllerName()) && $menuItem->is('action', $request->getActionName()))) {
if (!$menuItem->has('controller')) {
//This is a container, try to find first active child
$item = $menuItem;
foreach ($item->sortByOrder()->getChildren() as $menuItem) {
if ($menuItem->isAllowed() && $menuItem->has('controller')) {
break;
}
$menuItem = null;
}
}
if ($menuItem) {
$redirector = \Zend_Controller_Action_HelperBroker::getStaticHelper('redirector');
$redirector->gotoRoute($menuItem->toRouteUrl($request), null, true);
}
}
}
return $menuItem;
}
/**
* Return true if this user has a password.
*
* @return boolean
*/
public function hasEmailAddress()
{
return $this->_hasVar('user_email') && $this->_getVar('user_email');
}
/**
* Return true if this user has a password.
*
* @return boolean
*/
public function hasPassword()
{
return $this->definition->hasPassword($this);
}
/**
* Returns true if the role of the current user has the given privilege
*
* @param string $privilege
* @param boolean $current Checks value for current role (when false for normal role);
* @return bool
*/
public function hasPrivilege($privilege, $current = true)
{
if (! $this->acl) {
return true;
}
$role = $this->getRole($current);
return $this->acl->isAllowed($role, null, $privilege);
}
/**
* Return true if this user has this role
*
* @param string $role
* @return boolean
*/
public function hasRole($role)
{
$roles = $this->getRoles();
return (isset($roles[$role]));
}
/**
*
* @return boolean
*/
public function hasTwoFactor()
{
return (boolean) $this->_getVar('user_two_factor_key');
}
/**
* True when the reset key is within it's timeframe and OK for the current organization
*
* @return boolean
*/
public function hasValidResetKey()
{
return (boolean) $this->isActive() && $this->_getVar('user_resetkey_valid');
}
/**
* Return true if this user has a role that is accessible by the current user,
* i.e. is the current user allowed to change this specific user
*
* @return boolean
*/
public function inAllowedGroup()
{
if ($this->isCurrentUser() || (! $this->isStaff())) {
// Always allow editing of non-staff user
// for the time being
return true;
}
$group = $this->getGroupId();
$groups = $this->util->getDbLookup()->getActiveStaffGroups();
if (! isset($groups[$group])) {
// Allow editing when the group does not exist or is no longer active.
return true;
}
$allowedGroups = $this->userLoader->getCurrentUser()->getAllowedStaffGroups();
if ($allowedGroups) {
return (boolean) isset($allowedGroups[$group]);
} else {
return false;
}
}
/**
* @param boolean $checkCurrentOrganization Normally we check if the user is active ON THIS SITE, but not in the admin panel
* @return boolean True when a user can log in.
*/
public function isActive($checkCurrentOrganization = true)
{
if ($this->_getVar('user_active')) {
if ($checkCurrentOrganization) {
return $this->canLoginHere();
}
return true;
}
return false;
}
/**
* Is this organization in the list of currently allowed organizations?
*
* @param int $organizationId
* @return boolean
*/
public function isAllowedOrganization($organizationId)
{
$orgs = $this->getAllowedOrganizations();
return isset($orgs[$organizationId]) || (\Gems_User_UserLoader::SYSTEM_NO_ORG == $organizationId);
}
/**
* True when this user must enter a new password.
*
* @return boolean
*/
public function isBlockable()
{
if ($this->_hasVar('user_blockable')) {
return (boolean) $this->_getVar('user_blockable');
} else {
return true;
}
}
/**
* Checks if this user is the current user
*
* @return boolean
*/
public function isCurrentUser()
{
return $this->_vars instanceof \Zend_Session_Namespace;
}
/**
* Return true if this user is an embedded user that can defer to other logins.
*
* @return boolean
*/
public function isEmbedded()
{
return (boolean) $this->_getVar('user_embedded');
}
/**
*
* @param string $fieldName
* @return boolean True if this field is invisible
*/
public function isFieldInvisible($fieldName)
{
$group = $this->getGroup();
if ($group) {
return $group->isFieldInvisible($fieldName);
}
return false;
}
/**
*
* @param string $fieldName
* @return boolean True if this field is partially (or wholly) masked (or invisible)
*/
public function isFieldMaskedPartial($fieldName)
{
$group = $this->getGroup();
if ($group) {
return $group->isFieldMaskedPartial($fieldName);
}
return false;
}
/**
*
* @param string $fieldName
* @return boolean True if this field is wholly masked (or invisible)
*/
public function isFieldMaskedWhole($fieldName)
{
$group = $this->getGroup();
if ($group) {
return $group->isFieldMaskedWhole($fieldName);
}
return false;
}
/**
* True when this user requires a logout after answering a survey
*
* @return boolean
*/
public function isLogoutOnSurvey()
{
return (boolean) $this->_getVar('user_logout');
}
/**
* True when this user must enter a new password.
*
* @return boolean
*/
public function isPasswordResetRequired()
{
return (boolean) $this->_getVar('user_password_reset');
}
/**
* @return boolean True when we're (functionally) working in a frame, e.g. for an embedded user
*/
public function isSessionFramed()
{
return $this->_getVar('current_user_framed', false);
}
/**
* Returns true when this user is a staff member.
*
* @return boolean
*/
public function isStaff()
{
return (boolean) $this->_getVar('user_staff');
}
/**
* Can this user be authorized using two factor authentication?
*
* @return boolean
*/
public function isTwoFactorEnabled()
{
return (boolean) $this->_getVar('user_enable_2factor') && $this->hasTwoFactor();
}
/**
* Should this user be authorized using two factor authentication?
*
* @param string $ipAddress
* @return boolean
*/
public function isTwoFactorRequired($ipAddress)
{
return $this->definition->isTwoFactorRequired($ipAddress, $this->isTwoFactorEnabled(), $this->getGroup());
}
/**
* Load the callables | results needed to authenticate/authorize this user
*
* A callable will be called, then an adapter authorizes and if the end result
* is boolean, string or array it is converted into a Laminas\Authenticate\Result.
*
* @param string $password
* @param boolean $testPassword Set to false to test on the non-password checks only
* @return array Of Callable|Laminas\Authentication\Adapter\AdapterInterface|Laminas\Authenticate\Result|boolean|string|array
*/
protected function loadAuthorizers($password, $testPassword = true)
{
if ($this->isBlockable()) {
$auths['block'] = array($this, 'authorizeBlock');
}
// organization ip restriction
$auths['orgip'] = array($this, 'authorizeOrgIp');
// group ip restriction
$auths['ip'] = array($this, 'authorizeIp');
if ($testPassword) {
if ($this->isActive()) {
$auths['pwd'] = $this->definition->getAuthAdapter($this, $password);
} else {
$auths['pwd'] = false;
}
}
return $auths;
}
/**
* Returns an array of elements for check fields during password reset and/or
* 'label name' => 'required value' pairs. For asking extra questions before allowing
* a password change.
*
* Default is asking for the username but you can e.g. ask for someones birthday.
*
* @return array Of 'label name' => 'required values' or \Zend_Form_Element elements
*/
protected function loadResetPasswordCheckFields()
{
// CHECK ON SOMEONES BIRTHDAY
// Birthdays are usually not defined for staff but they do exist for respondents
if ($value = $this->_getVar('user_birthday')) {
$label = $this->_('Your birthday');
$birthdayElem = new \Gems_JQuery_Form_Element_DatePicker('birthday');
$birthdayElem->setLabel($label)
->setOptions(\MUtil_Model_Bridge_FormBridge::getFixedOptions('date'))
->setRequired(true)
->setStorageFormat('yyyy-MM-dd');
if ($format = $birthdayElem->getDateFormat()) {
$valueFormatted = \MUtil_Date::format($value, $format, $birthdayElem->getStorageFormat());
} else {
$valueFormatted = $value;
}
$validator = new \Zend_Validate_Identical($valueFormatted);
$validator->setMessage(sprintf($this->_('%s is not correct.'), $label), \Zend_Validate_Identical::NOT_SAME);
$birthdayElem->addValidator($validator);
return array($label => $birthdayElem);
}
// CHECK ON SOMEONES ZIP
// Zips are usually not defined for staff but they do exist for respondents
if ($value = $this->_getVar('user_zip')) {
$label = $this->_('Your zipcode');
$zipElem = new Text('zipcode');
$zipElem->setLabel($label)
->setRequired(true);
$validator = new \Zend_Validate_Identical($value);
$validator->setMessage(sprintf($this->_('%s is not correct.'), $label), \Zend_Validate_Identical::NOT_SAME);
$zipElem->addValidator($validator);
return array($label => $zipElem);
}
return array($this->_('Username') => $this->getLoginName());
}
/**
*
* @param string $defName Optional
* @return \Gems_User_User (continuation pattern)
*/
public function refresh($defName = null)
{
if ($defName) {
$this->definition = $this->userLoader->getUserDefinition($defName);
}
$newData = $this->definition->getUserData($this->getLoginName(), $this->getBaseOrganizationId());
$newData = $this->userLoader->ensureDefaultUserValues($newData, $this->definition, $defName);
foreach ($newData as $key => $value) {
$this->_setVar($key, $value);
}
$this->_getRole('user_role');
return $this;
}
/**
* Allowes a refresh of the existing list of organizations
* for this user.
*
* @return \Gems_User_User (continuation pattern)
*/
public function refreshAllowedOrganizations()
{
// Privilege overrules organizational settings
if ($this->hasPrivilege('pr.organization-switch')) {
$orgs = $this->util->getDbLookup()->getOrganizations();
} else {
$org = $this->getBaseOrganization();
$orgs = array($org->getId() => $org->getName()) +
$org->getAllowedOrganizations();
}
// \MUtil_Echo::track($orgs);
$this->_setVar('__allowedOrgs', $orgs);
// Clean this cache
$this->_unsetVar('__allowedRespOrgs');
return $this;
}
/**
* Load and set the embedded user data. triggered only when
* embedded data is requested
*
* @return void
*/
protected function refreshEmbeddingData()
{
if (! $this->isEmbedded()) {
return;
}
$data = $this->db->fetchRow(
"SELECT * FROM gems__systemuser_setup WHERE gsus_id_user = ?",
$this->getUserId()
);
if ($data) {
unset($data['gsus_id_user'], $data['gsus_changed'], $data['gsus_changed_by'],
$data['gsus_created'], $data['gsus_created_by']);
} else {
// Load defaults
$data = [
'gsus_secret_key' => null,
'gsus_create_user' => 0,
'gsus_authentication' => null,
'gsus_deferred_user_loader' => null,
'gsus_deferred_user_group' => null,
'gsus_redirect' => null,
'gsus_deferred_user_layout' => null,
];
}
foreach ($data as $key => $value) {
// Using the full field name to prevent any future clash with a new or user specific field
$this->_setVar($key, $value);
}
}
/**
* Check for password weakness.
*
* @param string $password Or null when you want a report on all the rules for this password.
* @param boolean $skipAge When setting a new password, we should not check for age
* @return mixed String or array of strings containing warning messages or nothing
*/
public function reportPasswordWeakness($password = null, $skipAge = false)
{
if ($this->canSetPassword()) {
$checker = $this->userLoader->getPasswordChecker();
$codes[] = $this->getCurrentOrganization()->getCode();
$codes[] = $this->getRoles();
$codes[] = $this->_getVar('__user_definition');
if ($this->isStaff()) {
$codes[] = 'staff';
}
return $checker->reportPasswordWeakness($this, $password, \MUtil_Ra::flatten($codes), $skipAge);
}
}
/**
* Send an e-mail to this user
*
* @param string $subjectTemplate A subject template in which {fields} are replaced
* @param string $bbBodyTemplate A BB Code body template in which {fields} are replaced
* @param boolean $useResetFields When true get a reset key for this user
* @param string $locale Optional locale
* @return mixed String or array of warnings when something went wrong
*/
public function sendMail($subjectTemplate, $bbBodyTemplate, $useResetFields = false, $locale = null)
{
if ($useResetFields && (! $this->canResetPassword())) {
return $this->_('Trying to send a password reset to a user that cannot be reset.');
}
$mail = $this->loader->getMail();
$mail->setTemplateStyle($this->getBaseOrganization()->getStyle());
$mail->setFrom($this->getFrom());
$mail->addTo($this->getEmailAddress(), $this->getFullName(), $this->project->getStaffBounce());
if ($bcc = $this->project->getEmailBcc()) {
$mail->addBcc($bcc);
}
if ($useResetFields) {
$fields = $this->getResetPasswordMailFields($locale);
} else {
$fields = $this->getMailFields($locale);
}
// \MUtil_Echo::track($fields, $bbBodyTemplate);
$fields = \MUtil_Ra::braceKeys($fields, '{', '}');
$mail->setSubject(strtr($subjectTemplate, $fields));
$mail->setBodyBBCode(strtr($bbBodyTemplate, $fields));
try {
$mail->send();
return null;
} catch (\Exception $e) {
return array(
$this->_('Unable to send e-mail.'),
$e->getMessage());
}
}
/**
* Set this user as the current user.
*
* This means that the data about this user will be stored in a session.
*
* @param boolean $signalLoader Do not set, except from UserLoader
* @param boolean $resetSessionId Should the session be reset?
* @return \Gems_User_User (continuation pattern)
*/
public function setAsCurrentUser($signalLoader = true, $resetSessionId = true)
{
// Get the current variables
$oldStore = $this->_getVariableStore();
// When $oldStore is a \Zend_Session_Namespace, then this user is already the current user.
if (! $this->isCurrentUser()) {
$this->userLoader->unsetCurrentUser();
if ($resetSessionId) {
\Zend_Session::regenerateId();
}
$this->_vars = $this->session;
foreach ($oldStore as $name => $value) {
$this->_vars->__set($name, $value);
}
// Perform the interface switch
$this->switchLocale();
if ($signalLoader) {
$this->userLoader->setCurrentUser($this);
}
}
$org = $this->getCurrentOrganization()->setAsCurrentOrganization();
return $this;
}
/**
* Set the currently selected organization for this user
*
* @param mixed $organization \Gems_User_Organization or an organization id.
* @return \Gems_User_User (continuation pattern)
*/
public function setCurrentOrganization($organization)
{
if (!($organization instanceof \Gems_User_Organization)) {
$organization = $this->userLoader->getOrganization($organization);
}
$organizationId = $organization->getId();
$oldOrganizationId = $this->getCurrentOrganizationId();
if ($organizationId != $oldOrganizationId) {
$this->_setVar('user_organization_id', $organizationId);
if ($this->isCurrentUser()) {
$this->getCurrentOrganization()->setAsCurrentOrganization();
if ($organization->canHaveRespondents()) {
$usedOrganizationId = $organizationId;
} else {
$usedOrganizationId = null;
}
// Now update the requestcache to change the oldOrgId to the new orgId
// Don't do it when the oldOrgId doesn't match
$keysArray = array_flip($this->possibleOrgIds);
$requestCache = $this->session->requestCache;
if ($requestCache) {
foreach ($requestCache as $key => &$elements) {
$elements = $this->_changeIds($elements, $oldOrganizationId, $usedOrganizationId, $keysArray);
}
$this->session->requestCache = $requestCache;
}
// $searchSession &= $_SESSION['ModelSnippetActionAbstract_getSearchData'];
$searchSession = new \Zend_Session_Namespace('ModelSnippetActionAbstract_getSearchData');
foreach ($searchSession as $id => $data) {
$searchSession->$id = $this->_changeIds($data, $oldOrganizationId, $usedOrganizationId, $keysArray);
}
}
}
return $this;
}
/**
* Set (for the whole session) the group of the current user.
*
* Different from switching, used for embedded login
*
* @param int $groupId
* @return self
*/
public function setGroupSession($groupId)
{
$this->_group = null;
if ($groupId == $this->_getVar('user_group')) {
$this->_unsetVar('current_user_group');
$this->_unsetVar('current_user_role');
} else {
$group = $this->userLoader->getGroup($groupId);
$this->_setVar('current_user_group', $groupId);
$this->_setVar('current_user_role', $group->getRole());
}
return $this;
}
/**
* (Temporarily) the group of the current user.
*
* @param int $groupId
* @return self
*/
public function setGroupTemp($groupId)
{
$this->_group = null;
if ($groupId == $this->_getVar('user_group')) {
$this->_unsetVar('current_user_group');
$this->_unsetVar('current_user_role');
} else {
$groups = $this->getAllowedStaffGroups(false);
$group = $this->userLoader->getGroup($groupId);
if (isset($groups[$groupId])) {
$this->_setVar('current_user_group', $groupId);
$this->_setVar('current_user_role', $group->getRole());
} elseif ($group->isActive()) {
throw new \Gems_Exception($this->_('No access to group'), 403, null, sprintf(
$this->_('You are not allowed to switch to the %s group.'),
$group->getName()
));
} else {
throw new \Gems_Exception($this->_('No access to group'), 403, null, sprintf(
$this->_('You cannot switch to an inactive or non-existing group.')
));
}
}
return $this;
}
/**
* Set the locale for this user..
*
* @param string $locale
* @return \Gems_User_User (continuation pattern)
*/
public function setLocale($locale)
{
$this->_setVar('user_locale', (string) $locale);
return $this;
}
/**
* Set the password, if allowed for this user type.
*
* @param string $password
* @return \Gems_User_User (continuation pattern)
*/
public function setPassword($password)
{
$this->definition->setPassword($this, $password);
$this->setPasswordResetRequired(false);
$this->refresh(); // force refresh
return $this;
}
/**
*
* @param boolean $reset
* @return \Gems_User_User (continuation pattern)
*/
public function setPasswordResetRequired($reset = true)
{
$this->_setVar('user_password_reset', (boolean) $reset);
return $this;
}
/**
* Set the Request object
*
* @param \Zend_Controller_Request_Abstract $request
* @return \Gems_User_User
*/
public function setRequest(\Zend_Controller_Request_Abstract $request)
{
$this->request = $request;
return $this;
}
/**
*
* @param string $option One of the EmbedLoader->listCrumbOptions() options
* @return $this
*/
public function setSessionCrumbs($option)
{
$this->_setVar('current_user_crumbs', $option);
return $this;
}
/**
*
* @param boolean $option When true we're working in a frame
* @return $this
*/
public function setSessionFramed($option = true)
{
$this->_setVar('current_user_framed', $option);
return $this;
}
/**
*
* @param string $layout Name of a .[html layout file
* @return $this
*/
public function setSessionMvcLayout($layout)
{
$this->_setVar('current_user_layout', $layout);
return $this;
}
/**
* @param $patientNr
* @param $orgId
* @return $this
*/
public function setSessionPatientNr($patientNr, $orgId)
{
$this->_setVar('current_user_patNr', $patientNr);
$this->_setVar('current_user_orgId', $orgId);
return $this;
}
/**
*
* @param string $style One of the escort->getStyle styles
* @return $this
*/
public function setSessionStyle($style)
{
$this->_setVar('current_user_style', $style);
return $this;
}
/**
* Set the parameters where the survey should return to
*
* @param mixed $return \Zend_Controller_Request_Abstract, array of something that can be turned into one.
* @return \Gems_User_User
*/
public function setSurveyReturn($return = null)
{
if (null === $return) {
$this->_unsetVar('surveyReturn');
return $this;
}
if ($return instanceof \Zend_Controller_Request_Abstract) {
$return = $return->getParams();
} elseif (! is_array($return)) {
$return = \MUtil_Ra::to($return);
}
if ('autofilter' == $return['action']) {
$return['action'] = 'index';
}
$return = array_filter($return);
// \MUtil_Echo::track($return);
$this->_setVar('surveyReturn', $return);
return $this;
}
/**
*
* @param string TwoFactorAuthenticatorInterface $authenticator
* @param string $newKey
* @param boolean $enabled
* @return $this
*/
public function setTwoFactorKey(TwoFactorAuthenticatorInterface $authenticator, $newKey, $enabled = null)
{
// Make sure the authclass is part of the data
$authClass = get_class($authenticator);
$authFind = '\\User\\TwoFactor\\';
$pos = strrpos($authClass, $authFind);
if ($pos) {
$authClass = substr($authClass, $pos + strlen($authFind));
}
$newValue = $authClass . TwoFactorAuthenticatorInterface::SEPERATOR . $newKey;
$this->_setVar('user_two_factor_key', $newValue);
if (null !== $enabled) {
$this->_setVar('user_enable_2factor', $enabled ? 1 : 0);
}
$this->definition->setTwoFactorKey($this, $newValue, $enabled);
return $this;
}
/**
* Switch to new locale
*
* @param string $locale Current if omitted
* @return boolean true if cookie was set
*/
public function switchLocale($locale = null)
{
if (null === $locale) {
$locale = $this->getLocale();
if (null === $locale) {
$site = $this->util->getSites()->getSiteForCurrentUrl();
if ($site) {
$locale = $site->getLocale();
}
}
}
if ($this->getLocale() != $locale) {
$this->setLocale($locale);
}
$this->locale->setLocale($locale);
$this->translateAdapter->setLocale($locale);
return \Gems_Cookies::setLocale($locale, $this->basepath->getBasePath());
}
/**
* Unsets this user as the current user.
*
* This means that the data about this user will no longer be stored in a session.
*
* @param boolean $signalLoader Do not set, except from UserLoader
* @return \Gems_User_User (continuation pattern)
*/
public function unsetAsCurrentUser($signalLoader = true)
{
// When $oldStore is a \Zend_Session_Namespace, then this user is already the current user.
if ($this->isCurrentUser()) {
// Get the current variables
$oldStore = $this->_vars;
$this->_vars = new \ArrayObject();
$this->_vars->setFlags(\ArrayObject::STD_PROP_LIST);
foreach ($oldStore as $name => $value) {
$this->_vars->offsetSet($name, $value);
}
// Clean up what is there now in the session.
$oldStore->unsetAll();
if ($signalLoader) {
// Signal the loader
$this->userLoader->unsetCurrentUser();
}
}
return $this;
}
}