Esempio n. 1
0
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_after_Q_session_write($params)
{
    Q::$state['session'] = true;
    if (!$params['changed']) {
        return;
    }
    // Q::autoload('Db');
    // Q::autoload('Db_Mysql');
    // Q::autoload('Db_Result');
    // Q::autoload('Db_Expression');
    // Q::autoload('Db_Query');
    // Q::autoload('Db_Query_Mysql');
    // Q::autoload('Db_Row');
    // Q::autoload('Base_Users_Session');
    // Q::autoload('Base_Users');
    // Q::autoload('Users');
    Q::autoload('Q_Utils');
    Q::autoload('Q_Config');
    Q::autoload('Q_Session');
    $id = Q_Session::id();
    if (!$id) {
        return;
    }
    $parts = explode('-', $id);
    $duration = count($parts) > 1 ? $parts[0] : 0;
    $content = Q::json_encode($_SESSION, JSON_FORCE_OBJECT);
    if (Users::$loggedOut) {
        Q_Utils::sendToNode(array("Q/method" => "Users/session", "sessionId" => $id, "content" => null, "duration" => $duration));
    } else {
        if (Q_Session::id() and !empty($_SERVER['HTTP_HOST'])) {
            try {
                Q_Utils::sendToNode(array("Q/method" => "Users/session", "sessionId" => $id, "content" => $content, "duration" => $duration));
            } catch (Exception $e) {
                // don't throw here, it would only result in a mysterious fatal error
            }
        }
    }
}
Esempio n. 3
0
function Users_after_Q_session_destroy($params)
{
    Q::$state['session'] = true;
    //  Q::autoload('Db');
    //  Q::autoload('Db_Mysql');
    //  Q::autoload('Db_Result');
    //  Q::autoload('Db_Expression');
    //  Q::autoload('Db_Query');
    //  Q::autoload('Db_Query_Mysql');
    //  Q::autoload('Db_Row');
    //  Q::autoload('Base_Users_Session');
    //  Q::autoload('Base_Users');
    //  Q::autoload('Users');
    Q::autoload('Q_Utils');
    Q::autoload('Q_Config');
    Q::autoload('Q_Session');
    $id = Q_Session::id();
    if (!$id) {
        return;
    }
    $content = Q::json_encode($_SESSION, JSON_FORCE_OBJECT);
    Q_Utils::sendToNode(array("Q/method" => "Users/session", "sessionId" => $id, "content" => null, "updatedTime" => null, "destroyed" => true));
}
Esempio n. 4
0
 /**
  * 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;
 }
Esempio n. 5
0
 /**
  * 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;
     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();
 }
Esempio n. 6
0
 /**
  * Unsubcsribe from all or specific stream's messages
  * @method unsubscribe
  * @param $options=array() {array}
  *  "userId": The user who is unsubscribing from the stream. Defaults to the logged-in user.
  *  "skipAccess": if true, skip access check for whether user can unsubscribe
  * @return {boolean}
  */
 function unsubscribe($options = array())
 {
     $stream = $this->fetchAsUser($options, $userId);
     if (empty($options['skipAccess']) and !$stream->testReadLevel('messages')) {
         if (!$stream->testReadLevel('see')) {
             throw new Streams_Exception_NoSuchStream();
         }
         throw new Users_Exception_NotAuthorized();
     }
     $participant = $stream->join(array("userId" => $userId, 'subscribed' => false, 'noVisit' => true, "skipAccess" => Q::ifset($options, 'skipAccess', false)));
     Q_Utils::sendToNode(array("Q/method" => "Streams/Stream/unsubscribe", "stream" => Q::json_encode($stream->toArray()), "participant" => Q::json_encode($participant), "success" => Q::json_encode(!!$participant)));
     // Post Streams/unsubscribe message to the stream
     $stream->post($userId, array('type' => 'Streams/unsubscribe'), true);
     // Now post Streams/unsubscribed message to Streams/participating
     Streams_Message::post($userId, $userId, 'Streams/participating', array('type' => 'Streams/unsubscribed', 'instructions' => Q::json_encode(array('publisherId' => $stream->publisherId, 'streamName' => $stream->name))), true);
     return !!$participant;
 }
