/** * Adds a device to the system, after sending a test notification to it * @param {array} $device * @param {string} $device.userId * @param {string} $device.deviceId * @param {string} [$device.formFactor] * @param {string} [$device.platform] * @param {string} [$device.version] * @param {string} [$device.sessionId] * @param {boolean} [$device.sandbox] * @param {string} [$device.passphrase] * @param {boolean} [$skipNotification=false] if true, skips sending notification * @return {Users_Device} */ static function add($device, $skipNotification = false) { Q_Valid::requireFields(array('userId', 'deviceId'), $device, true); $userId = $device['userId']; $deviceId = $device['deviceId']; if (!$skipNotification) { $app = Q::app(); $sandbox = Q::ifset($device, 'sandbox', null); if (!isset($sandbox)) { $sandbox = Q_Config::get($app, "cordova", "ios", "sandbox", false); } $env = $sandbox ? ApnsPHP_Abstract::ENVIRONMENT_SANDBOX : ApnsPHP_Abstract::ENVIRONMENT_PRODUCTION; $s = $sandbox ? 'sandbox' : 'production'; $cert = APP_LOCAL_DIR . DS . 'Users' . DS . 'certs' . DS . $app . DS . $s . DS . 'bundle.pem'; $authority = USERS_PLUGIN_FILES_DIR . DS . 'Users' . DS . 'certs' . DS . 'EntrustRootCA.pem'; $logger = new Users_ApnsPHP_Logger(); $push = new ApnsPHP_Push($env, $cert); $push->setLogger($logger); $push->setRootCertificationAuthority($authority); if (isset($device['passphrase'])) { $push->setProviderCertificatePassphrase($device['passphrase']); } $push->connect(); $message = new ApnsPHP_Message($deviceId); $message->setCustomIdentifier('Users_Device-adding'); $message->setBadge(0); $message->setText(Q_Config::get($app, "cordova", "ios", "device", "text", "Notifications have been enabled")); $message->setCustomProperty('userId', $userId); $message->setExpiry(5); $push->add($message); $push->send(); $push->disconnect(); $errors = $push->getErrors(); if (!empty($errors)) { $result = reset($errors); throw new Users_Exception_DeviceNotification($result['ERRORS'][0]); } } $sessionId = Q_Session::id(); $user = Users::loggedInUser(); $info = array_merge(Q_Request::userAgentInfo(), array('sessionId' => $sessionId, 'userId' => $user ? $user->id : null, 'deviceId' => null)); $device2 = Q::take($device, $info); $d = new Users_Device($device2); $d->save(true); if ($sessionId) { $s = new Users_Session(); $s->id = $sessionId; if (!$s->retrieve()) { $s->deviceId = $deviceId; } } $_SESSION['Users']['deviceId'] = $deviceId; $device2['Q/method'] = 'Users/device'; Q_Utils::sendToNode($device2); return $d; }
/** * This tool renders all user sessions opened. * * @param {array} $options An associative array of parameters, containing: * @param {string} [$options.userId] * The user's id. Defaults to id of the logged-in user, if any. * @param {bool} [$options.editable=true] * Whether user can delete sessions * @param {bool} [$options.devices=true] * Whether to show devices info */ function Users_sessions_tool($options) { $options = array_merge(array('editable' => true, 'devices' => true), $options); if (empty($options['userId'])) { $options['userId'] = Users::loggedInUser(true)->id; } Q_Response::addStylesheet('plugins/Users/css/tools/sessions.css'); Q_Response::setToolOptions($options); $sessions = Users_Session::select("us.*, ud.deviceId, ud.platform, ud.version, ud.formFactor", "us")->join(Users_Device::table() . ' ud', array('us.userId' => 'ud.userId', 'us.id' => 'ud.sessionId'), "LEFT")->where(array('us.userId' => $options['userId']))->fetchDbRows(); $noDevicesClass = $options['devices'] ? '' : "Users_sessions_noDevices"; $html = "<table class='Users_sessions_container {$noDevicesClass}'><tr><th>Session Id</th><th class='Users_sessions_devicesData'>Platform</th><th class='Users_sessions_devicesData'>Version</th><th>Last Updated</th>"; if ($options["editable"]) { $html .= '<th class="Users_sessions_actions"></th>'; } $html .= '</tr>'; foreach ($sessions as $session) { $updatedTime = date("M j, Y g:i A", strtotime($session->updatedTime)); $html .= "<tr><td class='Users_sessions_sessionId'>{$session->id}</td>" . "<td class='Users_sessions_devicesData'>{$session->platform}</td>" . "<td class='Users_sessions_devicesData'>{$session->version}</td>" . "<td>{$updatedTime}</td>"; if ($options["editable"]) { $html .= "<td class='Users_sessions_actions'><button name='delete'>Delete</button></td>"; } $html .= '</tr>'; } $html .= "</table>"; return $html; }
/** * Adds a device to the current user id and session. * See Users_Device::add method for more details. * @param {string} $deviceId * @return {void} */ function Users_device_post() { Q_Request::requireFields(array('deviceId')); $deviceId = $_REQUEST['deviceId']; $user = Users::loggedInUser(true); $device = Users_Device::add(array_merge($_REQUEST, array('userId' => $user->id))); Q_Response::setSlot('data', $device); }
function Users_device_post() { $user = Users::loggedInUser(true); $token = isset($_REQUEST['token']) ? $_REQUEST['token'] : null; $platform = Q_Request::platform(); $version = Q_Request::OSVersion(); $formFactor = Q_Request::isMobile() ? 'mobile' : (Q_Request::isTablet() ? 'tablet' : null); $device = new Users_Device(); $device->userId = $user->id; $device->deviceId = $token; $device->platform = $platform; $device->version = $version; $device->formFactor = $formFactor; $device->sessionId = Q_Session::id(); $_SESSION['Users']['deviceId'] = $token; Q_Response::setSlot('data', !!$device->save(true)); Q_Utils::sendToNode(array("Q/method" => "Users/device", "userId" => $user->id, "deviceId" => $token)); }
function Users_oAuth_post() { // Validate the inputs $fields = array('response_type', 'token_type', 'access_token', 'expires_in', 'scope', 'state', 'Q_Users_oAuth'); Q_Request::requireFields($fields, true); $params = Q::take($_REQUEST, $fields); $params['Q.Users.oAuth'] = $params['Q_Users_oAuth']; unset($params['Q_Users_oAuth']); Q_Valid::signature(true, $params, array('Q.Users.oAuth')); // Set the session id to the access_token Q_Session::id($params['access_token']); // Add a device, if any if ($deviceId = Q::ifset($_REQUEST, 'deviceId', null)) { $fields2 = array('deviceId', 'platform', 'version', 'formFactor'); Q_Request::requireFields($fields2); $device = Q::take($_REQUEST, $fields2); $device['userId'] = Users::loggedInUser(true)->id; Users_Device::add($device); } }
/** * Registers a user in the system. * @method register * @static * @param {string} $username The name of the user * @param {string|array} $identifier Can be an email address or mobile number. Or it could be an array of $type => $info * @param {string} [$identifier.identifier] an email address or phone number * @param {array} [$identifier.device] an array with keys "deviceId", "platform", "version" * to store in the Users_Device table for sending notifications * @param {array|string} [$icon=array()] Array of filename => url pairs * @param {string} [$provider=null] Provider such as "facebook" * @param {array} [$options=array()] An array of options that could include: * @param {string} [$options.activation] The key under "Users"/"transactional" config to use for sending an activation message. Set to false to skip sending the activation message for some reason. * @return {Users_User} * @throws {Q_Exception_WrongType} If identifier is not e-mail or modile * @throws {Q_Exception} If user was already verified for someone else * @throws {Users_Exception_AlreadyVerified} If user was already verified * @throws {Users_Exception_UsernameExists} If username exists */ static function register($username, $identifier, $icon = array(), $provider = null, $options = array()) { if (is_array($provider)) { $options = $provider; $provider = null; } /** * @event Users/register {before} * @param {string} username * @param {string|array} identifier * @param {string} icon * @param {string} provider * @return {Users_User} */ $return = Q::event('Users/register', compact('username', 'identifier', 'icon', 'provider', 'options'), 'before'); if (isset($return)) { return $return; } $during = 'register'; if (is_array($identifier)) { reset($identifier); switch (key($identifier)) { case 'device': $fields = array('deviceId', 'platform', 'version'); Q_Valid::requireFields($fields, $identifier, true); $device = $identifier; if (isset($identifier['identifier'])) { $identifier = $identifier['identifier']; } break; default: throw new Q_Exception_WrongType(array('field' => 'identifier', 'type' => 'an array with entry named "device"')); } } if (Q_Valid::email($identifier, $emailAddress)) { $ui_identifier = $emailAddress; $key = 'email address'; $type = 'email'; } else { if (Q_Valid::phone($identifier, $mobileNumber)) { $key = 'mobile number'; $ui_identifier = $mobileNumber; $type = 'mobile'; } else { throw new Q_Exception_WrongType(array('field' => 'identifier', 'type' => 'email address or mobile number'), array('emailAddress', 'mobileNumber')); } } $user = false; if ($provider) { if ($provider != 'facebook') { throw new Q_Exception_WrongType(array('field' => 'provider', 'type' => '"facebook"')); } $facebook = Users::facebook(); if ($facebook) { $uid = $facebook->getUser(); try { // authenticate (and possibly adopt) an existing provider user // or insert a new user during this authentication $user = Users::authenticate($provider, null, $authenticated, true); } catch (Exception $e) { } if ($user) { // the user is also logged in $adopted = true; // Adopt this provider user /** * @event Users/adoptFutureUser {before} * @param {Users_User} user * @param {string} during * @return {Users_User} */ $ret = Q::event('Users/adoptFutureUser', compact('user', 'during'), 'before'); if ($ret) { $user = $ret; } } } } if (!$user) { $user = new Users_User(); // the user we will save in the database } if (empty($adopted)) { // We will be inserting a new user into the database, so check if // this identifier was already verified for someone else. $ui = Users::identify($type, $ui_identifier); if ($ui) { throw new Users_Exception_AlreadyVerified(compact('key'), array('emailAddress', 'mobileNumber', 'identifier')); } } // Insert a new user into the database, or simply modify an existing (adopted) user $user->username = $username; if (!isset($user->signedUpWith) or $user->signedUpWith == 'none') { $user->signedUpWith = $type; } $user->icon = 'default'; $user->passphraseHash = ''; $url_parts = parse_url(Q_Request::baseUrl()); if (isset($url_parts['host'])) { // By default, the user's url would be this: $user->url = $username ? "http://{$username}." . $url_parts['host'] : ""; } /** * @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'); $sizes = Q_Config::expect('Users', 'icon', 'sizes'); sort($sizes); if (empty($icon)) { switch ($provider) { case 'facebook': // let's get this user's icon on facebook if (empty($uid)) { break; } $icon = array(); foreach ($sizes as $size) { $icon["{$size}.png"] = "https://graph.facebook.com/{$uid}/picture?width={$size}&height={$size}"; } break; } } else { // Import the user's icon and save it if (is_string($icon)) { // assume it's from gravatar $iconString = $icon; $icon = array(); foreach ($sizes as $size) { $icon["{$size}.png"] = "{$iconString}&s={$size}"; } } else { // locally generated icons $hash = md5(strtolower(trim($identifier))); $icon = array(); foreach ($sizes as $size) { $icon["{$size}.png"] = array('hash' => $hash, 'size' => $size); } } } if (!Q_Config::get('Users', 'register', 'icon', 'leaveDefault', false)) { self::importIcon($user, $icon); $user->save(); } if (empty($user->emailAddress) and empty($user->mobileNumber)) { // Add an email address or mobile number to the user, that they'll have to verify try { $activation = Q::ifset($options, 'activation', 'activation'); if ($activation) { $subject = Q_Config::get('Users', 'transactional', $activation, "subject", null); $body = Q_Config::get('Users', 'transactional', $activation, "body", null); } else { $subject = $body = null; } if ($type === 'email') { $user->addEmail($identifier, $subject, $body, array(), $options); } else { if ($type === 'mobile') { $p = $options; if ($delay = Q_Config::get('Users', 'register', 'delaySms', 0)) { $p['delay'] = $delay; } $sms = Q_Config::get('Users', 'transactional', $activation, "sms", null); $user->addMobile($mobileNumber, $sms, array(), $p); } } } catch (Exception $e) { // The activation message could not be sent, so remove this user // from the database. This way, this username will be // back on the market. $user->remove(); throw $e; } } if (!empty($device)) { $device['userId'] = $user->id; Users_Device::add($device); } /** * @event Users/register {after} * @param {string} username * @param {string|array} identifier * @param {string} icon * @param {Users_User} user * @param {string} provider * @return {Users_User} */ $return = Q::event('Users/register', compact('username', 'identifier', 'icon', 'user', 'provider', 'options', 'device'), 'after'); return $user; }
/** * Logs a user out * @method logout * @static */ static function logout() { // Access the session, if we haven't already. $user = self::loggedInUser(); $sessionId = Q_Session::id(); // One last chance to do something. // Hooks shouldn't be able to cancel the logout. /** * @event Users/logout {before} * @param {Users_User} user */ Q::event('Users/logout', compact('user'), 'before'); $deviceId = isset($_SESSION['Users']['deviceId']) ? $_SESSION['Users']['deviceId'] : null; $device = new Users_Device(); $device->sessionId = $sessionId; // WARNING: NON-PK LOOKUP. Should store device id in session! if ($user) { Q_Utils::sendToNode(array("Q/method" => "Users/logout", "sessionId" => Q_Session::id(), "userId" => $user->id, "deviceId" => $deviceId)); // forget the device for this user/session Users_Device::delete()->where(array('userId' => $user->id, 'sessionId' => $sessionId))->execute(); } // Destroy the current session, which clears the $_SESSION and all notices, etc. Q_Session::destroy(); }