function Users_before_Q_response_notices() { $from_parts = explode(' ', Q_Request::special('fromSuccess', false)); $from = reset($from_parts); if ($from === 'Users/activate') { $user = Q_Session::id() ? Users::loggedInUser() : null; $notice = $user ? "You've completed the activation." : "You've completed the activation. Try logging in now."; Q_Response::setNotice('Users/activate', $notice, true); } else { if ($from === 'Users/resend') { $notice = 'Your activation message has been re-sent. You should get it in a moment.'; Q_Response::setNotice('Users/resend', $notice, true); } } }
function Streams_stream_response_content() { $publisherId = Streams::requestedPublisherId(true); $name = Streams::requestedName(true); $fields = Streams::requestedFields(); $user = Users::loggedInUser(); $userId = $user ? $user->id : 0; $stream = isset(Streams::$cache['stream']) ? Streams::$cache['stream'] : null; if (!isset($stream)) { throw new Q_Exception_MissingRow(array('table' => 'stream', 'criteria' => 'that name')); } if ($publisherId != $userId and !$stream->testReadLevel('content')) { Q_Response::setNotice('Streams/stream/response/content', 'This content is hidden from you.', true); return ''; } // show stream as usual return Q::view('Streams/content/stream.php', compact('publisherId', 'name', 'fields', 'user', 'stream')); }
function Users_activate_post() { Q_Valid::nonce(true); $email = $mobile = $type = $user = null; extract(Users::$cache, EXTR_IF_EXISTS); if (isset($_REQUEST['passphrase'])) { if (empty($_REQUEST['passphrase'])) { throw new Q_Exception("You can't set a blank passphrase.", 'passphrase'); } $isHashed = !empty($_REQUEST['isHashed']); if ($isHashed and $isHashed !== 'true' and intval($_REQUEST['isHashed']) > 1) { // this will let us introduce other values for isHashed in the future throw new Q_Exception("Please set isHashed to 0 or 1", 'isHashed'); } // Save the pass phrase even if there may be a problem adding an email later. // At least the user will be able to log in. $user->passphraseHash = $user->computePassphraseHash($_REQUEST['passphrase'], $isHashed); Q_Response::setNotice("Users/activate/passphrase", "Your pass phrase has been saved.", true); // Log the user in, since they were able to set the passphrase Users::setLoggedInUser($user); // This also saves the user. if (empty($user->passphraseHash)) { throw new Q_Exception("Please set a pass phrase on your account", 'passphrase', true); } } if ($type) { if ($type == 'email address') { $user->setEmailAddress($email->address); // may throw exception } else { if ($type == 'mobile number') { $user->setMobileNumber($mobile->number); // may throw exception } } // Log the user in, since they have just added an email to their account Users::setLoggedInUser($user); // This also saves the user. Q_Response::removeNotice('Users/activate/objects'); Q_Response::setNotice("Users/activate/activated", "Your {$type} has been activated.", true); } Users::$cache['passphrase_set'] = true; Users::$cache['success'] = true; }
function Users_after_Users_addIdentifier($params) { extract($params); if (!Q_Config::get('Users', 'notices', 'identifier', true)) { return; } $loggedInUser = Users::loggedInUser(); if (!$loggedInUser or $loggedInUser->id !== $user->id) { return; } if (isset($email)) { $resend_button = "<button id='notices_set_email' class='Q_button'>Need it re-sent?</button>"; Q_Response::setNotice('Users/email', "Please check your email for an activation link. {$resend_button}"); } else { if (isset($mobile)) { $resend_button = "<button id='notices_set_mobile' class='Q_button'>Need it re-sent?</button>"; Q_Response::setNotice('Users/mobile', "Please check your mobile phone for an activation message. {$resend_button}"); } } }
/** * Send e-mail message * @method sendMessage * @param {string} $subject * The subject. May contain variable references to members * of the $fields array. * @param {string} $view * The name of a view for the body. Fields are passed to it. * @param {array} $fields=array() * The fields referenced in the subject and/or view * @param {array} $options=array() * Array of options. Can include:<br/> * "html" => Defaults to false. Whether to send as HTML email.<br/> * "name" => A human-readable name in addition to the address.<br/> * "from" => An array of (emailAddress, human_readable_name)<br/> * "delay" => A delay, in milliseconds, to wait until sending email. Only works if Node server is listening. */ function sendMessage($subject, $view, $fields = array(), $options = array()) { /** * @event Users/email/sendMessage {before} * @param {string} subject * @param {string} view * @param {array} fields * @param {array} options * @return {boolean} */ $result = Q::event('Users/email/sendMessage', compact('subject', 'view', 'fields', 'options'), 'before'); if (isset($result)) { return $result; } if (!Q_Valid::email($this->address, $emailAddress)) { throw new Q_Exception_WrongType(array('field' => '$this->address', 'type' => 'email address', 'emailAddress' => $this->address)); } $app = Q_Config::expect('Q', 'app'); $subject = Q_Handlebars::renderSource($subject, $fields); $body = Q::view($view, $fields); if (!Q_Config::get('Users', 'email', 'smtp', 'sendmail')) { Q_Response::setNotice("Q/email", "Please set up SMTP in Users/email/smtp as in docs.", false); return true; } $overrideLog = Q::event('Users/email/log', compact('emailAddress', 'subject', 'body'), 'before'); if (!isset($overrideLog) and $key = Q_Config::get('Users', 'email', 'log', 'key', null)) { Q::log("\nSent email message to {$emailAddress}:\n{$subject}\n{$body}", $key); } $from = Q::ifset($options, 'from', Q_Config::get('Users', 'email', 'from', null)); if (!isset($from)) { // deduce from base url $url_parts = parse_url(Q_Request::baseUrl()); $domain = $url_parts['host']; $from = array("email@{$domain}", $domain); } if (!is_array($from)) { throw new Q_Exception_WrongType(array('field' => '$options["from"]', 'type' => 'array')); } $sent = false; if (!empty($options['delay'])) { // Try to use Node.js to send the message $sent = Q_Utils::sendToNode(array("Q/method" => "Users/sendMessage", "delay" => $options['delay'], "emailAddress" => $emailAddress, "subject" => $subject, "body" => $body, "options" => $options)); } if (!$sent) { // Set up the default mail transport $smtp = Q_Config::get('Users', 'email', 'smtp', array('host' => 'sendmail')); $host = Q::ifset($smtp, 'host', 'sendmail'); if ($host === 'sendmail') { $transport = new Zend_Mail_Transport_Sendmail('-f' . reset($from)); } else { if (is_array($smtp)) { $host = $smtp['host']; unset($smtp['host']); } else { if (is_string($smtp)) { $host = $smtp; $smtp = null; } } $transport = new Zend_Mail_Transport_Smtp($host, $smtp); } $mail = new Zend_Mail(); $mail->setFrom(reset($from), next($from)); if (isset($options['name'])) { $mail->addTo($emailAddress, $options['name']); } else { $mail->addTo($emailAddress); } $mail->setSubject($subject); if (empty($options['html'])) { $mail->setBodyText($body); } else { $mail->setBodyHtml($body); } try { $mail->send($transport); } catch (Exception $e) { throw new Users_Exception_EmailMessage(array('error' => $e->getMessage())); } } /** * @event Users/email/sendMessage {after} * @param {string} subject * @param {string} view * @param {array} fields * @param {array} options * @param {string} mail */ Q::event('Users/email/sendMessage', compact('subject', 'view', 'fields', 'options', 'mail', 'app'), 'after'); return true; }
function Users_activate_objects_mobile($mobileNumber, &$mobile) { Q_Response::removeNotice('Users/activate/objects'); $mobile = new Users_Mobile(); if (!Q_Valid::phone($mobileNumber, $normalized)) { return; } $mobile->number = $normalized; if (!$mobile->retrieve()) { throw new Q_Exception_MissingRow(array('table' => 'mobile phone', 'criteria' => "number {$normalized}")); } $user = Users::loggedInUser(); if ($user) { if ($user->id != $mobile->userId) { throw new Q_Exception("You are logged in as a different user. Please log out and click the link again."); } } else { $user = new Users_User(); $user->id = $mobile->userId; if (!$user->retrieve()) { throw new Q_Exception_MissingRow(array('table' => 'user', 'criteria' => 'id = ' . $user->id)); } } if ($mobile->activationCode != $_REQUEST['code']) { throw new Q_Exception("The activation code does not match. Did you get a newer message?", 'code'); } $timestamp = Users_Mobile::db()->getCurrentTimestamp(); if ($timestamp > Users_Mobile::db()->fromDateTime($mobile->activationCodeExpires)) { throw new Q_Exception("Activation code expired"); } if (Q_Request::method() !== 'POST' and empty($_REQUEST['p']) and isset($user->mobileNumber) and $user->mobileNumber == $mobile->number) { Q_Response::setNotice('Users/activate/objects', "{$normalized} has already been activated for {$user->username}", true); return $user; } return $user; }
function Streams_before_Q_objects() { $token = Q_Request::special('Streams.token', null); if ($token === null) { return; } $invite = Streams_Invite::fromToken($token); if (!$invite) { throw new Q_Exception_MissingRow(array('table' => 'invite', 'criteria' => "token = '{$token}"), 'token'); } // did invite expire? $ts = Streams_Invite::db()->select("CURRENT_TIMESTAMP")->fetchAll(PDO::FETCH_NUM); if (isset($invite->expireTime) and $invite->expireTime < $ts[0][0]) { $invite->state = 'expired'; $invite->save(); } // is invite still pending? if ($invite->state !== 'pending') { switch ($invite->state) { case 'expired': $exception = new Streams_Exception_AlreadyExpired(null, 'token'); break; case 'accepted': $exception = new Streams_Exception_AlreadyAccepted(null, 'token'); break; case 'declined': $exception = new Streams_Exception_AlreadyDeclined(null, 'token'); break; case 'forwarded': $exception = new Streams_Exception_AlreadyForwarded(null, 'token'); break; default: $exception = new Q_Exception("This invite has already been " . $invite->state, 'token'); break; } $shouldThrow = Q::event('Streams/objects/inviteException', compact('invite', 'exception'), 'before'); if ($shouldThrow === null) { Q_Response::setNotice('Streams/objects', $exception->getMessage(), true); } else { if ($shouldThrow === true) { throw $exception; } } } // now process the invite $invitedUser = Users_User::fetch($invite->userId, true); $stream = Streams::fetchOne($invitedUser->id, $invite->publisherId, $invite->streamName); if (!$stream) { throw new Q_Exception_MissingRow(array('table' => 'stream', 'criteria' => "publisherId = '{$invite->publisherId}', name = '{$invite->streamName}'")); } $byUser = Users_User::fetch($invite->invitingUserId, true); $byStream = Streams::fetchOne($byUser->id, $invite->publisherId, $invite->streamName); if (!$byStream) { throw new Q_Exception_MissingRow(array('table' => 'stream', 'criteria' => "publisherId = '{$invite->publisherId}', name = '{$invite->streamName}'")); } $access = new Streams_Access(); $access->publisherId = $byStream->publisherId; $access->streamName = $byStream->name; $access->ofUserId = $invite->userId; $specified_access = false; foreach (array('readLevel', 'writeLevel', 'adminLevel') as $level_type) { $access->{$level_type} = -1; if (empty($invite->{$level_type})) { continue; } // Give access level from the invite. // However, if inviting user has a lower access level now, // then give that level instead, unless it is lower than // what the invited user would have had otherwise. $min = min($invite->{$level_type}, $byStream->get($level_type, 0)); if ($min > $stream->get($level_type, 0)) { $access->{$level_type} = $min; $specified_access = true; } } if ($specified_access) { $access->save(true); } // now log invited user in $user = Users::loggedInUser(); if (empty($user) or $user->id !== $invite->userId) { $user = new Users_User(); $user->id = $invite->userId; if (!$user->retrieve()) { // The user who was invited doesn't exist // This shouldn't happen. We just silently log it and return. Q::log("Sanity check failed: invite with {$invite->token} pointed to nonexistent user"); return; } Users::setLoggedInUser($user); } // accept invite and autosubscribe if first time if ($invite->accept() and !$stream->subscription($user->id)) { $stream->subscribe(); } // retain the invite object for further processing Streams::$followedInvite = $invite; }
/** * @method start * @static * @return {boolean} */ static function start() { if (self::id()) { // Session has already started return false; } /** * @event Q/session/start {before} * @return {false} * Return false to cancel session start */ if (false === Q::event('Q/session/start', array(), 'before')) { return false; } if (Q_Config::get('Q', 'session', 'custom', true)) { session_set_save_handler(array(__CLASS__, 'openHandler'), array(__CLASS__, 'closeHandler'), array(__CLASS__, 'readHandler'), array(__CLASS__, 'writeHandler'), array(__CLASS__, 'destroyHandler'), array(__CLASS__, 'gcHandler')); } if (!empty($_SESSION)) { $pre_SESSION = $_SESSION; } self::init(); $name = Q_Session::name(); $id = isset($_REQUEST[$name]) ? $_REQUEST[$name] : isset($_COOKIE[$name]) ? $_COOKIE[$name] : null; if (!self::isValidId($id)) { // The session id was probably not generated by us, generate a new one /** * @event Q/session/generate {before} * @param {string} id An invalid id, if any, that was passed by the client * @return {boolean} */ if (false === Q::event('Q/session/generate', compact('id'), 'before')) { return false; } $id = self::generateId(); } try { if ($id) { self::processDbInfo(); if (self::$session_db_connection) { $id_field = self::$session_db_id_field; $data_field = self::$session_db_data_field; $updated_field = self::$session_db_updated_field; $duration_field = self::$session_db_duration_field; $class = self::$session_db_row_class; $row = new $class(); $row->{$id_field} = $id; if ($row->retrieve(null, null, array('lock' => 'FOR UPDATE'))) { self::$session_db_row = $row; } else { // Start a new session with our own id $row->{$id_field} = self::generateId(); $row->{$data_field} = ""; $row->{$updated_field} = date('Y-m-d H:i:s'); $row->{$duration_field} = Q_Config::get('Q', 'session', 'durations', Q_Request::formFactor(), Q_Config::expect('Q', 'session', 'durations', 'session')); if (false !== Q::event('Q/session/save', array('row' => $row, 'id_field' => $id_field, 'data_field' => $data_field, 'updated_field' => $updated_field, 'duration_field' => $duration_field), 'before')) { $row->save(); self::id($row->{$id_field}); // this sets the session cookie as well self::$session_db_row = $row; } } } else { self::id($id); } } if (!empty($_SERVER['HTTP_HOST'])) { session_start(); } else { if (empty($_SESSION)) { $_SESSION = array(); } } } catch (Exception $e) { $app = Q_Config::get('Q', 'app', null); $prefix = $app ? "{$app}/" : ''; if (empty($_SERVER['HTTP_HOST'])) { echo "Warning: Ignoring Q_Session::start() called before running {$prefix}scripts/Q/install.php --all" . PHP_EOL; $message = $e->getMessage(); $file = $e->getFile(); $line = $e->getLine(); if (is_callable(array($e, 'getTraceAsStringEx'))) { $trace_string = $e->getTraceAsStringEx(); } else { $trace_string = $e->getTraceAsString(); } echo "{$message}\n(in {$file} line {$line})\n{$trace_string}" . PHP_EOL; } else { if (is_callable('apc_clear_cache')) { apc_clear_cache('user'); } Q::log($e); throw new Q_Exception("Please run {$prefix}scripts/Q/install.php --all"); } } // merge in all the stuff that was added to $_SESSION // before we started it. if (isset($pre_SESSION)) { foreach ($pre_SESSION as $k => $v) { $_SESSION[$k] = $v; } } if (isset($_SESSION['Q']['notices'])) { foreach ($_SESSION['Q']['notices'] as $k => $v) { Q_Response::setNotice($k, $v); } } /** * @event Q/session/start {after} */ Q::event('Q/session/start', array(), 'after'); return true; }
/** * @method sendMessage * @param {string} $view * The name of a view for the message. Fields are passed to this array. * @param {array} $fields=array() * The fields referenced in the subject and/or view * @param {array} $options=array() * Array of options. Can include:<br/> * "delay" => A delay, in milliseconds, to wait until sending email. Only works if Node server is listening. * @return {boolean} * @throws {Q_Exception_WrongType} * If phone number is invalid */ function sendMessage($view, $fields = array(), $options = array()) { /** * @event Users/sms/sendMessage {before} * @param {string} view * @param {array} fields * @param {array} options * @return {boolean} */ $result = Q::event('Users/sms/sendMessage', compact('view', 'fields', 'options'), 'before'); if (isset($result)) { return $result; } if (!Q_Valid::phone($this->number, $number)) { throw new Q_Exception_WrongType(array('field' => '$this->number', 'type' => 'mobile number', 'mobileNumber' => $this->number)); } $app = Q_Config::expect('Q', 'app'); $body = Q::view($view, $fields); $overrideLog = Q::event('Users/mobile/log', compact('mobileNumber', 'body'), 'before'); if (is_null($overrideLog) and $key = Q_Config::get('Users', 'mobile', 'log', 'key', null)) { Q::log("\nSent mobile message to {$this->number}:\n{$body}", $key); } $sent = false; if (!empty($options['delay'])) { // Try to use Node.js to send the message $sent = Q_Utils::sendToNode(array("Q/method" => "Users/sendMessage", "delay" => $options['delay'], "mobileNumber" => $number, "body" => $body, "options" => $options)); } if (!$sent) { $from = Q::ifset($options, 'from', Q_Config::get('Users', 'mobile', 'from', null)); if (!isset($from)) { // deduce from base url $url_parts = parse_url(Q_Request::baseUrl()); $domain = $url_parts['host']; $from = array("notifications@{$domain}", $domain); } $sid = Q_Config::get('Users', 'mobile', 'twilio', 'sid', null); $token = Q_Config::get('Users', 'mobile', 'twilio', 'token', null); if ($sid and $token) { $client = new Services_Twilio($sid, $token); $message = $client->account->sms_messages->create($from, $number, Q::view($view, $fields)); } else { if (!Q_Config::get('Users', 'email', 'smtp', null)) { Q_Response::setNotice("Q/mobile", "Please set up transport in Users/mobile/twilio as in docs", false); return true; } if (!is_array($from)) { $from = array($from, "{$app} activation"); } // Set up the default mail transport $host = Q_Config::get('Users', 'email', 'smtp', 'host', 'sendmail'); if ($host === 'sendmail') { $transport = new Zend_Mail_Transport_Sendmail('-f' . reset($from)); } else { if (is_array($host)) { $smtp = $host; $host = $smtp['host']; unset($smtp['host']); } else { $smtp = null; } $transport = new Zend_Mail_Transport_Smtp($host, $smtp); } $mail = new Zend_Mail(); $from_name = reset($from); $mail->setFrom(next($from), $from_name); $gateways = Q_Config::get('Users', 'mobile', 'gateways', array('at&t' => 'txt.att.net', 'sprint' => 'messaging.sprintpcs.com', 'verizon' => 'vtext.com', 't-mobile' => 'tmomail.net')); $number2 = substr($this->number, 2); foreach ($gateways as $k => $v) { $mail->addTo($number2 . '@' . $v); } $mail->setBodyText($body); try { $mail->send($transport); } catch (Exception $e) { throw new Users_Exception_MobileMessage(array('error' => $e->getMessage())); } } } /** * @event Users/sms/sendMessage {after} * @param {string} view * @param {array} fields * @param {array} options * @param {string} mail */ Q::event('Users/email/sendMessage', compact('view', 'fields', 'options', 'mail', 'app'), 'after'); return true; }