Example #1
0
 static function handlebars()
 {
     if (!isset(self::$handlebars)) {
         self::$handlebars = new Handlebars_Engine(array('cache' => new Handlebars_Cache_Disk(APP_FILES_DIR . DS . 'Q' . DS . 'cache' . DS . 'handlebars'), 'loader' => new Q_Handlebars_Loader(), 'partials_loader' => new Q_Handlebars_Loader('partials'), 'escape' => function ($value) {
             return htmlspecialchars($value, ENT_COMPAT, 'UTF-8');
         }));
         self::$handlebars->addHelper('call', array('Q_Handlebars', 'helperCall'));
         self::$handlebars->addHelper('tool', array('Q_Handlebars', 'helperTool'));
     }
     return self::$handlebars;
 }
Example #2
0
function Q_before_Q_view($params, &$result)
{
    extract($params);
    if (strtolower(substr($viewName, -9)) === '.mustache') {
        $result = Q_Mustache::render($viewName, $params);
        return false;
    }
    if (strtolower(substr($viewName, -11)) === '.handlebars') {
        $result = Q_Handlebars::render($viewName, $params);
        return false;
    }
}
Example #3
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;
 }
Example #4
0
 /**
  * Make the stream a member of category or other aggregating stream,
  * First parameter set - where to add, Second parameter set - what to add
  * NOTE: this currently only works when fromPublisherId and toPublisherId are on same Q cluster
  * @method relate
  * @static
  * @param {string} $asUserId
  *  The user who is making aggreagtor operation on the stream (add stream to category)
  * @param {string} $toPublisherId
  *  The user who has published the category stream
  * @param {string|array} $toStreamName
  *  The name of the category stream. Pass an array of strings to relate a single stream
  *  to multiple categories, but in that case make sure fromStreamName is a string.
  * @param {string} $type
  *  The type of the relation
  * @param {string} $fromPublisherId
  *  The user who has published the member stream
  * @param {string} $fromStreamName
  *  The name of the member stream. Pass an array of strings to relate multiple streams
  *  to a single category, but in that case make sure toStreamName is a string.
  * @param {array} $options=array()
  *  An array of options that can include:
  * @param {boolean} [$options.skipAccess=false] If true, skips the access checks and just relates the stream to the category
  * @param {double|string} [$options.weight] Pass a numeric value here, or something like "max+1" to make the weight 1 greater than the current MAX(weight)
  * @return {array|boolean}
  *  Returns false if the operation was canceled by a hook
  *  Returns true if relation was already there
  *  Otherwise returns array with keys "messagesFrom" and "messageTo" and values of type Streams_Message
  */
 static function relate($asUserId, $toPublisherId, $toStreamName, $type, $fromPublisherId, $fromStreamName, $options = array())
 {
     self::getRelations($asUserId, $toPublisherId, $toStreamName, $type, $fromPublisherId, $fromStreamName, $relatedToArray, $relatedFromArray, $categories, $streams, $arrayField, $options);
     // calculate weights
     $calculateWeights = null;
     foreach (${$arrayField} as $sn) {
         if (isset($relatedToArray[$sn])) {
             continue;
         }
         if (!isset($relatedToArray[$sn])) {
             // at least one new relation will be inserted
             if (isset($options['weight'])) {
                 $parts = explode('+', "{$options['weight']}");
                 if (count($parts) > 1) {
                     $calculateWeights = $parts[1];
                     break;
                 }
             }
         }
     }
     if (isset($calculateWeights)) {
         if (!is_numeric($calculateWeights) or $calculateWeights <= 0) {
             throw new Q_Exception_WrongValue(array('field' => 'weight', 'range' => 'a positive numeric value'), 'weight');
         }
         $rows = Streams_RelatedTo::select('toStreamName, MAX(weight) w')->where(compact('toPublisherId', 'toStreamName', 'type'))->groupBy('toStreamName')->ignoreCache()->fetchAll(PDO::FETCH_ASSOC);
         $maxWeights = array();
         foreach ($rows as $r) {
             $maxWeights[$r['toStreamName']] = $r['w'];
         }
     }
     $newRT = array();
     $newRF = array();
     $weights2 = array();
     foreach (${$arrayField} as $sn) {
         if (isset($relatedToArray[$sn])) {
             continue;
         }
         $category = $arrayField === 'toStreamName' ? $categories[$sn] : reset($categories);
         $stream = $arrayField === 'fromStreamName' ? $streams[$sn] : reset($streams);
         /**
          * @event Streams/relateTo/$categoryType {before}
          * @param {array} relatedTo
          * @param {array} relatedFrom
          * @param {string} asUserId
          * @param {Streams_Stream} category
          * @param {Streams_Stream} stream
          * @return {false} To cancel further processing
          */
         if (false === Q::event("Streams/relateTo/{$category->type}", compact('asUserId', 'category', 'stream'), 'before')) {
             continue;
         }
         /**
          * @event Streams/relateFrom/$streamType {before}
          * @param {array} relatedTo
          * @param {array} relatedFrom
          * @param {string} asUserId
          * @param {Streams_Stream} category
          * @param {Streams_Stream} stream
          * @return {false} To cancel further processing
          */
         if (false === Q::event("Streams/relateFrom/{$stream->type}", compact('asUserId', 'category', 'stream'), 'before')) {
             continue;
         }
         $tsn = $arrayField === 'toStreamName' ? $sn : $toStreamName;
         $newRT[$sn] = $newRF[$sn] = compact('toPublisherId', 'type', 'fromPublisherId');
         if ($calculateWeights) {
             if (!isset($weights2[$tsn])) {
                 $weights2[$tsn] = isset($maxWeights[$tsn]) ? $maxWeights[$tsn] : 0;
             }
             $weights2[$tsn] += $calculateWeights;
             $newRT[$sn]['weight'] = $weights2[$tsn];
         } else {
             if (isset($options['weight'])) {
                 $weights2[$tsn] = $newRT[$sn]['weight'] = $options['weight'];
             }
         }
         foreach (array('toStreamName', 'fromStreamName') as $f) {
             $newRT[$sn][$f] = $newRF[$sn][$f] = $f === $arrayField ? $sn : ${$f};
         }
     }
     // Save all the relatedTo
     Streams_RelatedTo::insertManyAndExecute($newRT);
     Streams_RelatedFrom::insertManyAndExecute($newRF);
     foreach (${$arrayField} as $sn) {
         $category = $arrayField === 'toStreamName' ? $categories[$sn] : reset($categories);
         $stream = $arrayField === 'fromStreamName' ? $streams[$sn] : reset($streams);
         $weight = isset($options['weight']) && is_numeric($options['weight']) ? $options['weight'] : null;
         $weight = Q::ifset($weights2, $category->name, $weight);
         $fromUrl = $stream->url();
         $fromIcon = $stream->icon;
         $fromTitle = $stream->title;
         $fromType = $stream->type;
         $fromDisplayType = Streams_Stream::displayType($fromType);
         if (!$category) {
             continue;
         }
         $toUrl = $category->url();
         $toIcon = $category->icon;
         $toTitle = $category->title;
         $toType = $category->type;
         $toDisplayType = Streams_Stream::displayType($toType);
         $parts = explode('/', $type);
         $displayType = substr(end($parts), 0, -1);
         $categoryName = explode('/', $category->name);
         $streamName = explode('/', $stream->name);
         $params = compact('relatedTo', 'relatedFrom', 'asUserId', 'category', 'stream', 'fromUrl', 'fromIcon', 'fromTitle', 'fromType', 'fromDisplayType', 'toUrl', 'toIcon', 'toTitle', 'toType', 'toDisplayType', 'displayType', 'categoryName', 'streamName');
         if ($u = Streams_Stream::getConfigField($category->type, array('relatedTo', $type, 'uri'), Streams_Stream::getConfigField($category->type, array('relatedTo', '*', 'uri', null)))) {
             $fromUrl = Q_Uri::url(Q_Handlebars::renderSource($u, $params));
         }
         if ($u = Streams_Stream::getConfigField($stream->type, array('relatedFrom', $type, 'uri'), Streams_Stream::getConfigField($stream->type, array('relatedFrom', '*', 'uri', null)))) {
             $toUrl = Q_Uri::url(Q_Handlebars::renderSource($u, $params));
         }
         $description = Q_Handlebars::renderSource(Streams_Stream::getConfigField($category->type, array('relatedTo', $type, 'description'), Streams_Stream::getConfigField($category->type, array('relatedTo', '*', 'description'), "New {$fromDisplayType} added")), $params);
         // Send Streams/relatedTo message to a stream
         // node server will be notified by Streams_Message::post
         // DISTRIBUTED: in the future, the publishers may be on separate domains
         // so posting this message may require internet communication.
         $instructions = compact('fromPublisherId', 'type', 'weight', 'displayType', 'fromUrl', 'toUrl', 'fromIcon', 'fromTitle', 'fromType', 'fromDisplayType', 'description');
         $instructions['fromStreamName'] = $stream->name;
         $relatedTo_messages[$toPublisherId][$category->name][] = array('type' => 'Streams/relatedTo', 'instructions' => $instructions);
         $description = Q_Handlebars::renderSource(Streams_Stream::getConfigField($stream->type, array('relatedFrom', $type, 'description'), Streams_Stream::getConfigField($stream->type, array('relatedFrom', '*', 'description'), "Added to {{toDisplayType}} as {$displayType}")), $params);
         // Send Streams/relatedFrom message to a stream
         // node server will be notified by Streams_Message::post
         // DISTRIBUTED: in the future, the publishers may be on separate domains
         // so posting this message may require internet communication.
         $instructions = compact('toPublisherId', 'type', 'weight', 'displayType', 'fromUrl', 'toUrl', 'toIcon', 'toTitle', 'toType', 'toDisplayType', 'description');
         $instructions['toStreamName'] = $category->name;
         $relatedFrom_messages[$fromPublisherId][$stream->name][] = array('type' => 'Streams/relatedFrom', 'instructions' => $instructions);
         /**
          * @event Streams/relateFrom/$streamType {after}
          * @param {string} relatedTo
          * @param {string} relatedFrom
          * @param {string} asUserId
          * @param {Streams_Stream} category
          * @param {Streams_Stream} stream
          */
         Q::event("Streams/relate/{$stream->type}", compact('relatedTo', 'relatedFrom', 'asUserId', 'category', 'stream'), 'after');
         /**
          * @event Streams/relateTo/$categoryType {after}
          * @param {string} relatedTo
          * @param {string} relatedFrom
          * @param {string} asUserId
          * @param {Streams_Stream} category
          * @param {Streams_Stream} stream
          */
         Q::event("Streams/relateTo/{$category->type}", compact('relatedTo', 'relatedFrom', 'asUserId', 'category', 'stream'), 'after');
     }
     list($messagesTo, $s) = Streams_Message::postMessages($asUserId, $relatedTo_messages, true);
     list($messagesFrom, $s) = Streams_Message::postMessages($asUserId, $relatedFrom_messages, true);
     return compact('messagesTo', 'messagesFrom');
 }
Example #5
0
 /**
  * Returns the canonical url of the stream, if any
  * @return {string|null|false}
  */
 function url()
 {
     $uri = self::getConfigField($this->type, 'uri', null);
     if (!$uri) {
         return null;
     }
     $uriString = Q_Handlebars::renderSource($uri, array('publisherId' => $this->publisherId, 'streamName' => explode('/', $this->name), 'name' => $this->name));
     return Q_Uri::from($uriString)->toUrl();
 }