function Streams_message_response_messages() { if (isset(Streams::$cache['message'])) { $message = Streams::$cache['message']; return Db::exportArray(array($message->ordinal => $message)); } if (isset(Streams::$cache['messages'])) { return Db::exportArray(Streams::$cache['messages']); } $publisherId = Streams::requestedPublisherId(true); $streamName = Streams::requestedName(true); $type = Streams::requestedMessageType(); $stream = Q::ifset(Streams::$cache, 'stream', Streams::fetchOne(null, $publisherId, $streamName, true)); $maxLimit = Streams_Stream::getConfigField($type, 'getMessagesLimit', 100); $limit = min($maxLimit, Q::ifset($_REQUEST, 'limit', $maxLimit)); if (isset($_REQUEST['ordinal'])) { $min = $_REQUEST['ordinal']; $limit = 1; } if (isset($_REQUEST['min'])) { $min = $_REQUEST['min']; } $max = isset($_REQUEST['max']) ? $_REQUEST['max'] : -1; if (isset($_REQUEST['ascending'])) { $ascending = $_REQUEST['ascending']; } if (!$stream->testReadLevel('messages')) { throw new Users_Exception_NotAuthorized(); } $messages = $stream->getMessages(compact('type', 'min', 'max', 'limit', 'ascending')); return Db::exportArray($messages); }
function Streams_after_Q_objects() { $user = Users::loggedInUser(); if (!$user) { return; } $invite = Streams::$followedInvite; if (!$invite) { return; } $displayName = $user->displayName(); if ($displayName) { return; } $stream = new Streams_Stream(); $stream->publisherId = $invite->publisherId; $stream->name = $invite->streamName; if (!$stream->retrieve()) { throw new Q_Exception_MissingRow(array('table' => 'stream', 'criteria' => 'with that name'), 'streamName'); } // Prepare the complete invite dialog $invitingUser = Users_User::fetch($invite->invitingUserId); list($relations, $related) = Streams::related($user->id, $stream->publisherId, $stream->name, false); $params = array('displayName' => null, 'action' => 'Streams/basic', 'icon' => $user->iconUrl(), 'token' => $invite->token, 'user' => array('icon' => $invitingUser->iconUrl(), 'displayName' => $invitingUser->displayName(array('fullAccess' => true))), 'stream' => $stream->exportArray(), 'relations' => Db::exportArray($relations), 'related' => Db::exportArray($related)); $config = Streams_Stream::getConfigField($stream->type, 'invite', array()); $defaults = Q::ifset($config, 'dialog', array()); $tree = new Q_Tree($defaults); if ($tree->merge($params)) { $dialogData = $tree->getAll(); if ($dialogData) { Q_Response::setScriptData('Q.plugins.Streams.invite.dialog', $dialogData); Q_Response::addTemplate('Streams/invite/complete'); } } }
function Streams_after_Q_file_save($params) { $path = $subpath = $name = $writePath = $data = $tailUrl = $size = $audio = null; extract($params, EXTR_OVERWRITE); if (!empty(Streams::$cache['canWriteToStream'])) { // some stream's associated file was being changed $stream = Streams::$cache['canWriteToStream']; } if (empty($stream)) { return; } $url = Q_Valid::url($tailUrl) ? $tailUrl : '{{baseUrl}}/' . $tailUrl; $stream->setAttribute('Q.file.url', $url); $stream->setAttribute('Q.file.size', $size); if ($audio) { include_once Q_CLASSES_DIR . DS . 'Audio' . DS . 'getid3' . DS . 'getid3.php'; $getID3 = new getID3(); $meta = $getID3->analyze($writePath . $name); $bitrate = $meta['audio']['bitrate']; $bits = $size * 8; $duration = $bits / $bitrate; $stream->setAttribute('Q.audio.bitrate', $bitrate); $stream->setAttribute('Q.audio.duration', $duration); } if (Streams_Stream::getConfigField($stream->type, 'updateTitle', false)) { // set the title every time a new file is uploaded $stream->title = $name; } if (Streams_Stream::getConfigField($stream->type, 'updateIcon', false)) { // set the icon every time a new file is uploaded $parts = explode('.', $name); $urlPrefix = Q_Request::baseUrl() . '/plugins/Streams/img/icons/files'; $dirname = STREAMS_PLUGIN_FILES_DIR . DS . 'Streams' . DS . 'icons' . DS . 'files'; $extension = end($parts); $stream->icon = file_exists($dirname . DS . $extension) ? "{$urlPrefix}/{$extension}" : "{$urlPrefix}/_blank"; } if (empty(Streams::$beingSavedQuery)) { $stream->changed(); } else { $stream->save(); } }
/** * 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; }
/** * Used to update an existing stream * * @param string $params Must include "publisherId" as well as "name" or "streamName". * Can also include 'type', 'title', 'icon', 'content', 'attributes', 'readLevel', * 'writeLevel', 'adminLevel', as well as any fields named in the * 'Streams'/'types'/$type/'fields' config field for this $type of stream. * @param {string} [$params.publisherId] The id of the user publishing the stream * @param {string} [$params.name] The name of the stream * @param {string} [$params.streamName] Alternatively, the name of the stream * @param {array} [$params.attributes] Array of attributeName => value to set in stream. * @param {array} [$params.icon] Optional array of icon data (see Q_Image::save params) * @return {} */ function Streams_stream_put($params) { // only logged in user can edit stream $user = Users::loggedInUser(true); $publisherId = Streams::requestedPublisherId(); if (empty($publisherId)) { $publisherId = $_REQUEST['publisherId'] = $user->id; } $name = Streams::requestedName(true); $req = array_merge($_REQUEST, $params); if (array_key_exists('closedTime', $req)) { $closedTime = $req['closedTime']; if (in_array($closedTime, array(false, 'false', 'null'))) { $req['closedTime'] = null; } } // do not set stream name $stream = Streams::fetchOne($user->id, $publisherId, $name); if (!$stream) { throw new Q_Exception_MissingRow(array('table' => 'stream', 'criteria' => "{publisherId: '{$publisherId}', name: '{$name}'}")); } // valid stream types should be defined in config by 'Streams/type' array $range = Q_Config::expect('Streams', 'types'); if (!array_key_exists($stream->type, $range)) { throw new Q_Exception("This app doesn't support streams of type " . $stream->type); } // check if editing directly from client is allowed $edit = Streams_Stream::getConfigField($stream->type, 'edit', false); if (!$edit) { throw new Q_Exception("This app doesn't let clients directly edit streams of type '{$stream->type}'"); } $suggest = false; if ($stream->publisherId != $user->id) { $stream->calculateAccess($user->id); if (!$stream->testWriteLevel('edit')) { if ($stream->testWriteLevel('suggest')) { $suggest = true; } else { throw new Users_Exception_NotAuthorized(); } } } $restricted = array('readLevel', 'writeLevel', 'adminLevel', 'permissions', 'inheritAccess', 'closedTime'); $owned = $stream->testAdminLevel('own'); // owners can reopen streams foreach ($restricted as $r) { if (isset($req[$r]) and !$owned) { throw new Users_Exception_NotAuthorized(); } } // handle setting of attributes if (isset($req['attributes']) and is_array($req['attributes'])) { foreach ($req['attributes'] as $k => $v) { $stream->setAttribute($k, $v); } unset($req['attributes']); } // Get all the extended field names for this stream type $fieldNames = Streams::getExtendFieldNames($stream->type); // Prevent editing restricted fields if (is_array($edit)) { $restrictedFields = array_diff($fieldNames, $edit); foreach ($restrictedFields as $fieldName) { if (in_array($fieldName, array('publisherId', 'name', 'streamName'))) { continue; } if (isset($req[$fieldName])) { throw new Users_Exception_NotAuthorized(); } } } // Process any icon that was posted $icon = Q::ifset($fieldNames, 'icon', null); if (is_array($icon)) { unset($fieldNames['icon']); Q_Response::setSlot('icon', Q::event("Q/image/post", $icon)); } // Process any file that was posted $file = Q::ifset($fieldNames, 'file', null); if (is_array($file)) { unset($fieldNames['file']); $data = Q::event("Q/file/post", $file); Q_Response::setSlot('file', $data); } if (!empty($fieldNames)) { foreach ($fieldNames as $f) { if (array_key_exists($f, $req)) { $stream->{$f} = $req[$f]; } } $stream->changed($user->id, $suggest ? 'Streams/suggest' : 'Streams/changed'); } if (!empty($req['join'])) { $stream->join(); } Streams::$cache['stream'] = $stream; }
/** * Used by HTTP clients to create a new stream in the system. * @class HTTP Streams stream * @method post * @param {array} [$params] Parameters that can come from the request * @param {string} $params.publisherId Required. The id of the user to publish the stream. * @param {string} $params.type Required. The type of the stream. * @param {string} [$params.Q_Streams_related_publisherId] Optionally indicate the publisher of the stream to relate the newly created to. Used together with the related.streamName option. * @param {string} [$params.Q_Streams_related_streamName] Optionally indicate the name of a stream to relate the newly crated stream to. This is often necessary in order to obtain permissions to create the stream. * @param {bool} [$params.dontSubscribe=false] Pass 1 or true here in order to skip auto-subscribing to the newly created stream. * @param {array} [$params.icon] This is used to upload a custom icon for the stream which will then be saved in different sizes. See fields for Q/image/post method * @param {string} [$params.icon.data] Required if $_FILES is empty. Base64-encoded data URI - see RFC 2397 * @param {string} [$params.icon.path="uploads"] parent path under web dir (see subpath) * @param {string} [$params.icon.subpath=""] subpath that should follow the path, to save the image under * @param {string} [$params.icon.merge=""] path under web dir for an optional image to use as a background * @param {string} [$params.icon.crop] array with keys "x", "y", "w", "h" to crop the original image * @param {string} [$params.icon.save=array("x" => "")] array of $size => $basename pairs * where the size is of the format "WxH", and either W or H can be empty. * @param {array} [$params.file] This is used to upload a custom icon for the stream which will then be saved in different sizes. See fields for Q/image/post method * @param {string} [$params.file.data] Required if $_FILES is empty. Base64-encoded data URI - see RFC 2397 * @param {string} [$params.file.path="uploads"] parent path under web dir (see subpath) * @param {string} [$params.file.subpath=""] subpath that should follow the path, to save the file under * @param {string} [$params.file.name] override name of the file, after the subpath */ function Streams_stream_post($params = array()) { $user = Users::loggedInUser(true); $publisherId = Streams::requestedPublisherId(); if (empty($publisherId)) { $publisherId = $_REQUEST['publisherId'] = $user->id; } $req = array_merge($_REQUEST, $params); $type = Streams::requestedType(true); $types = Q_Config::expect('Streams', 'types'); if (!array_key_exists($type, $types)) { throw new Q_Exception("This app doesn't support streams of type {$type}", 'type'); } $create = Streams_Stream::getConfigField($type, 'create', false); if (!$create) { throw new Q_Exception("This app doesn't let clients directly create streams of type {$type}", 'type'); } // Should this stream be related to another stream? $relate = array(); $relate['streamName'] = Q_Request::special("Streams.related.streamName", null, $req); if (isset($relate['streamName'])) { $relate['publisherId'] = Q_Request::special("Streams.related.publisherId", $publisherId, $req); $relate['type'] = Q_Request::special("Streams.related.type", "", $req); $relate['weight'] = "+1"; // TODO: introduce ways to have "1" and "+1" for some admins etc. } // Split the id for saving files in the filesystem $splitId = Q_Utils::splitId($publisherId); // Hold on to any icon that was posted $icon = null; if (!empty($req['icon']) and is_array($req['icon'])) { $icon = $req['icon']; unset($req['icon']); } // Hold on to any file that was posted $file = null; if (!empty($req['file']) and is_array($req['file'])) { $file = $req['file']; unset($req['file']); } // Check if the user owns the stream if ($user->id === $publisherId) { $asOwner = true; } else { $streamTemplate = Streams_Stream::getStreamTemplate($publisherId, $type, 'Streams_Stream'); $asOwner = $streamTemplate ? $streamTemplate->testAdminLevel('own') : false; } // Check if client can set the name of this stream if (isset($req['name'])) { $possible = Q_Config::get('Streams', 'possibleUserStreams', $req['name'], false); if (!$asOwner or !$possible) { throw new Users_Exception_NotAuthorized(); } } // Get allowed fields $allowedFields = array_merge(array('publisherId', 'name', 'type', 'icon', 'file'), Streams::getExtendFieldNames($type, $asOwner)); $fields = Q::take($req, $allowedFields); // Prevent setting restricted fields if (is_array($create)) { $restrictedFields = array_diff($allowedFields, $create); foreach ($restrictedFields as $fieldName) { if (in_array($fieldName, array('publisherId', 'type'))) { continue; } if (isset($req[$fieldName])) { throw new Users_Exception_NotAuthorized(); } } } // Create the stream $stream = Streams::create($user->id, $publisherId, $type, $fields, $relate, $result); $messageTo = false; if (isset($result['messagesTo'])) { $messageTo = reset($result['messagesTo']); $messageTo = reset($messageTo); if (is_array($messageTo)) { $messageTo = reset($messageTo); } $messageTo = $messageTo->exportArray(); } Q_Response::setSlot('messageTo', $messageTo); // Process any icon that was posted if ($icon === true) { $icon = array(); } if (is_array($icon)) { if (empty($icon['path'])) { $icon['path'] = 'uploads/Streams'; } if (empty($icon['subpath'])) { $icon['subpath'] = "{$splitId}/{$stream->name}/icon/" . time(); } Q_Response::setSlot('icon', Q::event("Q/image/post", $icon)); // the Streams/after/Q_image_save hook saves some attributes } // Process any file that was posted if ($file === true) { $file = array(); } if (is_array($file)) { if (empty($file['path'])) { $file['path'] = 'uploads/Streams'; } if (empty($file['subpath'])) { $file['subpath'] = "{$splitId}/{$stream->name}/file/" . time(); } Q_Response::setSlot('file', Q::event("Q/file/post", $file)); // the Streams/after/Q_file_save hook saves some attributes } // Re-fetch the stream object from the Streams::fetch cache, // since it might have been retrieved and modified to be different // from what is currently in $stream. // This also calculates the access levels on the stream. $stream = Streams::fetchOne($user->id, $publisherId, $stream->name); if (empty($req['dontSubscribe'])) { // autosubscribe to streams you yourself create, using templates $stream->subscribe(); } Streams::$cache['stream'] = $stream; }
/** * Find out whether a certain field is restricted from being * edited by clients via the regular Streams REST API. * @method restrictedFromClient * @static * @param {string} $streamType * @param {string} $fieldName * @param {string} [$whenCreating=false] * @return {boolean} */ static function restrictedFromClient($streamType, $fieldName, $whenCreating = false) { $during = $whenCreating ? 'create' : 'edit'; $info = Streams_Stream::getConfigField($streamType, $during, false); if (!$info) { return true; } if (is_array($info) and !in_array($fieldName, $info)) { return true; } return false; }
/** * Creates a new stream in the system * @method create * @static * @param {string} $asUserId The user who is attempting to create the stream. * @param {string} $publisherId The id of the user to publish the stream. * @param {string} $type The type of the stream to create. * @param {array} $fields Use this to set additional fields for the stream: * @param {string} [$fields.title=null] You can set the stream's title * @param {string} [$fields.icon=null] You can set the stream's icon * @param {string} [$fields.title=null] You can set the stream's content * @param {string} [$fields.attributes=null] You can set the stream's attributes directly as a JSON string * @param {string|integer} [$fields.readLevel=null] You can set the stream's read access level, see Streams::$READ_LEVEL * @param {string|integer} [$fields.writeLevel=null] You can set the stream's write access level, see Streams::$WRITE_LEVEL * @param {string|integer} [$fields.adminLevel=null] You can set the stream's admin access level, see Streams::$ADMIN_LEVEL * @param {string} [$fields.name=null] Here you can specify an exact name for the stream to be created. Otherwise a unique one is generated automatically. * @param {boolean} [$fields.skipAccess=false] Skip all access checks when creating and relating the stream. * @param {array} [$relate=array()] * The user would also be authorized if the stream would be related to * an existing category stream, in which the user has a writeLevel of at least "relate", * and the user that would be publishing this new stream has a template for this stream type * that is related to either the category stream or a template matching the category stream. * To test for this, pass an array with the following keys: * @param {string} $relate.publisherId The id of the user publishing that stream, defaults to $publisherId * @param {string} $relate.streamName The name of the stream to which the new stream would be related * @param {string} [$relate.type] The type of relation, defaults to "" * @param {string} [$relate.weight] To set the weight for the relation * @return {Streams_Stream|boolean} Returns the stream that was created. * @throws {Users_Exception_NotAuthorized} */ static function create($asUserId, $publisherId, $type, $fields = array(), $relate = null, &$result = null) { $skipAccess = Q::ifset($fields, 'skipAccess', false); if (!isset($asUserId)) { $asUserId = Users::loggedInUser(); if (!$asUserId) { $asUserId = ""; } } if ($asUserId instanceof Users_User) { $asUserId = $asUserId->id; } if ($publisherId instanceof Users_User) { $publisherId = $publisherId->id; } $authorized = self::isAuthorizedToCreate($asUserId, $publisherId, $type, $relate); if (!$authorized and !$skipAccess) { throw new Users_Exception_NotAuthorized(); } // OK we are good to go! $stream = new Streams_Stream(); $stream->publisherId = $publisherId; if (!empty($fields['name'])) { $p = new Q_Tree(); $p->load(STREAMS_PLUGIN_CONFIG_DIR . DS . 'streams.json'); $p->load(APP_CONFIG_DIR . DS . 'streams.json'); if ($info = $p->get($fields['name'], array())) { foreach (Base_Streams_Stream::fieldNames() as $f) { if (isset($info[$f])) { $stream->{$f} = $info[$f]; } } } } if (!isset($stream->type)) { $stream->type = $type; } // prepare attributes field if (isset($fields['attributes']) and is_array($fields['attributes'])) { $fields['attributes'] = json_encode($fields['attributes']); } // extend with any config defaults for this stream type $fieldNames = Streams::getExtendFieldNames($type); $fieldNames[] = 'name'; $defaults = Streams_Stream::getConfigField($stream->type, 'defaults', Streams_Stream::$DEFAULTS); foreach ($fieldNames as $f) { if (isset($fields[$f])) { $stream->{$f} = $fields[$f]; } else { if (array_key_exists($f, $defaults)) { $stream->{$f} = $defaults[$f]; } } } // ready to persist this stream to the database if (!empty($relate['streamName'])) { $rs = Streams::fetchOne($asUserId, $relate['publisherId'], $relate['streamName']); if ($rs and $rs->inheritAccess) { // inherit from the same stream $rs does $inheritAccess = $rs->inheritAccess; } else { // inherit from $rs $inheritAccess = Q::json_encode(array(array($relate['publisherId'], $relate['streamName']))); } $stream->inheritAccess = $inheritAccess; } $stream->save(); $stream->post($asUserId, array('type' => 'Streams/created', 'content' => '', 'instructions' => Q::json_encode($stream->toArray())), true); // relate the stream to category stream, if any if ($relate['streamName']) { $result = Streams::relate($asUserId, $relate['publisherId'], $relate['streamName'], $relate['type'], $stream->publisherId, $stream->name, array('weight' => isset($relate['weight']) ? $relate['weight'] : null, 'skipAccess' => $skipAccess)); } self::$fetch[$asUserId][$publisherId][$stream->name] = array('*' => $stream); return $stream; }