/** * Used to create a new relation * * @param array $_REQUEST * toPublisherId, toStreamName, type * fromPublisherId, fromStreamName, weight * @return {void} */ function Streams_related_post($params) { $user = Users::loggedInUser(true); $asUserId = $user->id; $toPublisherId = $_REQUEST['toPublisherId']; $toStreamName = $_REQUEST['toStreamName']; $type = $_REQUEST['type']; $fromPublisherId = $_REQUEST['fromPublisherId']; $fromStreamName = $_REQUEST['fromStreamName']; // TODO: When we start supporting multiple hosts, this will have to be rewritten // to make servers communicate with one another when establishing relations between streams if (!($stream = Streams::fetch($asUserId, $toPublisherId, $toStreamName))) { throw new Q_Exception_MissingRow(array('table' => 'stream', 'criteria' => 'with those fields'), array('publisherId', 'name')); } if (!($stream = Streams::fetch($asUserId, $fromPublisherId, $fromStreamName))) { throw new Q_Exception_MissingRow(array('table' => 'stream', 'criteria' => 'with those fields'), array('fromPublisherId', 'from_name')); } $weight = "+1"; if (isset($_REQUEST['weight'])) { if (!$stream->testWriteLevel('relations')) { throw new Users_Exception_NotAuthorized(); } $weight = $_REQUEST['weight']; } $result = Streams::relate($asUserId, $toPublisherId, $toStreamName, $type, $fromPublisherId, $fromStreamName, compact('weight')); Q_Response::setSlot('result', $result); }
/** * Used to create a new stream * * @param {array} $_REQUEST * @param {String} [$_REQUEST.title] Required. The title of the interest. * @param {String} [$_REQUEST.publisherId] Optional. Defaults to the app name. * @param {String} [$_REQUEST.subscribe] Optional. Defauls to false. Whether to subscribe rather than just join the interest stream. * @return {void} */ function Streams_interest_post() { $user = Users::loggedInUser(true); $title = Q::ifset($_REQUEST, 'title', null); if (!isset($title)) { throw new Q_Exception_RequiredField(array('field' => 'title')); } $app = Q_Config::expect('Q', 'app'); $publisherId = Q::ifset($_REQUEST, 'publisherId', $app); $name = 'Streams/interest/' . Q_Utils::normalize($title); $stream = Streams::fetchOne(null, $publisherId, $name); if (!$stream) { $stream = Streams::create($publisherId, $publisherId, 'Streams/interest', array('name' => $name, 'title' => $title)); $parts = explode(': ', $title, 2); $keywords = implode(' ', $parts); try { $data = Q_Image::pixabay($keywords, array('orientation' => 'horizontal', 'min_width' => '500', 'safesearch' => 'true', 'image_type' => 'photo'), true); } catch (Exception $e) { Q::log("Exception during Streams/interest post: " . $e->getMessage()); $data = null; } if (!empty($data)) { $sizes = Q_Config::expect('Streams', 'icons', 'sizes'); ksort($sizes); $params = array('data' => $data, 'path' => "plugins/Streams/img/icons", 'subpath' => $name, 'save' => $sizes, 'skipAccess' => true); Q_Image::save($params); $stream->icon = $name; } $stream->save(); } $subscribe = !!Q::ifset($_REQUEST, 'subscribe', false); if ($subscribe) { if (!$stream->subscription($user->id)) { $stream->subscribe(); } } else { $stream->join(); } $myInterestsName = 'Streams/user/interests'; $myInterests = Streams::fetchOne($user->id, $user->id, $myInterestsName); if (!$myInterests) { $myInterests = new Streams_Stream(); $myInterests->publisherId = $user->id; $myInterests->name = $myInterestsName; $myInterests->type = 'Streams/category'; $myInterests->title = 'My Interests'; $myInterests->save(); } Streams::relate($user->id, $user->id, 'Streams/user/interests', 'Streams/interest', $publisherId, $name, array('weight' => '+1')); Q_Response::setSlot('publisherId', $publisherId); Q_Response::setSlot('streamName', $name); /** * Occurs when the logged-in user has successfully added an interest via HTTP * @event Streams/interest/post {after} * @param {string} publisherId The publisher of the interest stream * @param {string} title The title of the interest * @param {boolean} subscribe Whether the user subscribed to the interest stream * @param {Users_User} user The logged-in user * @param {Streams_Stream} stream The interest stream * @param {Streams_Stream} myInterests The user's "Streams/user/interests" stream */ Q::event("Streams/interest/add", compact('publisherId', 'title', 'subscribe', 'user', 'stream', 'myInterests'), 'after'); }
/** * Relate another stream, published by the same publisher, to this stream * @param {Streams_Stream} $fromStream The stream to relate to this stream * @param {string} $type The type of relation * @param {string} [$asUserId=null] Override the user id to perform this action as * @param {array} [$options=array()] Any options to pass to Streams::relate * @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 "messageFrom" and "messageTo" and values of type Streams_Message */ function relateFrom($fromStream, $type, $asUserId = null, $options = array()) { return Streams::relate($asUserId, $this->publisherId, $this->name, $type, $fromStream->publisherId, $fromStream->name, $options); }
/** * 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) { $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 = Q_Config::get('Streams', 'types', $type, 'defaults', array()); 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 ($relate['streamName']) { $rs = Streams::fetchOne($asUserId, $relate['publisherId'], $relate['streamName']); if ($rs and $rs->inheritAccess) { // inherit from the same stream $rs does $inherit = $rs->inheritAccess; } else { // inherit from $rs $json = Q::json_encode(array(array($relate['publisherId'], $relate['streamName']))); } $stream->inheritAccess = $json; } $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)); Q_Response::setSlot('messageTo', $result['messageTo']->exportArray()); } self::$fetch[$asUserId][$publisherId][$stream->name] = array('*' => $stream); return $stream; }
/** * Call this function to relate a stream to category streams for things happening * around the given location. * @method relateTo * @static * @param {string} $publisherId The publisherId of the category streams * @param {double} $latitude The latitude of the coordinates near which to relate * @param {double} $longitude The longitude of the coordinates near which to relate * @param {string} $fromPublisherId The publisherId of the stream to relate * @param {string} $fromStreamName The name of the stream to relate * @param {string} $relationType The type of the relation to add * @param {array} $options The options to pass to the Streams::relate and Streams::create functions. Also can contain the following options: * @param {array} [$options.miles] Override the default set of distances found in the config under Places/nearby/miles * @param {callable} [$options.create] If set, this callback will be used to create streams when they don't already exist. It receives the $options array and should return a Streams_Stream object. Otherwise the category stream is skipped. * @param {callable} [$options.transform="array_keys"] Can be used to override the function which takes the output of Places_Nearby::forPublishers, and this $options array, and returns the array of ($originalName => $newCategoryName) pairs. * @return {array|boolean} Returns the array of category streams */ static function relateTo($publisherId, $latitude, $longitude, $fromPublisherId, $fromStreamName, $relationType, $options = array()) { $miles = Q::ifset($options, 'miles', null); $nearby = Places_Nearby::forPublishers($latitude, $longitude, $miles); if (!isset($fromPublisherId)) { $fromPublisherId = Q_Config::expect('Q', 'app'); } if ($transform = Q::ifset($options, 'transform', null)) { $create = Q::ifset($options, 'create', null); $transformed = call_user_func($transform, $nearby, $options); } else { $transformed = array_keys($nearby); $create = Q::ifset($options, 'create', array('Places_Nearby', '_create')); } $streams = Streams::fetch(null, $publisherId, $transformed); foreach ($nearby as $k => $info) { $name = isset($transformed[$k]) ? $transformed[$k] : $k; if (empty($streams[$name])) { if (empty($create)) { continue; } $params = compact('publisherId', 'latitude', 'longitude', 'fromPublisherId', 'fromStreamName', 'relationType', 'transformed', 'miles', 'nearby', 'name', 'info', 'streams'); $streams[$name] = call_user_func($create, $params, $options); } $stream = $streams[$name]; Streams::relate(null, $stream->publisherId, $stream->name, $relationType, $fromPublisherId, $fromStreamName, $options); } return $streams; }