MODX Revolution PHP Cross Reference Content Management Systems

Source: /core/model/modx/moduser.class.php - 808 lines - 30796 bytes - Summary - Text - Print

   1  <?php
   2  /**
   3   * @package modx
   4   */
   5  /**
   6   * The core MODX user class.
   7   *
   8   * @property int $id The ID of the User
   9   * @property string $username The username for this User
  10   * @property string $password The encrypted password for this User
  11   * @property string $cachepwd A cached, encrypted password used when resetting the User's password or for confirmation
  12   * @property string $class_key The class key of the user. Used for extending the modUser class.
  13   * @property boolean $active Whether or not this user is active, and thereby able to log in
  14   * @property string $remote_key Used for storing a remote reference key for authentication for a User
  15   * @property json $remote_data Used for storing remote data for authentication for a User
  16   * @property string $hash_class The hashing class used to create this User's password
  17   * @property string $salt A salt that might have been used to create this User's password
  18   *
  19   * @property modUserProfile $Profile
  20   * @property modUserGroup $PrimaryGroup
  21   * @property array $CreatedResources
  22   * @property array $EditedResources
  23   * @property array $DeletedResources
  24   * @property array $PublishedResources
  25   * @property array $SentMessages
  26   * @property array $ReceivedMessages
  27   * @property array $UserSettings
  28   * @property array $UserGroupMembers
  29   *
  30   * @see modUserGroupMember
  31   * @see modUserGroupRole
  32   * @see modUserMessage
  33   * @see modUserProfile
  34   * @package modx
  35   */
  36  class modUser extends modPrincipal {
  37      /** @var modX|xPDO $xpdo */
  38      public $xpdo;
  39      /**
  40       * A collection of contexts which the current principal is authenticated in.
  41       * @var array
  42       * @access public
  43       */
  44      public $sessionContexts= array ();
  45  
  46      /**
  47       * The modUser password field is hashed automatically, and prevent sudo from being set via mass-assignment
  48       *
  49       * {@inheritdoc}
  50       */
  51      public function set($k, $v= null, $vType= '') {
  52          if (!$this->getOption(xPDO::OPT_SETUP)) {
  53              if ($k == 'sudo') return false;
  54          }
  55          if (in_array($k, array('password', 'cachepwd')) && $this->xpdo->getService('hashing', 'hashing.modHashing')) {
  56              if (!$this->get('salt')) {
  57                  $this->set('salt', md5(uniqid(rand(),true)));
  58              }
  59              $vOptions = array('salt' => $this->get('salt'));
  60              $v = $this->xpdo->hashing->getHash('', $this->get('hash_class'))->hash($v, $vOptions);
  61          }
  62          return parent::set($k, $v, $vType);
  63      }
  64  
  65      /**
  66       * Set the sudo field explicitly
  67       *
  68       * @param boolean $sudo
  69       * @return bool
  70       */
  71      public function setSudo($sudo) {
  72          $this->_fields['sudo'] = (boolean)$sudo;
  73          $this->setDirty('sudo');
  74          return true;
  75      }
  76  
  77      /**
  78       * Overrides xPDOObject::save to fire modX-specific events
  79       * 
  80       * {@inheritDoc}
  81       */
  82      public function save($cacheFlag = false) {
  83          $isNew = $this->isNew();
  84  
  85          if ($this->xpdo instanceof modX) {
  86              $this->xpdo->invokeEvent('OnUserBeforeSave',array(
  87                  'mode' => $isNew ? modSystemEvent::MODE_NEW : modSystemEvent::MODE_UPD,
  88                  'user' => &$this,
  89                  'cacheFlag' => $cacheFlag,
  90              ));
  91          }
  92  
  93          $saved = parent :: save($cacheFlag);
  94          
  95          if ($saved && $this->xpdo instanceof modX) {
  96              $this->xpdo->invokeEvent('OnUserSave',array(
  97                  'mode' => $isNew ? modSystemEvent::MODE_NEW : modSystemEvent::MODE_UPD,
  98                  'user' => &$this,
  99                  'cacheFlag' => $cacheFlag,
 100              ));
 101          }
 102          return $saved;
 103      }
 104  
 105      /**
 106       * Overrides xPDOObject::remove to fire modX-specific events
 107       *
 108       * {@inheritDoc}
 109       */
 110      public function remove(array $ancestors = array()) {
 111          if ($this->xpdo instanceof modX) {
 112              $this->xpdo->invokeEvent('OnUserBeforeRemove',array(
 113                  'user' => &$this,
 114                  'ancestors' => $ancestors,
 115              ));
 116          }
 117  
 118          $removed = parent :: remove($ancestors);
 119  
 120          if ($this->xpdo instanceof modX) {
 121              $this->xpdo->invokeEvent('OnUserRemove',array(
 122                  'user' => &$this,
 123                  'ancestors' => $ancestors,
 124              ));
 125          }
 126  
 127          return $removed;
 128      }
 129  
 130      /**
 131       * Loads the principal attributes that define a modUser security profile.
 132       *
 133       * {@inheritdoc}
 134       */
 135      public function loadAttributes($target, $context = '', $reload = false) {
 136          $context = !empty($context) ? $context : $this->xpdo->context->get('key');
 137          $id = $this->get('id') ? (string) $this->get('id') : '0';
 138          if ($this->get('id') && !$reload) {
 139              $staleContexts = $this->get('session_stale');
 140              $staleContexts = !empty($staleContexts) ? $staleContexts : array();
 141              $stale = array_search($context, $staleContexts);
 142              if ($stale !== false) {
 143                  $reload = true;
 144                  $staleContexts = array_diff($staleContexts, array($context));
 145                  $this->set('session_stale', $staleContexts);
 146                  $this->save();
 147              }
 148          }
 149          if ($this->_attributes === null || $reload) {
 150              $this->_attributes = array();
 151              if (isset($_SESSION["modx.user.{$id}.attributes"])) {
 152                  if ($reload) {
 153                      unset($_SESSION["modx.user.{$id}.attributes"]);
 154                  } else {
 155                      $this->_attributes = $_SESSION["modx.user.{$id}.attributes"];
 156                  }
 157              }
 158          }
 159          if (!isset($this->_attributes[$context])) {
 160              $this->_attributes[$context] = array();
 161          }
 162          $target = (array) $target;
 163          foreach ($target as $t) {
 164              if (!isset($this->_attributes[$context][$t])) {
 165                  $this->_attributes[$context][$t] = $this->xpdo->call(
 166                      $t,
 167                      'loadAttributes',
 168                      array(&$this->xpdo, $context, $this->get('id'))
 169                  );
 170                  if (!isset($this->_attributes[$context][$t]) || !is_array($this->_attributes[$context][$t])) {
 171                      $this->_attributes[$context][$t] = array();
 172                  }
 173              }
 174          }
 175          $_SESSION["modx.user.{$id}.attributes"] = $this->_attributes;
 176      }
 177  
 178      /**
 179       * Determines if this user is authenticated in a specific context.
 180       *
 181       * Separate session contexts can allow users to login/out of specific sub-sites
 182       * individually (or in collections).
 183       *
 184       * @access public
 185       * @param string $sessionContext The context to determine if the user is
 186       * authenticated in.
 187       * @return boolean true, if the user is authenticated in the specified
 188       * context, false otherwise.
 189       */
 190      public function isAuthenticated($sessionContext= 'web') {
 191          $isAuthenticated= false;
 192          if (!empty ($sessionContext) && is_string($sessionContext)) {
 193              if ($this->hasSessionContext($sessionContext)) {
 194                  $isAuthenticated= true;
 195              }
 196              elseif (isset ($_SESSION[$sessionContext . "Validated"])) {
 197                  $isAuthenticated= ($_SESSION[$sessionContext . "Validated"] == 1);
 198              }
 199          }
 200          return $isAuthenticated;
 201      }
 202  
 203      /**
 204       * Ends a user session completely, including all contexts.
 205       *
 206       * @access public
 207       */
 208      public function endSession() {
 209          $this->removeLocks();
 210          $_SESSION = array();
 211          if (ini_get("session.use_cookies")) {
 212              $params = session_get_cookie_params();
 213              setcookie(
 214                  session_name(),
 215                  '',
 216                  time() - 42000,
 217                  $params["path"],
 218                  $params["domain"],
 219                  $params["secure"],
 220                  $params["httponly"]
 221              );
 222          }
 223          session_destroy();
 224      }
 225  
 226      /**
 227       * Determines if the provided password matches the hashed password stored for the user.
 228       *
 229       * @param string $password The password to determine if it matches.
 230       * @param array $options Optional settings for the hashing process.
 231       * @return boolean True if the provided password matches the stored password for the user.
 232       */
 233      public function passwordMatches($password, array $options = array()) {
 234          $match = false;
 235          if ($this->xpdo->getService('hashing', 'hashing.modHashing')) {
 236              $options = array_merge(array('salt' => $this->get('salt')), $options);
 237              $hashedPassword = $this->xpdo->hashing->getHash('', $this->get('hash_class'))->hash($password, $options);
 238              $match = ($this->get('password') === $hashedPassword);
 239          }
 240          return $match;
 241      }
 242  
 243      /**
 244       * Activate a reset user password if the proper activation key is provided.
 245       *
 246       * {@internal This does not mark the user active, but rather moves the cachepwd to the
 247       * password field if the activation key matches.}
 248       *
 249       * @param string $key The activation key provided to the user and stored in the registry for matching.
 250       * @return boolean|integer True if the activation was successful, false if unsuccessful,
 251       * and -1 if there is no activation to perform.
 252       */
 253      public function activatePassword($key) {
 254          $activated = -1;
 255          if ($this->get('cachepwd')) {
 256              if ($this->xpdo->getService('registry', 'registry.modRegistry') && $this->xpdo->registry->getRegister('user', 'registry.modDbRegister')) {
 257                  if ($this->xpdo->registry->user->connect()) {
 258                      $activated = false;
 259                      $this->xpdo->registry->user->subscribe('/pwd/reset/' . md5($this->get('username')));
 260                      $msgs = $this->xpdo->registry->user->read(array('poll_limit' => 1));
 261                      if (!empty($msgs)) {
 262                          if ($key === reset($msgs)) {
 263                              $this->_setRaw('password', $this->get('cachepwd'));
 264                              $this->_setRaw('cachepwd', '');
 265                              $activated = $this->save();
 266                          }
 267                      }
 268                  }
 269              }
 270              if ($activated === false) {
 271                  $this->_setRaw('cachepwd', '');
 272                  $this->save();
 273              }
 274          }
 275          return $activated;
 276      }
 277  
 278      /**
 279       * Change the user password.
 280       *
 281       * @access public
 282       * @param string $newPassword Password to set.
 283       * @param string $oldPassword Current password for validation.
 284       * @return boolean Indicates if password was successfully changed.
 285       * @todo Add support for configurable password encoding.
 286       */
 287      public function changePassword($newPassword, $oldPassword) {
 288          $changed= false;
 289          if ($this->passwordMatches($oldPassword)) {
 290              if (!empty ($newPassword)) {
 291                  $this->set('password', $newPassword);
 292                  $changed= $this->save();
 293                  if ($changed) {
 294                      $this->xpdo->invokeEvent('OnUserChangePassword', array (
 295                          'user' => &$this,
 296                          'newpassword' => $newPassword,
 297                          'oldpassword' => $oldPassword,
 298                          'userid' => $this->get('id'),/* deprecated */
 299                          'username' => $this->get('username'),/* deprecated */
 300                          'userpassword' => $newPassword,/* deprecated */
 301                      ));
 302                  }
 303              }
 304          }
 305          return $changed;
 306      }
 307  
 308      /**
 309       * Returns an array of user session context keys.
 310       *
 311       * @access public
 312       * @return array An array of session contexts.
 313       */
 314      public function getSessionContexts() {
 315          if (!is_array($this->sessionContexts) || empty ($this->sessionContexts)) {
 316              $this->sessionContexts= array ();
 317              if (isset ($_SESSION['modx.user.contextTokens'])) {
 318                  $this->sessionContexts= $_SESSION['modx.user.contextTokens'];
 319              } else {
 320                  $legacyContextTokens= array ();
 321                  if (isset ($_SESSION["webValidated"]) && $_SESSION["webValidated"] == 1) {
 322                      $legacyContextTokens[]= 'web';
 323                  }
 324                  if (isset ($_SESSION["mgrValidated"]) && $_SESSION["mgrValidated"] == 1) {
 325                      $legacyContextTokens[]= 'mgr';
 326                  }
 327                  foreach ($legacyContextTokens as $token)
 328                      $this->addSessionContext($token);
 329              }
 330              $_SESSION['modx.user.contextTokens']= $this->sessionContexts;
 331          }
 332          return $this->sessionContexts;
 333      }
 334  
 335      /**
 336       * Adds a new context to the user session context array.
 337       *
 338       * @access public
 339       * @param string $context The context to add to the user session.
 340       */
 341      public function addSessionContext($context) {
 342          if (!empty($context)) {
 343              $this->getSessionContexts();
 344              session_regenerate_id(true);
 345  
 346              $this->getOne('Profile');
 347              if ($this->Profile && $this->Profile instanceof modUserProfile) {
 348                  $ua= & $this->Profile;
 349                  if ($ua && !isset ($this->sessionContexts[$context]) || $this->sessionContexts[$context] != $this->get('id')) {
 350                      $ua->set('failedlogincount', 0);
 351                      $ua->set('logincount', $ua->logincount + 1);
 352                      $ua->set('lastlogin', $ua->thislogin);
 353                      $ua->set('thislogin', time());
 354                      $ua->set('sessionid', session_id());
 355                      $ua->save();
 356                  }
 357              }
 358              $this->sessionContexts[$context]= $this->get('id');
 359              $_SESSION['modx.user.contextTokens']= $this->sessionContexts;
 360              if (!isset($_SESSION["modx.{$context}.user.token"])) {
 361                  $_SESSION["modx.{$context}.user.token"]= $this->generateToken($context);
 362              }
 363          } else {
 364              $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Attempt to login to a context with an empty key");
 365          }
 366      }
 367  
 368      /**
 369       * Generate a specific authentication token for this user for accessing the MODX manager
 370       * @param string $salt Ignored
 371       * @return string
 372       */
 373      public function generateToken($salt) {
 374          return uniqid($this->xpdo->site_id . '_' . $this->get('id'), true);
 375      }
 376  
 377      /**
 378       * Get the user token for the user
 379       * @param string $ctx
 380       * @return string
 381       */
 382      public function getUserToken($ctx = '') {
 383          if (empty($ctx)) $ctx = $this->xpdo->context->get('key');
 384          return isset($_SESSION['modx.'.$ctx.'.user.token']) ? $_SESSION['modx.'.$ctx.'.user.token'] : '';
 385      }
 386  
 387      /**
 388       * Removes a user session context.
 389       *
 390       * @access public
 391       * @param string|array $context The context key or an array of context keys.
 392       */
 393      public function removeSessionContext($context) {
 394          if ($this->getSessionContexts()) {
 395              $contextToken= array ();
 396              if (is_array($context)) {
 397                  foreach ($context as $ctx) {
 398                      $contextToken[$ctx]= $this->get('id');
 399                      $this->removeSessionContextVars($ctx);
 400                  }
 401              } else {
 402                  $contextToken[$context]= $this->get('id');
 403                  $this->removeSessionContextVars($context);
 404              }
 405              $this->sessionContexts= array_diff_assoc($this->sessionContexts, $contextToken);
 406              if (empty($this->sessionContexts)) {
 407                  $this->endSession();
 408              } else {
 409                  $_SESSION['modx.user.contextTokens']= $this->sessionContexts;
 410              }
 411          }
 412      }
 413  
 414      /**
 415       * Removes the session vars associated with a specific context.
 416       *
 417       * @access public
 418       * @param string $context The context key.
 419       */
 420      public function removeSessionContextVars($context) {
 421          if (is_string($context) && !empty ($context)) {
 422              unset($_SESSION["modx.{$context}.user.token"]);
 423              unset($_SESSION["modx.{$context}.user.config"]);
 424              unset($_SESSION["modx.{$context}.session.cookie.lifetime"]);
 425          }
 426      }
 427  
 428      /**
 429       * Removes a session cookie for a user.
 430       *
 431       * TODO Implement this.
 432       *
 433       * @access public
 434       * @param string $context The context to remove.
 435       */
 436      public function removeSessionCookie($context) {}
 437  
 438      /**
 439       * Checks if the user has a specific session context.
 440       *
 441       * @access public
 442       * @param mixed $context Either a name of a context or array of context
 443       * names to check against.
 444       * @return boolean True if the user has the context(s) specified.
 445       */
 446      public function hasSessionContext($context) {
 447          $hasContext= false;
 448          if ($this->getSessionContexts()) {
 449              $contextTokens= array ();
 450              if (is_array($context)) {
 451                  foreach ($context as $ctx) {
 452                      $contextTokens[$ctx]= $this->get('id');
 453                  }
 454              }
 455              elseif (is_string($context)) {
 456                  $contextTokens[$context]= $this->get('id');
 457              }
 458              $hasContext= (count(array_intersect_assoc($contextTokens, $this->sessionContexts)) == count($contextTokens));
 459          }
 460          return $hasContext;
 461      }
 462  
 463      /**
 464       * Gets a count of {@link modUserMessage} objects ascribed to the user.
 465       *
 466       * @access public
 467       * @param mixed $read
 468       * @return integer The number of messages.
 469       */
 470      public function countMessages($read = '') {
 471          if ($read == 'read') { $read = 1; } elseif ($read == 'unread') { $read = 0; }
 472          $criteria= array ('recipient' => $this->get('id'));
 473          if ($read) {
 474              $criteria['messageread']= $read;
 475          }
 476          return $this->xpdo->getCount('modUserMessage', $criteria);
 477      }
 478  
 479      /**
 480       * Gets all user settings in array format.
 481       *
 482       * @access public
 483       * @return array A key -> value array of settings.
 484       */
 485      public function getSettings() {
 486          $settings = array();
 487          $uss = $this->getMany('UserSettings');
 488          /** @var modUserSetting $us */
 489          foreach ($uss as $us) {
 490              $settings[$us->get('key')] = $us->get('value');
 491          }
 492          $this->settings = $settings;
 493          return $settings;
 494      }
 495  
 496      /**
 497       * Gets all Resource Groups this user is assigned to. This may not work in
 498       * the new model.
 499       *
 500       * @access public
 501       * @param string $ctx The context in which to peruse for Resource Groups
 502       * @return array An array of Resource Group names.
 503       */
 504      public function getResourceGroups($ctx = '') {
 505          if (empty($ctx) && is_object($this->xpdo->context)) $ctx = $this->xpdo->context->get('key');
 506          $resourceGroups= array ();
 507          $id = $this->get('id') ? (string) $this->get('id') : '0';
 508          if (isset($_SESSION["modx.user.{$id}.resourceGroups"][$ctx])) {
 509              $resourceGroups= $_SESSION["modx.user.{$id}.resourceGroups"][$ctx];
 510          } else {
 511              $this->loadAttributes('modAccessResourceGroup',$ctx,true);
 512              if (isset($_SESSION["modx.user.{$id}.resourceGroups"][$ctx])) {
 513                  $resourceGroups= $_SESSION["modx.user.{$id}.resourceGroups"][$ctx];
 514              }
 515          }
 516          return $resourceGroups;
 517      }
 518  
 519      /**
 520       * Gets all the User Group IDs of the groups this user belongs to.
 521       *
 522       * @access public
 523       * @return array An array of User Group IDs.
 524       */
 525      public function getUserGroups() {
 526          $groups= array();
 527          $id = $this->get('id') ? (string) $this->get('id') : '0';
 528          if (isset($_SESSION["modx.user.{$id}.userGroups"]) && $this->xpdo->user->get('id') == $this->get('id')) {
 529              $groups= $_SESSION["modx.user.{$id}.userGroups"];
 530          } else {
 531              $memberGroups= $this->xpdo->getCollectionGraph('modUserGroup', '{"UserGroupMembers":{}}', array('UserGroupMembers.member' => $this->get('id')));
 532              if ($memberGroups) {
 533                  /** @var modUserGroup $group */
 534                  foreach ($memberGroups as $group) $groups[]= $group->get('id');
 535              }
 536              $_SESSION["modx.user.{$id}.userGroups"]= $groups;
 537          }
 538          return $groups;
 539      }
 540  
 541      /**
 542       * Return the Primary Group of this User
 543       *
 544       * @return modUserGroup|null
 545       */
 546      public function getPrimaryGroup() {
 547          if (!$this->isAuthenticated($this->xpdo->context->get('key'))) {
 548              return null;
 549          }
 550          $userGroup = $this->getOne('PrimaryGroup');
 551          if (!$userGroup) {
 552              $c = $this->xpdo->newQuery('modUserGroup');
 553              $c->innerJoin('modUserGroupMember','UserGroupMembers');
 554              $c->where(array(
 555                  'UserGroupMembers.member' => $this->get('id'),
 556              ));
 557              $c->sortby('UserGroupMembers.rank','ASC');
 558              $userGroup = $this->xpdo->getObject('modUserGroup',$c);
 559          }
 560          return $userGroup;
 561      }
 562  
 563      /**
 564       * Gets all the User Group names of the groups this user belongs to.
 565       *
 566       * @access public
 567       * @return array An array of User Group names.
 568       */
 569      public function getUserGroupNames() {
 570          $groupNames= array();
 571          $id = $this->get('id') ? (string) $this->get('id') : '0';
 572          if (isset($_SESSION["modx.user.{$id}.userGroupNames"]) && $this->xpdo->user->get('id') == $this->get('id')) {
 573              $groupNames= $_SESSION["modx.user.{$id}.userGroupNames"];
 574          } else {
 575              $memberGroups= $this->xpdo->getCollectionGraph('modUserGroup', '{"UserGroupMembers":{}}', array('UserGroupMembers.member' => $this->get('id')));
 576              if ($memberGroups) {
 577                  /** @var modUserGroup $group */
 578                  foreach ($memberGroups as $group) $groupNames[]= $group->get('name');
 579              }
 580              $_SESSION["modx.user.{$id}.userGroupNames"]= $groupNames;
 581          }
 582          return $groupNames;
 583      }
 584  
 585      /**
 586       * States whether a user is a member of a group or groups. You may specify
 587       * either a string name of the group, or an array of names.
 588       *
 589       * @access public
 590       * @param string|array $groups Either a string of a group name or an array
 591       * of names.
 592       * @param boolean $matchAll If true, requires the user to be a member of all
 593       * the groups specified. If false, the user can be a member of only one to
 594       * pass. Defaults to false.
 595       * @return boolean True if the user is a member of any of the groups
 596       * specified.
 597       */
 598      public function isMember($groups,$matchAll = false) {
 599          $isMember= false;
 600          $groupNames= $this->getUserGroupNames();
 601          if ($groupNames) {
 602              if (is_array($groups)) {
 603                  if ($matchAll) {
 604                      $matches= array_diff($groups, $groupNames);
 605                      $isMember= empty($matches);
 606                  } else {
 607                      $matches= array_intersect($groups, $groupNames);
 608                      $isMember= !empty($matches);
 609                  }
 610              } else {
 611                  $isMember= (array_search($groups, $groupNames) !== false);
 612              }
 613          }
 614          return $isMember;
 615      }
 616  
 617      /**
 618       * Join a User Group, and optionally assign a Role.
 619       *
 620       * @access public
 621       * @param mixed $groupId Either the name or ID of the User Group to join.
 622       * @param mixed $roleId Optional. Either the name or ID of the Role to
 623       * assign to for the group.
 624       * @return boolean True if successful.
 625       */
 626      public function joinGroup($groupId,$roleId = null) {
 627          $joined = false;
 628  
 629          $groupPk = is_string($groupId) ? array('name' => $groupId) : $groupId;
 630          /** @var modUserGroup $userGroup */
 631          $userGroup = $this->xpdo->getObject('modUserGroup',$groupPk);
 632          if (empty($userGroup)) {
 633              $this->xpdo->log(xPDO::LOG_LEVEL_ERROR,'User Group not found with key: '.$groupId);
 634              return $joined;
 635          }
 636  
 637          /** @var modUserGroupRole $role */
 638          if (!empty($roleId)) {
 639              $rolePk = is_string($roleId) ? array('name' => $roleId) : $roleId;
 640              $role = $this->xpdo->getObject('modUserGroupRole',$rolePk);
 641              if (empty($role)) {
 642                  $this->xpdo->log(xPDO::LOG_LEVEL_ERROR,'Role not found with key: '.$role);
 643                  return $joined;
 644              }
 645          }
 646  
 647          /** @var modUserGroupMember $member */
 648          $member = $this->xpdo->getObject('modUserGroupMember',array(
 649              'member' => $this->get('id'),
 650              'user_group' => $userGroup->get('id'),
 651          ));
 652          if (empty($member)) {
 653              $member = $this->xpdo->newObject('modUserGroupMember');
 654              $member->set('member',$this->get('id'));
 655              $member->set('user_group',$userGroup->get('id'));
 656              if (!empty($role)) {
 657                  $member->set('role',$role->get('id'));
 658              }
 659              $joined = $member->save();
 660              if (!$joined) {
 661                  $this->xpdo->log(xPDO::LOG_LEVEL_ERROR,'An unknown error occurred preventing adding the User to the User Group.');
 662              } else {
 663                  unset($_SESSION["modx.user.{$this->get('id')}.userGroupNames"]);
 664              }
 665          } else {
 666              $joined = true;
 667          }
 668          return $joined;
 669      }
 670  
 671      /**
 672       * Removes the User from the specified User Group.
 673       *
 674       * @access public
 675       * @param mixed $groupId Either the name or ID of the User Group to join.
 676       * @return boolean True if successful.
 677       */
 678      public function leaveGroup($groupId) {
 679          $left = false;
 680  
 681          $c = $this->xpdo->newQuery('modUserGroupMember');
 682          $c->innerJoin('modUserGroup','UserGroup');
 683          $c->where(array('member' => $this->get('id')));
 684  
 685          $fk = is_string($groupId) ? 'name' : 'id';
 686          $c->where(array(
 687              'member' => $this->get('id'),
 688              'UserGroup.'.$fk => $groupId,
 689          ));
 690  
 691          /** @var modUserGroupMember $member */
 692          $member = $this->xpdo->getObject('modUserGroupMember',$c);
 693          if (empty($member)) {
 694              $this->xpdo->log(xPDO::LOG_LEVEL_ERROR,'User could not leave group with key "'.$groupId.'" because the User was not a part of that group.');
 695          } else {
 696              $left = $member->remove();
 697              if (!$left) {
 698                  $this->xpdo->log(xPDO::LOG_LEVEL_ERROR,'An unknown error occurred preventing removing the User from the User Group.');
 699              } else {
 700                  unset($_SESSION["modx.user.{$this->get('id')}.userGroupNames"]);
 701              }
 702          }
 703          return $left;
 704      }
 705  
 706      /**
 707       * Remove any locks held by the user.
 708       *
 709       * @param array $options An array of options for controlling removal of specific locks or lock
 710       * types.
 711       * @return boolean True if the process was successful, or false if an error was encountered.
 712       */
 713      public function removeLocks(array $options = array()) {
 714          $removed = false;
 715          if ($this->xpdo instanceof modX) {
 716              if ($this->xpdo->getService('registry', 'registry.modRegistry')) {
 717                  $this->xpdo->registry->addRegister('locks', 'registry.modDbRegister', array('directory' => 'locks'));
 718                  $this->xpdo->registry->locks->connect();
 719  
 720                  $this->xpdo->registry->locks->subscribe('/resource/');
 721                  if ($msgs = $this->xpdo->registry->locks->read(array('remove_read' => false, 'poll_limit' => 1))) {
 722                      foreach ($msgs as $resource => $user) {
 723                          if ($user == $this->get('id')) {
 724                              $this->xpdo->registry->locks->subscribe('/resource/' . md5($resource));
 725                              $this->xpdo->registry->locks->read(array('remove_read' => true, 'poll_limit' => 1));
 726                          }
 727                      }
 728                  }
 729                  $removed = true;
 730              }
 731          }
 732          return $removed;
 733      }
 734  
 735      /**
 736       * Returns a randomly generated password
 737       *
 738       * @param integer $length The length of the password
 739       * @param array $options
 740       * @return string The newly generated password
 741       */
 742      public function generatePassword($length = 10,array $options = array()) {
 743          $options = array_merge(array(
 744              'allowable_characters' => 'abcdefghjkmnpqrstuvxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789',
 745              'srand_seed_multiplier' => 1000000,
 746          ),$options);
 747  
 748          $ps_len = strlen($options['allowable_characters']);
 749          srand((double) microtime() * $options['srand_seed_multiplier']);
 750          $pass = '';
 751          for ($i = 0; $i < $length; $i++) {
 752              $pass .= $options['allowable_characters'][mt_rand(0, $ps_len -1)];
 753          }
 754          return $pass;
 755      }
 756  
 757      /**
 758       * Send an email to the user
 759       *
 760       * @param string $message The body of the email
 761       * @param array $options An array of options
 762       * @return boolean True if successful
 763       */
 764      public function sendEmail($message,array $options = array()) {
 765          if (!($this->xpdo instanceof modX)) return false;
 766          $profile = $this->getOne('Profile');
 767          if (empty($profile)) return false;
 768  
 769          $this->xpdo->getService('mail', 'mail.modPHPMailer');
 770          if (!$this->xpdo->mail) return false;
 771          
 772          $this->xpdo->mail->set(modMail::MAIL_BODY, $message);
 773          $this->xpdo->mail->set(modMail::MAIL_FROM, $this->xpdo->getOption('from',$options,$this->xpdo->getOption('emailsender')));
 774          $this->xpdo->mail->set(modMail::MAIL_FROM_NAME, $this->xpdo->getOption('fromName',$options,$this->xpdo->getOption('site_name')));
 775          $this->xpdo->mail->set(modMail::MAIL_SENDER, $this->xpdo->getOption('sender',$options,$this->xpdo->getOption('emailsender')));
 776          $this->xpdo->mail->set(modMail::MAIL_SUBJECT, $this->xpdo->getOption('subject',$options,$this->xpdo->getOption('emailsubject')));
 777          $this->xpdo->mail->address('to',$profile->get('email'),$profile->get('fullname'));
 778          $this->xpdo->mail->address('reply-to',$this->xpdo->getOption('sender',$options,$this->xpdo->getOption('emailsender')));
 779          $this->xpdo->mail->setHTML($this->xpdo->getOption('html',$options,true));
 780          if ($this->xpdo->mail->send() == false) {
 781              return false;
 782          }
 783          $this->xpdo->mail->reset();
 784          return true;
 785      }
 786  
 787      /**
 788       * Get the dashboard for this user
 789       *
 790       * @return modDashboard
 791       */
 792      public function getDashboard() {
 793          $this->xpdo->loadClass('modDashboard');
 794  
 795          /** @var modUserGroup $userGroup */
 796          $userGroup = $this->getPrimaryGroup();
 797          if ($userGroup) {
 798              /** @var modDashboard $dashboard */
 799              $dashboard = $userGroup->getOne('Dashboard');
 800              if (empty($dashboard)) {
 801                  $dashboard = modDashboard::getDefaultDashboard($this->xpdo);
 802              }
 803          } else {
 804              $dashboard = modDashboard::getDefaultDashboard($this->xpdo);
 805          }
 806          return $dashboard;
 807      }
 808  }

title

Description

title

Description

title

Description

title

title

Body