/** * Returns a user in the database that will correspond to a new user in the future * once they authenticate or follow an invite. * Inserts a new user if one doesn't already exist. * * @method futureUser * @param {string} $type Could be one of "email", "mobile", "email_hashed", "mobile_hashed", "facebook", "twitter" or "none". * @param {string} $value The value corresponding to the type. If $type is: * * * "email" - this is one of the user's email addresses * * "mobile" - this is one of the user's mobile numbers * * "email_hashed" - this is the email, already hashed with Q_Utils::hash() * * "mobile_hashed" - this is the email, already hashed with Q_Utils::hash() * * "facebook" - this is the user's id on facebook * * "twitter" - this is the user's id on twitter * * "none" - the type is ignored, no "identify" rows are inserted into the db, etc. * * With every type except "none", the user will be * * NOTE: If the person we are representing here comes and registers the regular way, * and then later adds an email, mobile, or authenticates with a provider, * which happens to match the "future" mapping we inserted in users_identify table, * then this futureUser will not be converted, since they already registered * a different user. Later on, we may have some sort function to merge users together. * * @param {&string} [$status=null] The status of the user - 'verified' or 'future' * @return {Users_User} * @throws {Q_Exception_WrongType} If $type is not supported * @throws {Q_Exception_MissingRow} If identity for user exists but user does not exists */ static function futureUser($type, $value, &$status = null) { if (!array_key_exists($type, self::$types)) { throw new Q_Exception_WrongType(array('field' => 'type', 'type' => 'one of the supported types')); } if ($type !== 'none') { $ui = Users::identify($type, $value, null); if ($ui && !empty($ui->userId)) { $user = new Users_User(); $user->id = $ui->userId; if ($user->retrieve()) { $status = $ui->state; return $user; } else { $userId = $ui->userId; throw new Q_Exception_MissingRow(array('table' => 'user', 'criteria' => 'that id'), 'userId'); } } } // Make a user row to represent a "future" user and give them an empty username $user = new Users_User(); if ($field = self::$types[$type]) { $user->{$field} = $value; } $user->signedUpWith = 'none'; // this marks it as a future user for now $user->username = ""; $user->icon = 'future'; $during = 'future'; /** * @event Users/insertUser {before} * @param {string} during * @param {Users_User} 'user' */ Q::event('Users/insertUser', compact('user', 'during'), 'before'); $user->save(); // sets the user's id /** * @event Users/insertUser {after} * @param {string} during * @param {Users_User} user */ Q::event('Users/insertUser', compact('user', 'during'), 'after'); if ($type != 'email' and $type != 'mobile') { if ($type !== 'none') { // Save an identifier => user pair for this future user $ui = new Users_Identify(); $ui->identifier = "{$type}:{$value}"; $ui->state = 'future'; if (!$ui->retrieve()) { $ui->userId = $user->id; $ui->save(); } $status = $ui->state; } else { $status = 'future'; } } else { // Save hashed version $ui = new Users_Identify(); $hashed = Q_Utils::hash($value); $ui->identifier = $type . "_hashed:{$hashed}"; $ui->state = 'future'; if (!$ui->retrieve()) { $ui->userId = $user->id; $ui->save(); } $status = $ui->state; } return $user; }
/** * @method setMobileNumber * @param {string} $mobileNumber * @param {boolean} [$verified=false] * @throws {Q_Exception_MissingRow} * If mobile number is missing * @throws {Users_Exception_AlreadyVerified} * If user was already verified * @throws {Users_Exception_WrongState} * If verification state is wrong */ function setMobileNumber($mobileNumber, $verified = false) { Q_Valid::phone($mobileNumber, $normalized); $mobile = new Users_Mobile(); $mobile->number = $normalized; $retrieved = $mobile->retrieve('*', array('ignoreCache' => true)); if (empty($mobile->activationCode)) { $mobile->activationCode = ''; $mobile->activationCodeExpires = '0000-00-00 00:00:00'; } $mobile->authCode = md5(microtime() + mt_rand()); if ($verified) { $mobile->userId = $this->id; } else { if (!$retrieved) { throw new Q_Exception_MissingRow(array('table' => "a mobile phone", 'criteria' => "number {$normalized}"), 'mobileNumber'); } if ($mobile->userId != $this->id) { // We're going to tell them it's verified for someone else, // even though it may not have been verified yet. // In the future, might throw a more accurate exception. throw new Users_Exception_AlreadyVerified(array('key' => 'mobile number', 'userId' => $mobile->userId)); } if (!in_array($mobile->state, array('unverified', 'active'))) { throw new Users_Exception_WrongState(array('key' => $mobile->number, 'state' => $mobile->state), 'mobileNumber'); } } // Everything is okay. Assign it! $mobile->state = 'active'; $mobile->save(); $ui = new Users_Identify(); $ui->identifier = "mobile_hashed:" . Q_Utils::hash($normalized); $ui->state = 'verified'; $ui->userId = $this->id; $ui->save(true); $this->mobileNumberPending = ''; $this->mobileNumber = $normalized; $this->save(); $user = $this; /** * @event Users/setMobileNumber {after} * @param {string} user * @param {string} mobile */ Q::event('Users/setMobileNumber', compact('user', 'mobile'), 'after'); return true; }