Beispiel #1
0
 /**
  * Assigns ordinal and readyTime
  * @method beforeSave
  * @param {array} $value
  *	The row beind saved
  * @return {array}
  */
 function beforeSave($value)
 {
     if (!$this->retrieved) {
         $max = Streams_Rule::select("MAX(ordinal) + 1")->where(array('ofUserId' => $this->ofUserId, 'publisherId' => $this->publisherId, 'streamName' => $this->streamName))->ignoreCache()->fetchAll(PDO::FETCH_COLUMN);
         $value['ordinal'] = $this->ordinal = isset($max[0]) ? $max[0] : 1;
         if (!isset($this->readyTime)) {
             $value['readyTime'] = $this->readyTime = new Db_Expression('CURRENT_TIMESTAMP');
         }
     }
     return parent::beforeSave($value);
 }
Beispiel #2
0
/**
 * Subscription tool
 * @param array $options
 *  "publisherId" => the id of the user who is publishing the stream
 *  "streamName" => the name of the stream for which to edit access levels
 */
function Streams_subscription_tool($options)
{
    $subscribed = 'no';
    extract($options);
    $user = Users::loggedInUser(true);
    if (!isset($publisherId)) {
        $publisherId = Streams::requestedPublisherId(true);
    }
    if (!isset($streamName)) {
        $streamName = Streams::requestedName();
    }
    $stream = Streams::fetchOne($user->id, $publisherId, $streamName);
    if (!$stream) {
        throw new Q_Exception_MissingRow(array('table' => 'stream', 'criteria' => compact('publisherId', 'streamName')));
    }
    $streams_participant = new Streams_Participant();
    $streams_participant->publisherId = $publisherId;
    $streams_participant->streamName = $streamName;
    $streams_participant->userId = $user->id;
    if ($streams_participant->retrieve()) {
        $subscribed = $streams_participant->subscribed;
    }
    $types = Q_Config::get('Streams', 'types', $stream->type, 'messages', array());
    $messageTypes = array();
    foreach ($types as $type => $msg) {
        $name = Q::ifset($msg, 'title', $type);
        /*
         * group by name
         */
        foreach ($messageTypes as $msgType) {
            if ($msgType['name'] == $name) {
                continue 2;
            }
        }
        $messageTypes[] = array('value' => $type, 'name' => $name);
    }
    $usersFetch = array('userId' => $user->id, 'state' => 'active');
    $devices = array();
    $emails = Users_Email::select('address')->where($usersFetch)->fetchAll(PDO::FETCH_COLUMN);
    $mobiles = Users_Mobile::select('number')->where($usersFetch)->fetchAll(PDO::FETCH_COLUMN);
    foreach ($emails as $email) {
        $devices[] = array('value' => Q::json_encode(array('email' => $email)), 'name' => 'my email');
    }
    foreach ($mobiles as $mobile) {
        $devices[] = array('value' => Q::json_encode(array('mobile' => $mobile)), 'name' => 'my mobile');
    }
    $items = array();
    $rules = Streams_Rule::select('deliver, filter')->where(array('ofUserId' => $user->id, 'publisherId' => $publisherId, 'streamName' => $streamName))->fetchAll(PDO::FETCH_ASSOC);
    while ($rule = array_pop($rules)) {
        $filter = json_decode($rule['filter']);
        /*
         * group by name
         */
        foreach ($rules as $val) {
            if (json_decode($val['filter'])->labels == $filter->labels) {
                continue 2;
            }
        }
        $items[] = array('deliver' => json_decode($rule['deliver']), 'filter' => $filter);
    }
    Q_Response::addScript("plugins/Streams/js/Streams.js");
    Q_Response::addScript("plugins/Streams/js/tools/subscription.js");
    Q_Response::setToolOptions(compact('items', 'subscribed', 'messageTypes', 'devices', 'publisherId', 'streamName'));
}
Beispiel #3
0
/**
 * Create or update subscription
 */
