function Streams_0_8_6_Streams_mysql() { $app = Q_Config::expect('Q', 'app'); // access for managing communities $access = new Streams_Access(); $access->publisherId = $app; $access->streamName = 'Streams/community*'; $access->ofUserId = ''; $access->ofContactLabel = "{$app}/admins"; $access->readLevel = Streams::$READ_LEVEL['messages']; $access->writeLevel = Streams::$WRITE_LEVEL['edit']; $access->adminLevel = Streams::$ADMIN_LEVEL['manage']; $access->save(); // access for managing categories $access = new Streams_Access(); $access->publisherId = $app; $access->streamName = 'Streams/category/'; $access->ofUserId = ''; $access->ofContactLabel = "{$app}/admins"; $access->readLevel = Streams::$READ_LEVEL['messages']; $access->writeLevel = Streams::$WRITE_LEVEL['close']; $access->adminLevel = Streams::$ADMIN_LEVEL['manage']; $access->save(); // template to help users relate things to Streams/category streams Streams_Stream::insert(array('publisherId' => '', 'name' => 'Streams/category/', 'type' => 'Streams/template', 'title' => 'Untitled Category', 'icon' => 'Streams/category', 'content' => '', 'attributes' => null, 'readLevel' => Streams::$READ_LEVEL['messages'], 'writeLevel' => Streams::$WRITE_LEVEL['relate'], 'adminLevel' => Streams::$ADMIN_LEVEL['invite']))->execute(); // template to help users create subcategories for things Streams_RelatedTo::insert(array('toPublisherId' => '', 'toStreamName' => 'Streams/category/', 'type' => 'subcategories', 'fromPublisherId' => '', 'fromStreamName' => 'Streams/category/'))->execute(); }
function Streams_0_8_4_Streams_mysql() { $app = Q_Config::expect('Q', 'app'); $communityId = Users::communityId(); $user = Users_User::fetch($communityId); // avatar for the App user $avatar = new Streams_Avatar(); $avatar->toUserId = $communityId; $avatar->publisherId = $communityId; $avatar->username = $user->username; $avatar->firstName = Users::communityName(); $avatar->lastName = Users::communitySuffix(); $avatar->icon = $user->icon; $avatar->save(); $avatar2 = new Streams_Avatar(); $avatar2->copyFrom($avatar, null, false, true); $avatar->toUserId = ''; $avatar->save(); // access stream for managing app roles $stream = new Streams_Stream(); $stream->publisherId = Users::communityId(); $stream->name = 'Streams/contacts'; $stream->type = 'Streams/resource'; $stream->title = "Contacts"; $stream->setAttribute('prefixes', array("Users/", "{$app}/")); $stream->save(); // access stream for managing app roles $stream = new Streams_Stream(); $stream->publisherId = $app; $stream->name = 'Streams/labels'; $stream->type = 'Streams/resource'; $stream->title = "Labels"; $stream->setAttribute('prefixes', array("Users/", "{$app}/")); $stream->save(); // access for managing app contacts $access = new Streams_Access(); $access->publisherId = $communityId; $access->streamName = 'Streams/contacts'; $access->ofUserId = ''; $access->ofContactLabel = "{$app}/admins"; $access->readLevel = Streams::$READ_LEVEL['messages']; $access->writeLevel = Streams::$WRITE_LEVEL['edit']; $access->adminLevel = Streams::$ADMIN_LEVEL['manage']; $access->save(); // access for managing app roles $access = new Streams_Access(); $access->publisherId = $communityId; $access->streamName = 'Streams/labels'; $access->ofUserId = ''; $access->ofContactLabel = "{$app}/admins"; $access->readLevel = Streams::$READ_LEVEL['messages']; $access->writeLevel = Streams::$WRITE_LEVEL['edit']; $access->adminLevel = Streams::$ADMIN_LEVEL['manage']; $access->save(); }
function Websites_0_8_3_Streams_mysql() { $app = Q_Config::expect('Q', 'app'); // access for managing communities $access = new Streams_Access(); $access->publisherId = $app; $access->streamName = 'Streams/community*'; $access->ofUserId = ''; $access->ofContactLabel = "Websites/admins"; $access->readLevel = Streams::$READ_LEVEL['messages']; $access->writeLevel = Streams::$WRITE_LEVEL['edit']; $access->adminLevel = Streams::$ADMIN_LEVEL['manage']; $access->save(); }
function Websites_0_9_1_Streams_mysql() { $userId = Users::communityId(); $ofUserId = ''; $ofContactLabel = 'Websites/admins'; $grantedByUserId = null; $streams = array("Websites/presentation/" => array('type' => "Streams/template", "title" => "Untitled Presentation", "icon" => "{{baseUrl}}/plugins/Websites/img/icons/Websites/presentation", "content" => "", "deletable" => true), "Websites/slide/" => array('type' => "Streams/template", "title" => "Untitled Slide", "icon" => "{{baseUrl}}/plugins/Websites/img/icons/Websites/presentation", "content" => "", "deletable" => true)); $readLevel = Streams::$READ_LEVEL['messages']; $adminLevel = Streams::$ADMIN_LEVEL['own']; $rows = array(); foreach ($streams as $streamName => $stream) { $publisherId = substr($streamName, -1) == '/' ? '' : $userId; $level = !empty($stream['deletable']) ? 'close' : 'edit'; $writeLevel = Streams::$WRITE_LEVEL[!empty($stream['deletable']) ? 'close' : 'edit']; $rows[] = compact('publisherId', 'streamName', 'ofUserId', 'ofContactLabel', 'grantedByUserId', 'readLevel', 'writeLevel', 'adminLevel'); } Streams_Access::insertManyAndExecute($rows); $attributes = null; $closedTime = null; $readLevel = Streams::$READ_LEVEL['messages']; $writeLevel = Streams::$WRITE_LEVEL['join']; $adminLevel = Streams::$ADMIN_LEVEL['invite']; $inheritAccess = null; $rows = array(); foreach ($streams as $name => $s) { extract($s); $publisherId = substr($name, -1) == '/' ? '' : $userId; $rows[] = compact('publisherId', 'name', 'type', 'title', 'icon', 'content', 'attributes', 'readLevel', 'writeLevel', 'adminLevel', 'inheritAccess'); } Streams_Stream::insertManyAndExecute($rows); Streams_RelatedTo::insert(array('toPublisherId' => '', 'toStreamName' => 'Websites/presentation/', 'type' => 'slides', 'fromPublisherId' => '', 'fromStreamName' => 'Websites/slide/'))->execute(); }
function Streams_0_8_8_Streams_mysql() { $communityId = Users::communityId(); $user = Users_User::fetch($communityId, true); Streams::create($communityId, $communityId, 'Streams/resource', array('name' => 'Streams/invitations', 'readLevel' => 0, 'writeLevel' => 0, 'adminLevel' => 0)); Streams_Access::insert(array('publisherId' => $communityId, 'streamName' => "Streams/invitations", 'ofUserId' => '', 'grantedByUserId' => null, 'ofContactLabel' => "{$app}/admins", 'readLevel' => Streams::$READ_LEVEL['messages'], 'writeLevel' => Streams::$WRITE_LEVEL['close'], 'adminLevel' => Streams::$ADMIN_LEVEL['invite']))->execute(); }
function Streams_access_put($params) { $user = Users::loggedInUser(true); Q_Valid::nonce(true); $publisherId = Streams::requestedPublisherId(true); $streamName = Streams::requestedName(true); $stream = Streams::fetchOne($user->id, $publisherId, $streamName); if (!$stream) { throw new Q_Exception_MissingRow(array('table' => 'stream', 'criteria' => 'with that name')); } if (!$stream->testAdminLevel('own')) { throw new Users_Exception_NotAuthorized(); } $p = array_merge($_REQUEST, $params); $access = new Streams_Access(); $access->publisherId = $stream->publisherId; $access->streamName = $stream->name; $access->ofUserId = Q::ifset($_REQUEST, 'ofUserId', ''); $access->ofContactLabel = Q::ifset($_REQUEST, 'ofContactLabel', ''); if (empty($access->ofUserId) and empty($access->ofContactLabel)) { $fields = array('grantedByUserId', 'filter', 'readLevel', 'writeLevel', 'adminLevel', 'permissions'); foreach ($fields as $field) { if (isset($p[$field])) { $stream->{$field} = $p[$field]; } } $stream->save(); return; } $access->retrieve(); $fields = array('grantedByUserId', 'filter', 'readLevel', 'writeLevel', 'adminLevel', 'permissions'); foreach ($fields as $field) { if (isset($p[$field])) { $access->{$field} = $p[$field]; } } $defaults = array('grantedByUserId' => $user->id, 'readLevel' => -1, 'writeLevel' => -1, 'adminLevel' => -1); foreach ($defaults as $k => $v) { if (!isset($access->{$k})) { $access->{$k} = $v; } } $access->save(); Streams::$cache['access'] = $access; }
function Websites_0_8_Streams_mysql() { $userId = Q_Config::get("Websites", "user", "id", null); if (!$userId) { throw new Q_Exception('Websites: Please fill in the config field "Websites"/"user"/"id"'); } // $now = Streams::db()->toDateTime(Streams::db()->getCurrentTimestamp()); $ofUserId = ''; $ofContactLabel = 'Websites/admins'; $grantedByUserId = null; $streams = array("Streams/images/" => array('type' => "Streams/template", "title" => "Images", "icon" => "default", "content" => "", "deletable" => true), "Streams/image/" => array('type' => "Streams/template", "title" => "Untitled Image", "icon" => "Streams/image", "content" => "", "deletable" => true), "Streams/file/" => array('type' => "Streams/template", "title" => "Untitled File", "icon" => "files/_blank", "content" => "", "deletable" => true), "Websites/article/" => array('type' => "Streams/template", "title" => "Untitled Article", "icon" => "default", "content" => "", "deletable" => true), "Websites/seo/" => array('type' => "Streams/template", "title" => "Website SEO", "icon" => Q_Html::themedUrl("plugins/Websites/img/seo"), "content" => "", "deletable" => true), "Websites/header" => array('type' => "Streams/image/icon", "title" => "Header image", "icon" => Q_Html::themedUrl("plugins/Websites/img/header"), "content" => ""), "Websites/slogan" => array('type' => "Streams/text/small", "title" => "Website slogan", "icon" => "default", "content" => "The coolest website"), "Websites/title" => array('type' => "Streams/text/small", "title" => "Website title", "icon" => "default", "content" => "Website Title"), "Websites/menu" => array('type' => "Streams/category", "title" => "Website Menu", "icon" => "default", "content" => ""), "Websites/articles" => array('type' => "Streams/category", "title" => "Articles", "icon" => "default", "content" => "Articles"), "Websites/images" => array('type' => "Streams/category", "title" => "Images", "icon" => "default", "content" => "Articles")); $readLevel = Streams::$READ_LEVEL['messages']; $writeLevel = Streams::$WRITE_LEVEL['edit']; $adminLevel = Streams::$ADMIN_LEVEL['own']; $rows = array(); foreach ($streams as $streamName => $stream) { $publisherId = substr($streamName, -1) == '/' ? '' : $userId; $writeLevel = !empty($stream['deletable']) ? 40 : 30; $rows[] = compact('publisherId', 'streamName', 'ofUserId', 'ofContactLabel', 'grantedByUserId', 'readLevel', 'writeLevel', 'adminLevel'); } Streams_Access::insertManyAndExecute($rows); $attributes = null; $closedTime = null; $readLevel = Streams::$READ_LEVEL['messages']; $writeLevel = Streams::$WRITE_LEVEL['join']; $adminLevel = Streams::$ADMIN_LEVEL['invite']; $inheritAccess = null; $rows = array(); foreach ($streams as $name => $s) { extract($s); if (substr($name, 0, 9) != 'Websites/') { continue; // this tempate was already added by Streams install script } $publisherId = substr($name, -1) == '/' ? '' : $userId; $rows[] = compact('publisherId', 'name', 'type', 'title', 'icon', 'content', 'attributes', 'readLevel', 'writeLevel', 'adminLevel', 'inheritAccess'); } Streams_Stream::insertManyAndExecute($rows); Streams_RelatedTo::insert(array('toPublisherId' => '', 'toStreamName' => 'Streams/images/', 'type' => 'images', 'fromPublisherId' => '', 'fromStreamName' => 'Streams/image/'))->execute(); Streams_RelatedTo::insert(array('toPublisherId' => '', 'toStreamName' => 'Streams/category/', 'type' => 'articles', 'fromPublisherId' => '', 'fromStreamName' => 'Websites/article/'))->execute(); Streams_RelatedTo::insert(array('toPublisherId' => '', 'toStreamName' => 'Streams/category/', 'type' => 'announcements', 'fromPublisherId' => '', 'fromStreamName' => 'Websites/article/'))->execute(); }
function Streams_0_8_7_Streams_mysql() { $app = Q_Config::expect('Q', 'app'); $user = Users_User::fetch($app, true); $simulated = array('row' => $user, 'inserted' => true, 'modifiedFields' => $user->fields); Q::event('Db/Row/Users_User/saveExecute', $simulated, 'after'); $stream = array('publisherId' => '', 'name' => "Streams/images/", 'type' => 'Streams/template', 'title' => 'Image Gallery', 'icon' => 'default', 'content' => '', 'attributes' => null, 'readLevel' => Streams::$READ_LEVEL['messages'], 'writeLevel' => Streams::$WRITE_LEVEL['close'], 'adminLevel' => Streams::$ADMIN_LEVEL['invite']); $access = array('publisherId' => '', 'streamName' => "Streams/images/", 'ofUserId' => '', 'grantedByUserId' => null, 'ofContactLabel' => "{$app}/admins", 'readLevel' => Streams::$READ_LEVEL['messages'], 'writeLevel' => Streams::$WRITE_LEVEL['close'], 'adminLevel' => Streams::$ADMIN_LEVEL['invite']); Streams_Stream::insert($stream)->execute(); Streams_Access::insert($access)->execute(); $stream['name'] = $access['streamName'] = 'Streams/image/'; $stream['icon'] = 'Streams/image'; $stream['title'] = 'Untitled Image'; Streams_Stream::insert($stream)->execute(); Streams_Access::insert($access)->execute(); $stream['name'] = $access['streamName'] = 'Streams/file/'; $stream['icon'] = 'files/_blank'; $stream['title'] = 'Untitled File'; Streams_Stream::insert($stream)->execute(); Streams_Access::insert($access)->execute(); }
function Streams_after_Users_User_saveExecute($params) { // If the username or icon was somehow modified, // update all the avatars for this publisher $modifiedFields = $params['modifiedFields']; $user = $params['row']; $updates = array(); if (isset($modifiedFields['username'])) { $updates['username'] = $modifiedFields['username']; } if (isset($modifiedFields['icon'])) { $updates['icon'] = $modifiedFields['icon']; } if ($user->id === Users::communityId()) { $firstName = Users::communityName(); $lastName = Users::communitySuffix(); $firstName = $firstName ? $firstName : ""; $lastName = $lastName ? $lastName : ""; } else { $firstName = Q::ifset(Streams::$cache, 'register', 'first', ''); $lastName = Q::ifset(Streams::$cache, 'register', 'last', ''); } if ($params['inserted']) { // create some standard streams for them $onInsert = Q_Config::get('Streams', 'onInsert', 'Users_User', array()); if (!$onInsert) { return; } $p = new Q_Tree(); $p->load(STREAMS_PLUGIN_CONFIG_DIR . DS . 'streams.json'); $p->load(APP_CONFIG_DIR . DS . 'streams.json'); $values = array('Streams/user/firstName' => $firstName, 'Streams/user/lastName' => $lastName); // Check for user data from facebook if (!empty(Users::$cache['facebookUserData'])) { $userData = Users::$cache['facebookUserData']; foreach ($userData as $name_fb => $value) { foreach ($p->getAll() as $name => $info) { if (isset($info['name_fb']) and $info['name_fb'] === $name_fb) { $onInsert[] = $name; $values[$name] = $value; } } } } foreach ($onInsert as $name) { $stream = Streams::fetchOne($user->id, $user->id, $name); if (!$stream) { // it shouldn't really be in the db yet $stream = new Streams_Stream(); $stream->publisherId = $user->id; $stream->name = $name; } $stream->type = $p->expect($name, "type"); $stream->title = $p->expect($name, "title"); $stream->content = $p->get($name, "content", ''); // usually empty $stream->readLevel = $p->get($name, 'readLevel', Streams_Stream::$DEFAULTS['readLevel']); $stream->writeLevel = $p->get($name, 'writeLevel', Streams_Stream::$DEFAULTS['writeLevel']); $stream->adminLevel = $p->get($name, 'adminLevel', Streams_Stream::$DEFAULTS['adminLevel']); if ($name === "Streams/user/icon") { $sizes = Q_Config::expect('Users', 'icon', 'sizes'); sort($sizes); $stream->setAttribute('sizes', $sizes); $stream->icon = $user->iconUrl(); } if (isset($values[$name])) { $stream->content = $values[$name]; } $stream->save(); // this also inserts avatars $o = array('userId' => $user->id, 'skipAccess' => true); $so = $p->get($name, "subscribe", array()); if ($so === false) { $stream->join($o); } else { $stream->subscribe(array_merge($o, $so)); } } // Save a greeting stream, to be edited $communityId = Users::communityId(); Streams::create($user->id, $user->id, "Streams/greeting", array('name' => "Streams/greeting/{$communityId}")); // Create some standard labels $label = new Users_Label(); $label->userId = $user->id; $label->label = 'Streams/invited'; $label->icon = 'labels/Streams/invited'; $label->title = 'People I invited'; $label->save(true); $label2 = new Users_Label(); $label2->userId = $user->id; $label2->label = 'Streams/invitedMe'; $label2->icon = 'labels/Streams/invitedMe'; $label2->title = 'Who invited me'; $label2->save(true); // By default, users they invite should see their full name $access = new Streams_Access(); $access->publisherId = $user->id; $access->streamName = 'Streams/user/firstName'; $access->ofUserId = ''; $access->ofContactLabel = 'Streams/invited'; $access->grantedByUserId = $user->id; $access->readLevel = Streams::$READ_LEVEL['content']; $access->writeLevel = -1; $access->adminLevel = -1; $access->save(); $access = new Streams_Access(); $access->publisherId = $user->id; $access->streamName = 'Streams/user/lastName'; $access->ofUserId = ''; $access->ofContactLabel = 'Streams/invited'; $access->grantedByUserId = $user->id; $access->readLevel = Streams::$READ_LEVEL['content']; $access->writeLevel = -1; $access->adminLevel = -1; $access->save(); // NOTE: the above saving of access caused Streams::updateAvatar to run, // insert a Streams_Avatar row for the new user, and properly configure it. } else { if ($modifiedFields) { if ($updates) { Streams_Avatar::update()->set($updates)->where(array('publisherId' => $user->id))->execute(); } foreach ($modifiedFields as $field => $value) { $name = Q_Config::get('Streams', 'onUpdate', 'Users_User', $field, null); if (!$name) { continue; } $stream = isset(Streams::$beingSaved[$field]) ? Streams::$beingSaved[$field] : Streams::fetchOne($user->id, $user->id, $name); if (!$stream) { // it should probably already be in the db continue; } $stream->content = $value; if ($name === "Streams/user/icon") { $sizes = Q_Config::expect('Users', 'icon', 'sizes'); sort($sizes); $attributes = $stream->attributes; $stream->setAttribute('sizes', $sizes); $stream->icon = $changes['icon'] = $user->iconUrl(); } Streams::$beingSavedQuery = $stream->changed($user->id); } } } }
function Streams_before_Q_objects() { $token = Q_Request::special('Streams.token', null); if ($token === null) { return; } $invite = Streams_Invite::fromToken($token); if (!$invite) { throw new Q_Exception_MissingRow(array('table' => 'invite', 'criteria' => "token = '{$token}"), 'token'); } // did invite expire? $ts = Streams_Invite::db()->select("CURRENT_TIMESTAMP")->fetchAll(PDO::FETCH_NUM); if (isset($invite->expireTime) and $invite->expireTime < $ts[0][0]) { $invite->state = 'expired'; $invite->save(); } // is invite still pending? if ($invite->state !== 'pending') { switch ($invite->state) { case 'expired': $exception = new Streams_Exception_AlreadyExpired(null, 'token'); break; case 'accepted': $exception = new Streams_Exception_AlreadyAccepted(null, 'token'); break; case 'declined': $exception = new Streams_Exception_AlreadyDeclined(null, 'token'); break; case 'forwarded': $exception = new Streams_Exception_AlreadyForwarded(null, 'token'); break; default: $exception = new Q_Exception("This invite has already been " . $invite->state, 'token'); break; } $shouldThrow = Q::event('Streams/objects/inviteException', compact('invite', 'exception'), 'before'); if ($shouldThrow === null) { Q_Response::setNotice('Streams/objects', $exception->getMessage(), true); } else { if ($shouldThrow === true) { throw $exception; } } } // now process the invite $invitedUser = Users_User::fetch($invite->userId, true); $stream = Streams::fetchOne($invitedUser->id, $invite->publisherId, $invite->streamName); if (!$stream) { throw new Q_Exception_MissingRow(array('table' => 'stream', 'criteria' => "publisherId = '{$invite->publisherId}', name = '{$invite->streamName}'")); } $byUser = Users_User::fetch($invite->invitingUserId, true); $byStream = Streams::fetchOne($byUser->id, $invite->publisherId, $invite->streamName); if (!$byStream) { throw new Q_Exception_MissingRow(array('table' => 'stream', 'criteria' => "publisherId = '{$invite->publisherId}', name = '{$invite->streamName}'")); } $access = new Streams_Access(); $access->publisherId = $byStream->publisherId; $access->streamName = $byStream->name; $access->ofUserId = $invite->userId; $specified_access = false; foreach (array('readLevel', 'writeLevel', 'adminLevel') as $level_type) { $access->{$level_type} = -1; if (empty($invite->{$level_type})) { continue; } // Give access level from the invite. // However, if inviting user has a lower access level now, // then give that level instead, unless it is lower than // what the invited user would have had otherwise. $min = min($invite->{$level_type}, $byStream->get($level_type, 0)); if ($min > $stream->get($level_type, 0)) { $access->{$level_type} = $min; $specified_access = true; } } if ($specified_access) { $access->save(true); } // now log invited user in $user = Users::loggedInUser(); if (empty($user) or $user->id !== $invite->userId) { $user = new Users_User(); $user->id = $invite->userId; if (!$user->retrieve()) { // The user who was invited doesn't exist // This shouldn't happen. We just silently log it and return. Q::log("Sanity check failed: invite with {$invite->token} pointed to nonexistent user"); return; } Users::setLoggedInUser($user); } // accept invite and autosubscribe if first time if ($invite->accept() and !$stream->subscription($user->id)) { $stream->subscribe(); } // retain the invite object for further processing Streams::$followedInvite = $invite; }
/** * Starts a recurring subscription * @param {Streams_Stream} $plan The subscription plan stream * @param {string} [$payments=null] The type of payments processor, could be "authnet" or "stripe". If omitted, the subscription proceeds without any payments. * @param {array} [$options=array()] Options for the subscription * @param {date} [$options.startDate=today] The start date of the subscription * @param {date} [$options.endDate=today+year] The end date of the subscription * @param {Users_User} [$options.user=Users::loggedInUser()] Allows us to set the user to subscribe * @param {Users_User} [$options.publisherId=Users::communityId()] Allows us to override the publisher to subscribe to * @param {string} [$options.description=null] description of the charge, to be sent to customer * @param {string} [$options.metadata=null] any additional metadata to store with the charge * @param {string} [$options.subscription=null] if this charge is related to a subscription stream * @param {string} [$options.subscription.publisherId] * @param {string} [$options.subscription.streamName] * @throws Assets_Exception_DuplicateTransaction * @throws Assets_Exception_HeldForReview * @throws Assets_Exception_ChargeFailed * @return {Streams_Stream} A stream of type 'Assets/subscription' representing this subscription */ static function startSubscription($plan, $payments = null, $options = array()) { if (!isset($options['user'])) { $options['user'] = Users::loggedInUser(true); } $app = Q_Config::expect('Q', 'app'); $user = Q::ifset($options, 'user', Users::loggedInUser(true)); $currency = 'USD'; // TODO: may want to implement support for currency conversion $startDate = Q::ifset($options, 'startDate', date("Y-m-d")); $startDate = date('Y-m-d', strtotime($startDate)); $months = $plan->getAttribute('months', 12); $amount = $plan->getAttribute('amount'); $endDate = date("Y-m-d", strtotime("-1 day", strtotime("+{$months} month", strtotime($startDate)))); $endDate = date('Y-m-d', strtotime($endDate)); $publisherId = Q::ifset($options, 'publisherId', Users::communityId()); $publisher = Users_User::fetch($publisherId); $streamName = "Assets/subscription/{$user->id}/{$plan->name}"; if ($subscription = Streams::fetchOne($publisherId, $publisherId, $streamName)) { return $subscription; // it already started } $attributes = Q::json_encode(array('payments' => $payments, 'planPublisherId' => $plan->publisherId, 'planStreamName' => $plan->name, 'startDate' => $startDate, 'endDate' => $endDate, 'months' => $months, 'amount' => $amount, 'currency' => $currency)); $stream = Streams::create($publisherId, $publisherId, "Assets/subscription", array('name' => $streamName, 'title' => $plan->title, 'readLevel' => Streams::$READ_LEVEL['none'], 'writeLevel' => Streams::$WRITE_LEVEL['none'], 'adminLevel' => Streams::$ADMIN_LEVEL['none'], 'attributes' => $attributes)); $access = new Streams_Access(array('publisherId' => $publisherId, 'streamName' => $streamName, 'ofUserId' => $user->id, 'grantedByUserId' => $app, 'readLevel' => Streams::$READ_LEVEL['max'], 'writeLevel' => -1, 'adminLevel' => -1)); $access->save(); $amount = $plan->getAttribute('amount', null); if (!is_numeric($amount)) { throw new Q_Exception_WrongValue(array('field' => 'amount', 'range' => 'an integer')); } $options['stream'] = $stream; if ($payments) { Assets::charge($payments, $amount, $currency, $options); } /** * @event Assets/startSubscription {before} * @param {Streams_Stream} plan * @param {Streams_Stream} subscription * @param {string} startDate * @param {string} endDate * @return {Users_User} */ Q::event('Assets/startSubscription', compact('plan', 'user', 'publisher', 'stream', 'startDate', 'endDate', 'months', 'currency'), 'after'); return $stream; }
/** * @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; }
/** * Calculates the access for one or more streams by querying the database * Modifies the objects in the $streams array, setting their access levels. * After the function returns, you will be able to call the methods * testReadLevel(), testWriteLevel() and testAdminLevel() * on these streams before using them on the user's behalf. * @method fetch * @static * @param {string} $asUserId * Set this to the user relative to whom access is calculated. * If this matches the publisherId, just sets full access and calls publishedByFetcher(true). * If this is '', only returns the streams anybody can see. * If this is null, the logged-in user's id is used, or '' if no one is logged in * @param {string} $publisherId * The id of the user publishing these streams * @param {array} $streams * An array of streams, obtained for example by Streams::fetch * @param {boolean} $recalculate=false * Pass true here to force recalculating access to streams for which access was already calculated * @return {integer} * The number of streams that were recalculated */ static function calculateAccess($asUserId, $publisherId, $streams, $recalculate = 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; } if ($recalculate) { $streams2 = $streams; } else { $streams2 = array(); foreach ($streams as $k => $s) { if ($s->get('readLevel', null) === null) { $streams2[$k] = $s; } } } if (empty($streams2)) { return 0; } $public_source = Streams::$ACCESS_SOURCES['public']; $contact_source = Streams::$ACCESS_SOURCES['contact']; $direct_source = Streams::$ACCESS_SOURCES['direct']; $streams3 = array(); $names = array(); foreach ($streams2 as $s) { if ($s->get('asUserId', null) === $asUserId) { continue; } $s->set('asUserId', $asUserId); if ($asUserId and $asUserId == $publisherId) { // The publisher should have full access to every one of their streams. // Streams which are "required", though, won't be deleted by the system. $required = Q_Config::get('Streams', 'requiredUserStreams', $s->name, false); $s->set('isRequired', $required); $s->set('readLevel', Streams::$READ_LEVEL['max']); $s->set('writeLevel', Streams::$WRITE_LEVEL['max']); $s->set('adminLevel', Streams::$ADMIN_LEVEL['max']); $s->set('readLevel_source', $direct_source); $s->set('writeLevel_source', $direct_source); $s->set('adminLevel_source', $direct_source); $s->publishedByFetcher(true); continue; } $s->set('readLevel', $s->readLevel); $s->set('writeLevel', $s->writeLevel); $s->set('adminLevel', $s->adminLevel); $s->set('readLevel_source', $public_source); $s->set('writeLevel_source', $public_source); $s->set('adminLevel_source', $public_source); if (empty($asUserId)) { continue; // No need to fetch further access info. } $names[] = $s->name; $names[] = $s->type . "*"; $streams3[] = $s; } if (empty($names)) { return count($streams2); } // Get the per-label access data // Avoid making a join to allow more flexibility for sharding $accesses = Streams_Access::select('*')->where(array('publisherId' => $publisherId, 'streamName' => $names, 'ofUserId' => array('', $asUserId)))->fetchDbRows(); $labels = array(); foreach ($accesses as $access) { if ($access->ofContactLabel) { $labels[] = $access->ofContactLabel; } } if (!empty($labels)) { $labels = array_unique($labels); $contacts = Users_Contact::select('*')->where(array('userId' => $publisherId, 'label' => $labels, 'contactUserId' => $asUserId))->fetchDbRows(); foreach ($contacts as $contact) { foreach ($accesses as $access) { if ($access->ofContactLabel !== $contact->label) { continue; } foreach ($streams3 as $stream) { $tail = substr($access->streamName, -1); $head = substr($access->streamName, 0, -1); if ($stream->name !== $access->streamName and ($tail !== '*' or $head !== $stream->type)) { continue; } $readLevel = $stream->get('readLevel', 0); $writeLevel = $stream->get('writeLevel', 0); $adminLevel = $stream->get('adminLevel', 0); if ($access->readLevel >= 0 and $access->readLevel > $readLevel) { $stream->set('readLevel', $access->readLevel); $stream->set('readLevel_source', $contact_source); } if ($access->writeLevel >= 0 and $access->writeLevel > $writeLevel) { $stream->set('writeLevel', $access->writeLevel); $stream->set('writeLevel_source', $contact_source); } if ($access->adminLevel >= 0 and $access->adminLevel > $adminLevel) { $stream->set('adminLevel', $access->adminLevel); $stream->set('adminLevel_source', $contact_source); } } } } } // Override with per-user access data foreach ($accesses as $access) { foreach ($streams3 as $stream) { $tail = substr($access->streamName, -1); $head = substr($access->streamName, 0, -1); if ($stream->name !== $access->streamName and ($tail !== '*' or $head !== $stream->type)) { continue; } if ($access->ofUserId === $asUserId) { if ($access->readLevel >= 0) { $stream->set('readLevel', $access->readLevel); $stream->set('readLevel_source', $direct_source); } if ($access->writeLevel >= 0) { $stream->set('writeLevel', $access->writeLevel); $stream->set('writeLevel_source', $direct_source); } if ($access->adminLevel >= 0) { $stream->set('adminLevel', $access->adminLevel); $stream->set('adminLevel_source', $direct_source); } } } } return count($streams2); }
/** * Access tool * @class Streams access * @constructor * @param {array} $options Options for the tool * @param {string} [$options.publisherId] the id of the user who is publishing the stream * @param {string} [$options.streamName] the name of the stream for which to edit access levels * @param {array} [$options.tabs] array of tab name => title. Defaults to read, write, admin tabs. * @param {array} [$options.ranges] associative array with keys "read", "write", "admin" and values as associative arrays of ($min, $max) for the displayed levels. * @param {boolean} [$options.controls] optionally set this to true to render only the controls */ function Streams_access_tool($options) { $tabs = array('read' => 'visible to', 'write' => 'editable by', 'admin' => 'members'); extract($options); $user = Users::loggedInUser(true); /** * @var string $streamName */ if (empty($streamName)) { $streamName = Streams::requestedName(true); } if (empty($publisherId)) { $publisherId = Streams::requestedPublisherId(); if (empty($publisherId)) { $publisherId = $user->id; } } reset($tabs); $tab = Q::ifset($_REQUEST, 'tab', key($tabs)); $stream = Streams::fetchOne($user->id, $publisherId, $streamName); if (!$stream) { throw new Q_Exception_MissingRow(array('table' => 'stream', 'criteria' => 'with that name')); } $stream->addPreloaded($user->id); if (!$stream->testAdminLevel('own')) { throw new Users_Exception_NotAuthorized(); } $access_array = Streams_Access::select('*')->where(array('publisherId' => $stream->publisherId, 'streamName' => $stream->name))->andWhere("{$tab}Level != -1")->fetchDbRows(); $labelRows = Users_Label::fetch($stream->publisherId, '', true); $labels = array(); $icons = array(); foreach ($labelRows as $label => $row) { $labels[$label] = $row->title; $icons[$label] = "labels/{$label}"; } $userId_list = array(); foreach ($access_array as $a) { if ($a->ofUserId) { $userId_list[] = $a->ofUserId; } } $avatar_array = empty($userId_list) ? array() : Streams_Avatar::fetch($user->id, $userId_list); switch ($tab) { case 'read': $levels = Q_Config::get('Streams', 'readLevelOptions', array()); break; case 'write': $levels = Q_Config::get('Streams', 'writeLevelOptions', array()); break; case 'admin': $levels = Q_Config::get('Streams', 'adminLevelOptions', array()); break; } if (isset($ranges[$tab])) { $range_min = reset($ranges[$tab]); $range_max = end($ranges[$tab]); foreach ($levels as $k => $v) { if ($k < $range_min) { unset($levels[$k]); } if ($k > $range_max) { unset($levels[$k]); } } } $accessActionUrl = Q_Uri::url("Streams/access?publisherId={$publisherId}&streamName={$streamName}"); $dir = Q_Config::get('Users', 'paths', 'icons', 'files/Users/icons'); $accessArray = Db::exportArray($access_array); $avatarArray = Db::exportArray($avatar_array); if (empty($controls)) { Q_Response::addScript("plugins/Streams/js/Streams.js"); Q_Response::addScript("plugins/Streams/js/tools/access.js"); Q_Response::setToolOptions(compact('accessArray', 'avatarArray', 'labels', 'icons', 'tab', 'publisherId', 'streamName')); } else { Q_Response::setSlot('extra', array('stream' => $stream->exportArray(), 'accessArray' => $accessArray, 'avatarArray' => $avatarArray, 'labels' => $labels, 'icons' => $icons)); } return Q::view('Streams/tool/access.php', compact('stream', 'tabs', 'tab', 'labels', 'icons', 'levels', 'dir', 'publisherId', 'streamName', 'accessActionUrl', 'controls')); }
/** * Keeps Access table consistent on row deletion and update avatar * @method afterRemoveExecute * @param {Db_Result} $result * Query result * @param {array} $query * The query which has been excecuted * @return {Db_Result} */ function afterRemoveExecute($result, $query) { if (!empty($this->ofUserId)) { // Removed an access for a specific user Streams::updateAvatar($this->ofUserId, $this->publisherId); return $result; } if (empty($this->ofContactLabel)) { return $result; } // Update all avatars corresponding to access rows for this stream $tainted_access = Streams_Access::select('*')->where(array('publisherId' => $this->publisherId, 'streamName' => $this->streamName))->fetchDbRows(); $found = false; foreach ($tainted_access as $ca) { if ($ca->ofContactLabel === $this->ofContactLabel) { // this should never really happen, since the row was just deleted $found = true; $ca->set('removed', true); } } if (!$found) { $this->set('removed', true); $tainted_access[] = $this; } Streams::updateAvatars($this->publisherId, $tainted_access, $this->streamName); return $result; }