Esempio n. 7
0
 /**
  * Post (potentially) multiple messages to multiple streams.
  * With one call to this function you can post at most one message per stream.
  * @static
  * @param {string} $asUserId
  *  The user to post the message as
  * @param {string} $messages
  *  Array indexed as follows:
  *  array($publisherId => array($streamName => $message))
  *  where $message are either Streams_Message objects, 
  *  or arrays containing all the fields of messages that will need to be posted.
  * @param {booleam} $skipAccess=false
  *  If true, skips the access checks and just posts the message.
  * @return {array}
  *  Returns an array(array(Streams_Message), array(Streams_Stream))
  */
 static function postMessages($asUserId, $messages, $skipAccess = false)
 {
     if (!isset($asUserId)) {
         $asUserId = Users::loggedInUser();
         if (!$asUserId) {
             $asUserId = "";
         }
     }
     if ($asUserId instanceof Users_User) {
         $asUserId = $asUserId->id;
     }
     // Build arrays we will need
     foreach ($messages as $publisherId => $arr) {
         if (!is_array($arr)) {
             throw new Q_Exception_WrongType(array('field' => "messages", 'type' => 'array of publisherId => streamName => message'));
         }
         foreach ($arr as $streamName => &$message) {
             if (!is_array($message)) {
                 if (!$message instanceof Streams_Message) {
                     throw new Q_Exception_WrongType(array('field' => "message under {$publisherId} => {$streamName}", 'type' => 'array or Streams_Message'));
                 }
                 $message = $message->fields;
             }
         }
     }
     // Start posting messages, publisher by publisher
     $eventParams = array();
     $posted = array();
     $streams = array();
     $messages2 = array();
     $totals2 = array();
     $clientId = Q_Request::special('clientId', '');
     $sendToNode = true;
     foreach ($messages as $publisherId => $arr) {
         $streamNames = array_keys($messages[$publisherId]);
         $streams[$publisherId] = $fetched = Streams::fetch($asUserId, $publisherId, $streamNames, '*', array('refetch' => true, 'begin' => true));
         foreach ($arr as $streamName => $message) {
             $p =& $posted[$publisherId][$streamName];
             $p = false;
             $type = isset($message['type']) ? $message['type'] : 'text/small';
             $content = isset($message['content']) ? $message['content'] : '';
             $instructions = isset($message['instructions']) ? $message['instructions'] : '';
             $weight = isset($message['weight']) ? $message['weight'] : 1;
             if (!isset($message['byClientId'])) {
                 $message['byClientId'] = $clientId ? substr($clientId, 0, 255) : '';
             }
             if (is_array($instructions)) {
                 $instructions = Q::json_encode($instructions);
             }
             $byClientId = $message['byClientId'];
             // Get the Streams_Stream object
             if (!isset($fetched[$streamName])) {
                 $p = new Q_Exception_MissingRow(array('table' => 'stream', 'criteria' => "publisherId {$publisherId} and name {$streamName}"));
                 continue;
             }
             $stream = $fetched[$streamName];
             // Make a Streams_Message object
             $message = new Streams_Message();
             $message->publisherId = $publisherId;
             $message->streamName = $streamName;
             $message->insertedTime = new Db_Expression("CURRENT_TIMESTAMP");
             $message->sentTime = new Db_Expression("CURRENT_TIMESTAMP");
             $message->byUserId = $asUserId;
             $message->byClientId = $byClientId ? substr($byClientId, 0, 31) : '';
             $message->type = $type;
             $message->content = $content;
             $message->instructions = $instructions;
             $message->weight = $weight;
             $message->ordinal = $stream->messageCount + 1;
             // thanks to transaction
             // Set up some parameters for the event hooks
             $eventParams[$publisherId][$streamName] = array('publisherId' => $publisherId, 'message' => $message, 'skipAccess' => $skipAccess, 'sendToNode' => &$sendToNode, 'stream' => $stream);
             $params = $eventParams[$publisherId][$streamName];
             /**
              * @event Streams/post/$streamType {before}
              * @param {string} publisherId
              * @param {Streams_Stream} stream
              * @param {string} message
              * @return {false} To cancel further processing
              */
             if (Q::event("Streams/post/{$stream->type}", $params, 'before') === false) {
                 $results[$stream->name] = false;
                 continue;
             }
             /**
              * @event Streams/message/$messageType {before}
              * @param {string} publisherId
              * @param {Streams_Stream} stream
              * @param {string} message
              * @return {false} To cancel further processing
              */
             if (Q::event("Streams/message/{$type}", $params, 'before') === false) {
                 $results[$stream->name] = false;
                 continue;
             }
             if (!$skipAccess && !$stream->testWriteLevel('post')) {
                 $p = new Users_Exception_NotAuthorized();
                 /**
                  * @event Streams/notAuthorized {before}
                  * @param {string} publisherId
                  * @param {Streams_Stream} stream
                  * @param {string} message
                  */
                 Q::event("Streams/notAuthorized", $params, 'after');
                 continue;
             }
             // if we are still here, mark the message as "in the database"
             $message->wasRetrieved(true);
             $posted[$publisherId][$streamName] = $message;
             // build the arrays of rows to insert
             $messages2[] = $mf = $message->fields;
             $totals2[] = array('publisherId' => $mf['publisherId'], 'streamName' => $mf['streamName'], 'messageType' => $mf['type'], 'messageCount' => 1);
         }
     }
     if ($totals2) {
         Streams_Total::insertManyAndExecute($totals2, array('onDuplicateKeyUpdate' => array('messageCount' => new Db_Expression('messageCount + 1'))));
     }
     if ($messages2) {
         Streams_Message::insertManyAndExecute($messages2);
     }
     // time to update the stream rows and commit the transaction
     // on all the shards where the streams were fetched.
     Streams_Stream::update()->set(array('messageCount' => new Db_Expression("messageCount+1")))->where(array('publisherId' => $publisherId, 'name' => $streamNames))->commit()->execute();
     // handle all the events for successfully posting
     foreach ($posted as $publisherId => $arr) {
         foreach ($arr as $streamName => $m) {
             $message = $posted[$publisherId][$streamName];
             $params =& $eventParams[$publisherId][$streamName];
             /**
              * @event Streams/message/$messageType {after}
              * @param {string} publisherId
              * @param {Streams_Stream} stream
              * @param {string} message
              */
             Q::event("Streams/message/{$message->type}", $params, 'after', false);
             /**
              * @event Streams/post/$streamType {after}
              * @param {string} publisherId
              * @param {Streams_Stream} stream
              * @param {string} message
              */
             Q::event("Streams/post/{$stream->type}", $params, 'after', false);
         }
     }
     /**
      * @event Streams/postMessages {after}
      * @param {string} publisherId
      * @param {Streams_Stream} stream
      * @param {string} posted
      */
     Q::event("Streams/postMessages", array('streams' => $streams, 'messages' => $messages, 'skipAccess' => $skipAccess, 'posted' => $posted), 'after', false);
     if ($sendToNode) {
         Q_Utils::sendToNode(array("Q/method" => "Streams/Message/postMessages", "posted" => Q::json_encode($messages2), "streams" => Q::json_encode($streams)));
     }
     return array($posted, $streams);
 }