function Streams_subscription_put($params)
{
    $items = array();
    $subscribed = 'no';
    $updateTemplate = true;
    $streamName = Streams::requestedName();
    $publisherId = Streams::requestedPublisherId(true);
    $user = Users::loggedInUser(true);
    extract($_REQUEST);
    $items = json_decode($items, true);
    $stream = Streams::fetchOne($user->id, $publisherId, $streamName);
    if (!$stream) {
        throw new Q_Exception_MissingRow(array('table' => 'stream', 'criteria' => compact('publisherId', 'streamName')));
    }
    $rules = Streams_Rule::select('*')->where(array('ofUserId' => $user->id, 'publisherId' => $publisherId, 'streamName' => $streamName))->fetchDbRows(null, '', 'ordinal');
    $types = Q_Config::get('Streams', 'types', $stream->type, 'messages', array());
    if ($subscribed !== 'no') {
        // update rules
        while ($item = array_pop($items)) {
            // join "grouped" message types to $items
            foreach ($types as $type => $msg) {
                if ($msg['title'] == $item['filter']->labels and $type != $item['filter']->types) {
                    $items[] = (object) array('deliver' => $item->deliver, 'filter' => array('types' => $type, 'labels' => $msg['title'], 'notifications' => $item['filter']->notifications));
                }
            }
            if (!($rule = array_pop($rules))) {
                $rule = new Streams_Rule();
                $rule->ofUserId = $user->id;
                $rule->publisherId = $publisherId;
                $rule->streamName = $streamName;
                $rule->relevance = 1;
            }
            $rule->filter = Q::json_encode($item['filter']);
            $rule->deliver = Q::json_encode($item['deliver']);
            $rule->save();
        }
    }
    foreach ($rules as $rule) {
        $rule->remove();
    }
    $streams_subscription = new Streams_Subscription();
    $streams_subscription->streamName = $streamName;
    $streams_subscription->publisherId = $publisherId;
    $streams_subscription->ofUserId = $user->id;
    $streams_subscription->filter = Q::json_encode(array());
    $streams_subscription->retrieve();
    $streams_participant = new Streams_Participant();
    $streams_participant->publisherId = $publisherId;
    $streams_participant->streamName = $streamName;
    $streams_participant->userId = $user->id;
    $streams_participant->state = 'participating';
    $streams_participant->reason = '';
    $streams_participant->retrieve();
    $streams_participant->subscribed = $subscribed;
    $streams_participant->save();
    if ($subscribed === 'yes') {
        $stream->subscribe(array('skipRules' => true));
    } else {
        $stream->unsubscribe();
    }
}
Beispiel #4
0
 /**
  * Subscribe to the stream's messages<br/>
  *	If options are not given check the subscription templates:
  *	1. exact stream name and exact user id
  *	2. generic stream name and exact user id
  *	3. exact stream name and generic user
  *	4. generic stream name and generic user
  *	default is to subscribe to ALL messages.
  *	If options supplied - skip templates and use options<br/><br/>
  * Using subscribe if subscription is already active will modify existing
  * subscription - change type(s) or modify notifications
  * @method subscribe
  * @param $options=array() {array}
  * @param {array} [$options.types] array of message types, if this is empty then subscribes to all types
  * @param {integer} [$options.notifications=0] limit number of notifications, 0 means no limit
  * @param {datetime} [$options.untilTime=null] time limit, if any for subscription
  * @param {datetime} [$options.readyTime] time from which user is ready to receive notifications again
  * @param {string} [$options.userId] the user subscribing to the stream. Defaults to the logged in user.
  * @param {array} [$options.deliver=array('to'=>'default')] under "to" key, named the field under Streams/rules/deliver config, which will contain the names of destinations, which can include "email", "mobile", "email+pending", "mobile+pending"
  * @param {boolean} [$options.skipRules]  if true, do not attempt to create rules
  * @param {boolean} [$options.skipAccess]  if true, skip access check for whether user can subscribe
  * @return {Streams_Subscription|false}
  */
 function subscribe($options = array())
 {
     $stream = $this->fetchAsUser($options, $userId, $user);
     if (empty($options['skipAccess']) and !$stream->testReadLevel('messages')) {
         if (!$stream->testReadLevel('see')) {
             throw new Streams_Exception_NoSuchStream();
         }
         throw new Users_Exception_NotAuthorized();
     }
     // first make user a participant
     $stream->join(array("userId" => $userId, "subscribed" => true, "noVisit" => true, "skipAccess" => Q::ifset($options, 'skipAccess', false)));
     // check for 'messages' level
     $s = new Streams_Subscription();
     $s->publisherId = $stream->publisherId;
     $s->streamName = $stream->name;
     $s->ofUserId = $userId;
     $s->retrieve();
     $type = null;
     if ($template = $stream->getSubscriptionTemplate('Streams_Subscription', $userId, $type)) {
         $filter = json_decode($template->filter, true);
     } else {
         $filter = array('types' => array(), 'notifications' => 0);
     }
     if (isset($options['types'])) {
         $filter['types'] = !empty($options['types']) ? $options['types'] : $filter['types'];
     }
     if (isset($options['notifications'])) {
         $filter['notifications'] = $options['notifications'];
     }
     $s->filter = Q::json_encode($filter);
     if (isset($options['untilTime'])) {
         $s->untilTime = $options['untilTime'];
     } else {
         if ($type > 0 and $template and $template->duration > 0) {
             $s->untilTime = date("c", time() + $template->duration);
         }
     }
     if (!$s->save(true)) {
         return false;
     }
     if (empty($options['skipRules'])) {
         // Now let's handle rules
         $type2 = null;
         $template = $stream->getSubscriptionTemplate('Streams_Rule', $userId, $type2);
         $ruleSuccess = true;
         if ($type2 !== 0) {
             $rule = new Streams_Rule();
             $rule->ofUserId = $userId;
             $rule->publisherId = $stream->publisherId;
             $rule->streamName = $stream->name;
             if (empty($template) and $rule->retrieve()) {
                 $ruleSuccess = false;
             } else {
                 $rule->readyTime = isset($options['readyTime']) ? $options['readyTime'] : new Db_Expression('CURRENT_TIMESTAMP');
                 $rule->filter = !empty($template->filter) ? $template->filter : '{"types":[],"labels":[]}';
                 $rule->relevance = !empty($template->relevance) ? $template->relevance : 1;
                 $rule->deliver = !empty($template->deliver) ? $template->deliver : Q::json_encode(Q::ifset($options, 'deliver', array('to' => 'default')));
                 $ruleSuccess = !!$rule->save();
             }
         }
     }
     // skip error testing for rule save BUT inform node.
     // Node can notify user to check the rules
     Q_Utils::sendToNode(array("Q/method" => "Streams/Stream/subscribe", "subscription" => Q::json_encode($s->toArray()), "stream" => Q::json_encode($stream->toArray()), "success" => Q::json_encode($ruleSuccess)));
     // Post Streams/subscribe message to the stream
     $stream->post($userId, array('type' => 'Streams/subscribe'), true);
     // Now post Streams/subscribed message to Streams/participating
     Streams_Message::post($userId, $userId, 'Streams/participating', array('type' => 'Streams/subscribed', 'instructions' => Q::json_encode(array('publisherId' => $stream->publisherId, 'streamName' => $stream->name))), true);
     return $s;
 }
