/** * Displays an HTML document that can be printed, ideally with line breaks. * Uses a particular view for the layout. * @param {array} $_REQUEST * @param {string} $_REQUEST.invitingUserId Required. The id of the user that generated the invitations with a call to Streams::invite. * @param {string} $_REQUEST.batch Required. The name of the batch under which invitations were saved during a call to Streams::invite. * @param {string} [$_REQUEST.limit=100] The maximum number of invitations to show on the page * @param {string} [$_REQUEST.offset=0] Used for paging * @param {string} [$_REQUEST.title='Invitations'] Override the title of the document * @param {string} [$_REQUEST.layout='default'] The name of the layout to use for the HTML document * @see Users::addLink() */ function Streams_invitations_response() { Q_Request::requireFields(array('batch', 'invitingUserId'), true); $invitingUserId = $_REQUEST['invitingUserId']; $batch = $_REQUEST['batch']; $user = Users::loggedInUser(true); $stream = Streams::fetchOne(null, $invitingUserId, 'Streams/invitations', true); if (!$stream->testReadLevel('content')) { throw new Users_Exception_NotAuthorized(); } $title = Q::ifset($_REQUEST, 'layout', 'title'); $layoutKey = Q::ifset($_REQUEST, 'layout', 'default'); $limit = min(1000, Q::ifset($_REQUEST, 'limit', 100)); $offset = Q::ifset($_REQUEST, 'offset', 0); $layout = Q_Config::expect('Streams', 'invites', 'layout', $layoutKey); $pattern = Streams::invitationsPath($invitingUserId) . DS . $batch . DS . "*.html"; $filenames = glob($pattern); $parts = array(); foreach ($filenames as $f) { if (--$offset > 0) { continue; } $parts[] = file_get_contents($f); if (--$limit == 0) { break; } } $content = implode("\n\n<div class='Q_pagebreak Streams_invitations_separator'></div>\n\n", $parts); echo Q::view($layout, compact('title', 'content', 'parts')); return false; }
/** * Displays an HTML document that can be printed, ideally with line breaks. * Uses a particular view for the layout. * @param {array} $_REQUEST * @param {string} $_REQUEST.invitingUserId Required. The id of the user that generated the invitations with a call to Streams::invite. * @param {string} $_REQUEST.batch Required. The name of the batch under which invitations were saved during a call to Streams::invite. * @param {string} [$_REQUEST.limit=100] The maximum number of invitations to show on the page * @param {string} [$_REQUEST.offset=0] Used for paging * @param {string} [$_REQUEST.title='Invitations'] Override the title of the document * @param {string} [$_REQUEST.layout='default'] The name of the layout to use for the HTML document * @see Users::addLink() */ function Streams_invitations_response() { Q_Request::requireFields(array('batch', 'invitingUserId'), true); $invitingUserId = $_REQUEST['invitingUserId']; $batch = $_REQUEST['batch']; $title = Q::ifset($_REQUEST, 'layout', 'title'); $layoutKey = Q::ifset($_REQUEST, 'layout', 'default'); $limit = min(1000, Q::ifset($_REQUEST, 'limit', 100)); $offset = Q::ifset($_REQUEST, 'offset', 0); $layout = Q_Config::expect('Streams', 'invites', 'layout', $layoutKey); $app = Q_Config::expect('Q', 'app'); $pattern = Streams::invitationsPath($invitingUserId) . DS . $batch . DS . "*.html"; $filenames = glob($pattern); $parts = array(); foreach ($filenames as $f) { if (--$offset > 0) { continue; } $parts[] = file_get_contents($f); if (--$limit == 0) { break; } } $content = implode("\n\n<div class='Q_pagebreak Streams_invitations_separator'></div>\n\n", $parts); echo Q::view($layout, compact('content', 'parts')); return false; }
/** * Invites a user (or a future user) to a stream . * @method invite * @static * @param {string} $publisherId The id of the stream publisher * @param {string} $streamName The name of the stream the user will be invited to * @param {array} $who Array that can contain the following keys: * @param {string|array} [$who.userId] user id or an array of user ids * @param {string|array} [$who.fb_uid] fb user id or array of fb user ids * @param {string|array} [$who.label] label or an array of labels, or tab-delimited string * @param {string|array} [$who.identifier] identifier or an array of identifiers, or tab-delimited string * @param {integer} [$who.newFutureUsers] the number of new Users_User objects to create via Users::futureUser in order to invite them to this stream. This typically is used in conjunction with passing the "html" option to this function. * @param {array} [$options=array()] * @param {string|array} [$options.label] label or an array of labels for adding publisher's contacts * @param {string|array} [$options.myLabel] label or an array of labels for adding logged-in user's contacts * @param {integer} [$options.readLevel] => the read level to grant those who are invited * @param {integer} [$options.writeLevel] => the write level to grant those who are invited * @param {integer} [$options.adminLevel] => the admin level to grant those who are invited * @param {string} [$options.displayName] => the display name to use to represent the inviting user * @param {string} [$options.appUrl] => Can be used to override the URL to which the invited user will be redirected and receive "Q.Streams.token" in the querystring. * @param {array} [$options.html] => an array of ($template, $batchName) such as ("MyApp/foo.handlebars", "foo") for generating html snippets which can then be viewed from and printed via the action Streams/invitations?batchName=$batchName * @param {array} [$options.asUserId=null] Invite as this user id * @see Users::addLink() * @return {array} returns array with keys "success", "invited", "statuses", "identifierTypes", "alreadyParticipating" */ static function invite($publisherId, $streamName, $who, $options = array()) { if (isset($options['asUserId'])) { $asUserId = $options['asUserId']; $asUser = Users_User::fetch($asUserId); } else { $asUser = Users::loggedInUser(true); $asUserId = $asUser->id; } // Fetch the stream as the logged-in user $stream = Streams::fetch($asUserId, $publisherId, $streamName); if (!$stream) { throw new Q_Exception_MissingRow(array('table' => 'stream', 'criteria' => 'with that name'), 'streamName'); } $stream = reset($stream); // Do we have enough admin rights to invite others to this stream? if (!$stream->testAdminLevel('invite') || !$stream->testWriteLevel('join')) { throw new Users_Exception_NotAuthorized(); } if (isset($options['html'])) { $html = $options['html']; if (!is_array($html) or count($html) < 2) { throw new Q_Exception_WrongType(array('field' => "options.html", 'type' => 'array of 2 strings')); } list($template, $batchName) = $html; // validate these paths $filename = APP_VIEWS_DIR . DS . $template; if (!Q::realPath($filename)) { throw new Q_Exception_MissingFile(compact('filename')); } $ext = $pathinfo = pathinfo($template, PATHINFO_EXTENSION); if ($ext !== 'handlebars') { throw new Q_Exception_WrongValue(array('field' => 'options.html[0]', 'range' => 'a filename with extension .handlebars')); } $path = Streams::invitationsPath($asUserId) . DS . $batchName; Q_Utils::canWriteToPath($path, true, true); } // get user ids if any to array, throw if user not found $raw_userIds = isset($who['userId']) ? Users_User::verifyUserIds($who['userId'], true) : array(); // merge labels if any if (isset($who['label'])) { $label = $who['label']; if (is_string($label)) { $label = array_map('trim', explode("\t", $labels)); } $raw_userIds = array_merge($raw_userIds, Users_User::labelsToIds($asUserId, $label)); } // merge identifiers if any $identifierType = null; $statuses = null; if (isset($who['identifier'])) { $identifier = $who['identifier']; if (is_string($identifier)) { if (Q_Valid::email($who['identifier'])) { $identifierType = 'email'; } else { if (Q_Valid::phone($who['identifier'])) { $identifierType = 'mobile'; } } $identifier = array_map('trim', explode("\t", $identifier)); } $statuses = array(); $identifier_ids = Users_User::idsFromIdentifiers($identifier, $statuses); $raw_userIds = array_merge($raw_userIds, $identifier_ids); } // merge fb uids if any if (isset($who['fb_uid'])) { $fb_uids = $who['fb_uid']; if (is_string($fb_uids)) { $fb_uids = array_map('trim', explode("\t", $fb_uids)); } $raw_userIds = array_merge($raw_userIds, Users_User::idsFromFacebook($fb_uids)); } if (!empty($who['newFutureUsers'])) { $nfu = $who['newFutureUsers']; for ($i = 0; $i < $nfu; ++$i) { $raw_userIds[] = Users::futureUser('none', null)->id; } } // ensure that each userId is included only once // and remove already participating users $raw_userIds = array_unique($raw_userIds); $total = count($raw_userIds); $userIds = Streams_Participant::filter($raw_userIds, $stream); $to_invite = count($userIds); $appUrl = !empty($options['appUrl']) ? $options['appUrl'] : Q_Request::baseUrl() . '/' . Q_Config::get("Streams", "types", $stream->type, "invite", "url", "plugins/Streams/stream"); // now check and define levels for invited user $readLevel = isset($options['readLevel']) ? $options['readLevel'] : null; if (isset($readLevel)) { if (!$stream->testReadLevel($readLevel)) { // We can't assign greater read level to other people than we have ourselves! throw new Users_Exception_NotAuthorized(); } } $writeLevel = isset($options['writeLevel']) ? $options['writeLevel'] : null; if (isset($writeLevel)) { if (!$stream->testWriteLevel($writeLevel)) { // We can't assign greater write level to other people than we have ourselves! throw new Users_Exception_NotAuthorized(); } } $adminLevel = isset($options['adminLevel']) ? $options['adminLevel'] : null; if (isset($adminLevel)) { if (!$stream->testAdminLevel($adminLevel + 1)) { // We can't assign an admin level greater, or equal, to our own! // A stream's publisher can assign owners. Owners can assign admins. // Admins can confer powers to invite others, to some people. // Those people can confer the privilege to publish a message re this stream. // But admins can't assign other admins, and even stream owners // can't assign other owners. throw new Users_Exception_NotAuthorized(); } } // calculate expiry time $duration = Q_Config::get("Streams", "types", $stream->type, "invite", "duration", false); $expiry = $duration ? strtotime($duration) : null; // let node handle the rest, and get the result $params = array("Q/method" => "Streams/Stream/invite", "invitingUserId" => $asUserId, "username" => $asUser->username, "userIds" => Q::json_encode($userIds), "stream" => Q::json_encode($stream->toArray()), "appUrl" => $appUrl, "label" => Q::ifset($options, 'label', null), "myLabel" => Q::ifset($options, 'myLabel', null), "readLevel" => $readLevel, "writeLevel" => $writeLevel, "adminLevel" => $adminLevel, "displayName" => isset($options['displayName']) ? $options['displayName'] : Streams::displayName($asUser), "expiry" => $expiry); if ($template) { $params['template'] = $template; $params['batchName'] = $batchName; } $result = Q_Utils::queryInternal('Q/node', $params); return array('success' => $result, 'invited' => $userIds, 'statuses' => $statuses, 'identifierType' => $identifierType, 'alreadyParticipating' => $total - $to_invite); }