Esempio n. 8
0
 /**
  * @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;
 }
Esempio n. 9
0
 /**
  * Executes a query against the database and returns the result set.
  * @method excecute
  * @param {boolean} [$prepareStatement=false] If true, a PDO statement will be prepared
  * from the query before it is executed. It is also saved for future invocations to use.
  * Do this only if the statement will be executed many times with
  * different parameters. Basically you would use ->bind(...) between
  * invocations of ->execute().
  * @return {Db_Result} The Db_Result object containing the PDO statement that resulted from the query.
  */
 function execute($prepareStatement = false)
 {
     if (class_exists('Q')) {
         /**
          * @event Db/query/execute {before}
          * @param {Db_Query_Mysql} query
          * @return {Db_Result}
          */
         $result = Q::event('Db/query/execute', array('query' => $this), 'before');
     }
     if (isset($result)) {
         return $result;
     }
     $stmts = array();
     // make sure SQL template will be ready for sharding. reallyConnect will add new values
     unset($this->replacements['{$dbname}']);
     unset($this->replacements['{$prefix}']);
     $this->startedTime = Q::milliseconds(true);
     if ($prepareStatement) {
         // Prepare the query into a SQL statement
         // this takes two round-trips to the database
         // Preparing the statement if it wasn't yet set
         if (!isset($this->statement)) {
             if ($q = $this->build()) {
                 $pdo = $this->reallyConnect();
                 $this->statement = $pdo->prepare($q);
                 if ($this->statement === false) {
                     if (!isset($sql)) {
                         $sql = $this->getSQL();
                     }
                     if (class_exists('Q_Exception_DbQuery')) {
                         throw new Exception("query could not be prepared");
                     }
                     throw new Exception("query could not be prepared [query was: {$sql} ]", -1);
                 }
             }
         }
         // Bind the parameters
         foreach ($this->parameters as $key => $value) {
             $this->statement->bindValue($key, $value);
         }
     }
     $sql_template = $this->getSQL(null, true);
     $queries = $this->shard();
     $connection = $this->db->connectionName();
     if (!empty($queries["*"])) {
         $shard_names = Q_Config::get('Db', 'connections', $connection, 'shards', array('' => ''));
         $q = $queries["*"];
         foreach ($shard_names as $k => $v) {
             $queries[$k] = $q;
         }
         unset($queries['*']);
     }
     foreach ($queries as $shard_name => $query) {
         $upcoming = Q_Config::get('Db', 'upcoming', $connection, false);
         if ($query->type !== Db_Query::TYPE_SELECT && $query->type !== Db_Query::TYPE_RAW) {
             if (!empty($upcoming['block']) && $shard_name === $upcoming['shard']) {
                 throw new Db_Exception_Blocked(compact('shard_name', 'connection'));
             }
         }
         $query->startedTime = Q::milliseconds(true);
         $pdo = $query->reallyConnect($shard_name);
         $connInfo = Db::getConnection($connection);
         $dsn = $connInfo['dsn'];
         $nt =& self::$nestedTransactions[$dsn];
         if (!isset($nt)) {
             self::$nestedTransactions[$dsn] = 0;
             $nt =& self::$nestedTransactions[$dsn];
         }
         $sql = $query->getSQL();
         try {
             if (!empty($query->clauses["BEGIN"])) {
                 if (++$nt == 1) {
                     $pdo->beginTransaction();
                 }
             } else {
                 if (!empty($query->clauses["ROLLBACK"])) {
                     $pdo->rollBack();
                     $nt = 0;
                 }
             }
             if ($query->type !== Db_Query::TYPE_ROLLBACK) {
                 if ($prepareStatement) {
                     // Execute the statement
                     try {
                         $query->statement->execute();
                         $stmt = $query->statement;
                     } catch (Exception $e) {
                         if (class_exists('Q_Exception_DbQuery')) {
                             throw $e;
                         }
                         throw new Exception($e->getMessage() . "\n... Query was: {$sql}", -1);
                     }
                 } else {
                     // Obtain the full SQL code ourselves
                     // and send to the database, without preparing it there.
                     if ($sql) {
                         $stmt = $pdo->query($sql);
                     } else {
                         $stmt = true;
                     }
                 }
                 $stmts[] = $stmt;
                 if (!empty($query->clauses["COMMIT"]) && $nt) {
                     // we commit only if no error occurred - warnings are permitted
                     if (!$stmt or $stmt !== true and !in_array(substr($stmt->errorCode(), 0, 2), array('00', '01'))) {
                         $err = $pdo->errorInfo();
                         throw new Exception($err[0], $err[1]);
                     }
                     if (--$nt == 0) {
                         $pdo->commit();
                     }
                 }
             }
         } catch (Exception $exception) {
             if ($nt) {
                 $pdo->rollBack();
                 $nt = 0;
             }
             break;
         }
         $this->nestedTransactionCount = $nt;
         if (class_exists('Q') && isset($sql)) {
             // log query if shard split process is active
             // all activities will be done by node.js
             switch ($this->type) {
                 case Db_Query::TYPE_SELECT:
                     // SELECT queries don't need to be logged
                 // SELECT queries don't need to be logged
                 case Db_Query::TYPE_RAW:
                     // Raw queries are run on shard '' - i.e. main db only
                     // actually, raw query may get here only on initial sharding
                     // when sharding has started raw queries are never run on shard
                     break;
                 default:
                     if (!$upcoming or $shard_name !== $upcoming['shard']) {
                         break;
                     }
                     $table = $this->table;
                     foreach ($this->replacements as $k => $v) {
                         $table = str_replace($k, $v, $table);
                     }
                     if ($table !== $upcoming['dbTable']) {
                         break;
                     }
                     // node will determine new shard(s) names using
                     // new sharding config which is available within split process
                     $timestamp = $pdo->query("SELECT CURRENT_TIMESTAMP")->fetchAll(PDO::FETCH_COLUMN, 0);
                     if ($timestamp === false || !isset($timestamp[0])) {
                         $timestamp = date("Y-m-d H:i:s");
                         // backup solution
                     } else {
                         $timestamp = $timestamp[0];
                     }
                     $sql_template = str_replace('CURRENT_TIMESTAMP', "'{$timestamp}'", $sql_template);
                     $transaction = !empty($this->clauses['COMMIT']) ? 'COMMIT' : (!empty($this->clauses['BEGIN']) ? 'START TRANSACTION' : (!empty($this->clauses['ROLLBACK']) ? 'ROLLBACK' : ''));
                     $upcoming_shards = array_keys($query->shard($upcoming['indexes'][$upcoming['table']]));
                     $logServer = Q_Config::get('Db', 'internal', 'sharding', 'logServer', null);
                     if (!empty($transaction) && $transaction !== 'COMMIT') {
                         Q_Utils::sendToNode(array('Q/method' => 'Db/Shards/log', 'shards' => $upcoming_shards, 'sql' => "{$transaction};"), Q_Config::get('Db', 'internal', 'sharding', 'logServer', null));
                     }
                     Q_Utils::sendToNode(array('Q/method' => 'Db/Shards/log', 'shards' => $upcoming_shards, 'sql' => trim(str_replace("\n", ' ', $sql_template))), Q_Config::get('Db', 'internal', 'sharding', 'logServer', null));
                     if (!empty($transaction) && $transaction === 'COMMIT') {
                         Q_Utils::sendToNode(array('Q/method' => 'Db/Shards/log', 'shards' => $upcoming_shards, 'sql' => "{$transaction};"), $logServer, true);
                     }
             }
             $query->endedTime = Q::milliseconds(true);
         }
     }
     $this->endedTime = Q::milliseconds(true);
     if (!empty($exception)) {
         /**
          * @event Db/query/exception {after}
          * @param {Db_Query_Mysql} query
          * @param {array} queries
          * @param {string} sql
          * @param {Exception} exception
          */
         Q::event('Db/query/exception', compact('query', 'queries', 'sql', 'exception'), 'after');
         if (!class_exists('Q_Exception_DbQuery')) {
             throw $exception;
         }
         throw new Q_Exception_DbQuery(array('sql' => $sql, 'message' => $exception->getMessage() . "[query was: {$sql}]"));
     }
     /**
      * @event Db/query/execute {after}
      * @param {Db_Query_Mysql} query
      * @param {array} queries
      * @param {string} sql
      */
     Q::event('Db/query/execute', compact('query', 'queries', 'sql'), 'after');
     return new Db_Result($stmts, $this);
 }