Beispiel #5
0
 /**
  * Subscribe to one or more streams, to start receiving notifications.
  * Posts "Streams/subscribe" message to the streams.
  * Also posts "Streams/subscribed" messages to user's "Streams/participating" stream.
  *	If options are not given check the subscription templates:
  *	1. generic publisher id and generic user
  *	2. exact publisher id and generic user
  *	3. generic publisher id and exact user
  *	default is to subscribe to ALL messages.
  *	If options are supplied - skip templates and use options.
  * Using subscribe if subscription is already active will modify existing
  * subscription - change type(s) or modify notifications
  * @method subscribe
  * @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 {array} [$options.filter] optional array with two keys
  * @param {array} [$options.filter.types] array of message types, if this is empty then subscribes to all types
  * @param {array} [$options.filter.notifications=0] limit number of notifications, 0 means no limit
  * @param {datetime} [$options.untilTime=null] time limit, if any for subscription
  * @param {array} [$options.rule=array()] optionally override the rule for new subscriptions
  * @param {array} [$options.rule.deliver=array('to'=>'default')] under "to" key,
  *   named the field under Streams/rules/deliver config, which will contain the names of destinations,
  *   which can include "email", "mobile", "email+pending", "mobile+pending"
  * @param {datetime} [$options.rule.readyTime] time from which user is ready to receive notifications again
  * @param {array} [$options.rule.filter] optionally set a filter for the rules to add
  * @param {boolean} [$options.skipRules] if true, do not attempt to create rules for new subscriptions
  * @param {boolean} [$options.skipAccess] if true, skip access check for whether user can join and subscribe
  * @return {array} An array of Streams_Participant rows from the database.
  */
 static function subscribe($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');
     }
     $participants = Streams::join($asUserId, $publisherId, $streams2, array('subscribed' => true, 'noVisit' => true, 'skipAccess' => Q::ifset($options, 'skipAccess', false)));
     $shouldUpdate = false;
     if (isset($options['filter'])) {
         $filter = Q::json_encode($options['filter']);
         $shouldUpdate = true;
     }
     $db = Streams_Subscription::db();
     if (isset($options['untilTime'])) {
         $untilTime = $db->toDateTime($options['untilTime']);
         $shouldUpdate = true;
     }
     $subscriptions = array();
     $rows = Streams_Subscription::select('*')->where(array('publisherId' => $publisherId, 'streamName' => $streamNames, 'ofUserId' => $asUserId))->fetchAll(PDO::FETCH_ASSOC);
     foreach ($rows as $row) {
         $sn = $row['streamName'];
         $subscriptions[$sn] = $row;
     }
     $messages = array();
     $pMessages = array();
     $streamNamesMissing = array();
     $streamNamesUpdate = array();
     foreach ($streamNames as $sn) {
         $messages[$publisherId][$sn] = array('type' => 'Streams/subscribe');
         $pMessages[] = array('type' => 'Streams/subscribed', 'instructions' => array('publisherId' => $publisherId, 'streamName' => $sn));
         if (empty($subscriptions[$sn])) {
             $streamNamesMissing[] = $sn;
             continue;
         }
         if ($shouldUpdate) {
             $streamNamesUpdate[] = $sn;
         }
     }
     if ($streamNamesUpdate) {
         Streams_Subscription::update()->set(compact('filter', 'untilTime'))->where(array('publisherId' => $publisherId, 'streamName' => $streamNamesUpdate, 'ofUserId' => $asUserId))->execute();
     }
     $rules = array();
     if ($streamNamesMissing) {
         $types = array();
         foreach ($streamNamesMissing as $sn) {
             $stream = $streams2[$sn];
             $types[$stream->type][] = $sn;
         }
         $subscriptionRows = array();
         $ruleRows = array();
         foreach ($types as $type => $sns) {
             // insert subscriptions
             if (!isset($filter) or !isset($untilTime)) {
                 $templates = Streams_Subscription::select('*')->where(array('publisherId' => array('', $publisherId), 'streamName' => $type . '/', 'ofUserId' => array('', $asUserId)))->fetchAll(PDO::FETCH_ASSOC);
                 $template = null;
                 foreach ($templates as $t) {
                     if (!$template or $template['publisherId'] == '' and $t['publisherId'] !== '' or $template['userId'] == '' and $t['userId'] !== '') {
                         $template = $t;
                     }
                 }
             }
             if (!isset($filter)) {
                 $filter = Q::json_encode($template ? Q::json_decode($template['filter']) : Streams_Stream::getConfigField($type, array('subscriptions', 'filter'), array("types" => array("^(?!(Users/)|(Streams/)).*/", "Streams/relatedTo", "Streams/chat/message"), "notifications" => 0)));
             }
             if (!isset($untilTime)) {
                 $untilTime = ($template and $template['duration'] > 0) ? new Db_Expression("CURRENT_TIMESTAMP + INTERVAL {$template['duration']} SECOND") : null;
             }
             foreach ($sns as $sn) {
                 $subscriptions[$sn] = $subscriptionRows[] = new Streams_Subscription(array('publisherId' => $publisherId, 'streamName' => $sn, 'ofUserId' => $asUserId, 'untilTime' => $untilTime, 'filter' => $filter));
             }
             if (!empty($options['skipRules'])) {
                 continue;
             }
             // insert up to one rule per subscription
             $rule = null;
             if (isset($options['rule'])) {
                 $rule = $options['rule'];
                 if (isset($rule['readyTime'])) {
                     $rule['readyTime'] = $db->toDateTime($rule['readyTime']);
                 }
                 if (isset($rule['filter']) and is_array($rule['filter'])) {
                     $rule['filter'] = Q::json_encode($rule['filter']);
                 }
                 if (isset($rule['deliver']) and is_array($rule['deliver'])) {
                     $rule['deliver'] = Q::json_encode($rule['deliver']);
                 }
             }
             if (!isset($rule)) {
                 $templates = Streams_Rule::select('*')->where(array('ofUserId' => array('', $asUserId), 'publisherId' => array('', $publisherId), 'streamName' => $type . '/', 'ordinal' => 1))->fetchAll(PDO::FETCH_ASSOC);
                 foreach ($templates as $t) {
                     if (!$rule or $rule['userId'] == '' and $t['userId'] !== '' or $rule['publisherId'] == '' and $t['publisherId'] !== '') {
                         $rule = $t;
                     }
                 }
             }
             if (!isset($rule)) {
                 $rule = array('deliver' => '{"to": "default"}', 'filter' => '{"types": [], "labels": []}');
             }
             if ($rule) {
                 $rule['ofUserId'] = $asUserId;
                 $rule['publisherId'] = $publisherId;
                 if (empty($rule['readyTime'])) {
                     $rule['readyTime'] = new Db_Expression("CURRENT_TIMESTAMP");
                 }
                 foreach ($sns as $sn) {
                     $row = $rule;
                     $row['streamName'] = $sn;
                     $row['ordinal'] = 1;
                     $row['filter'] = '';
                     $rules[$sn] = $ruleRows[] = $row;
                     $messages[$publisherId][$sn]['instructions'] = Q::json_encode(array('rule' => $row));
                 }
             }
         }
         Streams_Subscription::insertManyAndExecute($subscriptionRows);
         Streams_Rule::insertManyAndExecute($ruleRows);
     }
     foreach ($streamNames as $sn) {
         $subscription = $subscriptions[$sn];
         $stream = $streams2[$sn];
         // skip error testing for rule save BUT inform node.
         // Node can notify user to check the rules
         Q_Utils::sendToNode(array("Q/method" => "Streams/Stream/subscribe", "subscription" => Q::json_encode($subscription), "stream" => Q::json_encode($stream->toArray()), "rule" => isset($rules[$sn]) ? Q::json_encode($rules[$sn]) : null));
     }
     Streams_Message::postMessages($asUserId, $messages, true);
     Streams_Message::postMessages($asUserId, array($asUserId => array('Streams/participating' => $pMessages)), true);
     return $participants;
 }