Esempio n. 10
0
 /**
  * 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;
 }
Esempio n. 11
0
 /**
  * Unsubscribe from one or more streams, to stop receiving notifications.
  * Pooststs "Streams/unsubscribe" message to the streams.
  * Also posts "Streams/unsubscribed" messages to user's "Streams/participating" stream.
  * Does not change the actual subscription, but only the participant row.
  * (When subscribing again, the existing subscription will be used.)
  * @method unsubscribe
  * @static
  * @param {string} $asUserId The id of the user that is joining. Pass null here to use the logged-in user's id.
  * @param {string} $publisherId The id of the user publishing all the streams
  * @param {array} $streams An array of Streams_Stream objects or stream names
  * @param {array} [$options=array()]
  * @param {boolean} [$options.leave] set to true to also leave the streams
  * @param {boolean} [$options.skipAccess] if true, skip access check for whether user can join and subscribe
  * @return {array} Returns an array of Streams_Participant rows, if any were in the database.
  */
 static function unsubscribe($asUserId, $publisherId, $streams, $options = array())
 {
     $streams2 = self::_getStreams($asUserId, $publisherId, $streams);
     $streamNames = array();
     foreach ($streams2 as $s) {
         $streamNames[] = $s->name;
     }
     if (empty($options['skipAccess'])) {
         self::_accessExceptions($streams2, $streamNames, 'join');
     }
     $skipAccess = Q::ifset($options, 'skipAccess', false);
     if (empty($options['leave'])) {
         $criteria = array('publisherId' => $publisherId, 'streamName' => $streamNames, 'userId' => $asUserId);
         Streams_Participant::update()->set(array('subscribed' => 'no'))->where($criteria)->execute();
         $participants = Streams_Participant::select('*')->where($criteria)->fetchDbRows();
     } else {
         $participants = Streams::leave($asUserId, $publisherId, $streams2, compact('skipAccess'));
     }
     $messages = array();
     $pMessages = array();
     foreach ($streamNames as $sn) {
         $stream = $streams2[$sn];
         if ($participant = Q::ifset($participants, $sn, null)) {
             if ($participant instanceof Streams_Participant) {
                 $participant = $participant->toArray();
             }
         }
         // Send a message to Node
         Q_Utils::sendToNode(array("Q/method" => "Streams/Stream/unsubscribe", "participant" => Q::json_encode($participant), "stream" => Q::json_encode($stream->toArray())));
         // Stream messages to post
         $messages[$publisherId][$sn] = array('type' => 'Streams/unsubscribe');
         $pMessages[] = array('type' => 'Streams/unsubscribed', 'instructions' => array('publisherId' => $publisherId, 'streamName' => $sn));
     }
     Streams_Message::postMessages($asUserId, $messages, true);
     Streams_Message::postMessages($asUserId, array($asUserId => array('Streams/participating' => $pMessages)), true);
     return $participants;
 }
Esempio n. 12
0
 /**
  * @method afterRemoveExcecute
  * @param {Db_Result} $result
  * @param {Db_Query} $query
  * @return {Db_Result}
  */
 function afterRemoveExecute($result, $query)
 {
     $stream = $this;
     // if the above call threw an exception, then we will not be doing the following.
     Q_Utils::sendToNode(array("Q/method" => "Streams/Stream/remove", "stream" => Q::json_encode($stream->toArray())));
     /**
      * @event Streams/remove/$streamType {after}
      * @param {Streams_Stream} stream
      * @param {string} asUserId
      */
     Q::event("Streams/remove/{$stream->type}", compact('stream', 'result'), 'after');
     if ($this->name !== 'Streams/user/firstName' and $this->name !== 'Streams/user/lastName') {
         return $result;
     }
     // Update all avatars corresponding to access rows for this stream
     $taintedAccess = Streams_Access::select('*')->where(array('publisherId' => $this->publisherId, 'streamName' => $this->name))->fetchDbRows();
     Streams::updateAvatars($this->publisherId, $taintedAccess, $this, true);
     return $result;
 }