Esempio n. 1
0
/**
 * 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.
 * @return {void}
 */
function Streams_interest_delete()
{
    $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) {
        throw new Q_Exception_MissingRow(array('table' => 'stream', 'criteria' => Q::json_encode(compact('publisherId', 'name'))));
    }
    $miPublisherId = $user->id;
    $miName = 'Streams/user/interests';
    $myInterests = Streams::fetchOne($user->id, $miPublisherId, $miName);
    if (!$myInterests) {
        throw new Q_Exception_MissingRow(array('table' => 'stream', 'criteria' => Q::json_encode(array('publisherId' => $miPublisherId, 'name' => $miName))));
    }
    $stream->leave();
    Streams::unrelate($user->id, $user->id, 'Streams/user/interests', 'Streams/interest', $publisherId, $name, array('adjustWeights' => true));
    Q_Response::setSlot('publisherId', $publisherId);
    Q_Response::setSlot('streamName', $name);
    /**
     * Occurs when the logged-in user has successfully removed an interest via HTTP
     * @event Streams/interest/delete {after}
     * @param {string} publisherId The publisher of the interest stream
     * @param {string} title The title of the interest
     * @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/remove", compact('publisherId', 'title', 'subscribe', 'user', 'stream', 'myInterests'), 'after');
}
Esempio n. 2
0
function Q_filters_reducisaurus($params)
{
    $parts = $params['parts'];
    $dest = $params['dest'];
    $processed = array();
    foreach ($parts as $src => $content) {
        $dest_parts = explode('/', $dest);
        $src_parts = explode('/', $src);
        $j = 0;
        foreach ($dest_parts as $i => $p) {
            if (!isset($src_parts[$i]) or $src_parts[$i] !== $dest_parts[$i]) {
                break;
            }
            $j = $i + 1;
        }
        $dc = count($dest_parts);
        $sc = count($src_parts);
        $relative = str_repeat("../", $dc - $j - 1) . implode('/', array_slice($src_parts, $j, $sc - $j - 1));
        if ($relative) {
            $relative .= '/';
        }
        $processed[$src] = preg_replace("/url\\((\\'){0,1}/", 'url($1' . $relative, $content);
    }
    $service_url = "http://reducisaurus.appspot.com/css";
    $options = array('file' => implode("\n\n", $processed));
    $result = Q_Utils::post($service_url, $options);
    if ($error = substr($result, 0, 5) === 'Error') {
        throw new Q_Exception("Reducisaurus:\n" . $result);
    }
    return $result;
}
Esempio n. 3
0
/**
 * Adds a label to the system. Fills the "label" (and possibly "icon") slot.
 * @param {array} $_REQUEST
 * @param {string} $_REQUEST.title The title of the label
 * @param {string} [$_REQUEST.label] You can override the label to use
 * @param {string} [$_REQUEST.icon] Optional path to an icon
 * @param {string} [$_REQUEST.userId=Users::loggedInUser(true)->id] You can override the user id, if another plugin adds a hook that allows you to do this
 */
function Users_label_post($params = array())
{
    $req = array_merge($_REQUEST, $params);
    Q_Request::requireFields(array('title'), $req, true);
    $loggedInUserId = Users::loggedInUser(true)->id;
    $userId = Q::ifset($req, 'userId', $loggedInUserId);
    $icon = Q::ifset($req, 'icon', null);
    $title = $req['title'];
    $l = Q::ifset($req, 'label', 'Users/' . Q_Utils::normalize($title));
    Users::canManageLabels($loggedInUserId, $userId, $l, true);
    $label = new Users_Label();
    $label->userId = $userId;
    $label->label = $l;
    if ($label->retrieve()) {
        throw new Users_Exception_LabelExists();
    }
    $label->title = $title;
    if (is_array($icon)) {
        // Process any icon that was posted
        $icon['path'] = 'uploads/Users';
        $icon['subpath'] = "{$userId}/label/{$label}/icon";
        $data = Q::event("Q/image/post", $icon);
        Q_Response::setSlot('icon', $data);
        $label->icon = Q_Request::baseUrl() . '/' . $data[''];
    } else {
        $label->icon = 'default';
    }
    $label->save();
    Q_Response::setSlot('label', $label->exportArray());
}
Esempio n. 4
0
 static function _create($params, $options)
 {
     $title = Q_Utils::normalize($options['title']);
     $info = $params['info'];
     $options['name'] = "Places/interest/{$info['geohash']}/{$info['miles']}/{$title}";
     return Streams::create(null, $params['publisherId'], 'Places/interest', $options);
 }
function Websites_0_8_Users_mysql()
{
    $userId = Users::communityId();
    Users_Label::addLabel('Websites/admins', $userId, 'Website Admins', 'labels/Websites/admins', false);
    if (!file_exists(USERS_PLUGIN_FILES_DIR . DS . 'Users' . DS . 'icons' . DS . 'Websites')) {
        Q_Utils::symlink(WEBSITES_PLUGIN_FILES_DIR . DS . 'Websites' . DS . 'icons' . DS . 'labels' . DS . 'Websites', USERS_PLUGIN_FILES_DIR . DS . 'Users' . DS . 'icons' . DS . 'labels' . DS . 'Websites');
    }
}
function Streams_before_Q_Utils_canWriteToPath($params, &$result)
{
    extract($params);
    /**
     * @var $path
     * @var $throwIfNotWritable
     * @var $mkdirIfMissing
     */
    // Assume that Users/before/Q/Utils/canWriteToPath already executed
    $user = Users::loggedInUser();
    $userId = $user ? $user->id : "";
    $app = Q_Config::expect('Q', 'app');
    $len = strlen(APP_DIR);
    if (substr($path, 0, $len) === APP_DIR) {
        $sp = str_replace(DS, '/', substr($path, $len + 1));
        if (substr($sp, -1) === '/') {
            $sp = substr($sp, 0, strlen($sp) - 1);
        }
        $prefix = "files/{$app}/uploads/Streams/";
        $len = strlen($prefix);
        if (substr($sp, 0, $len) === $prefix) {
            $splitId = Q_Utils::splitId($userId);
            $prefix2 = "files/{$app}/uploads/Streams/invitations/{$splitId}/";
            if ($userId and substr($sp, 0, strlen($prefix2)) === $prefix2) {
                $result = true;
                // user can write any invitations here
                return;
            }
            $parts = explode('/', substr($sp, $len));
            $c = count($parts);
            if ($c >= 3) {
                $result = false;
                for ($j = 0; $j < $c - 3; ++$j) {
                    $publisherId = implode('', array_slice($parts, 0, $j + 1));
                    $l = $j;
                    for ($i = $c - 1; $i > $j; --$i) {
                        $l = $i;
                        if (in_array($parts[$i], array('icon', 'file'))) {
                            break;
                        }
                    }
                    $name = implode('/', array_slice($parts, $j + 1, $l - $j - 1));
                    if ($name and $stream = Streams::fetchOne($userId, $publisherId, $name)) {
                        $result = $stream->testWriteLevel('edit');
                        Streams::$cache['canWriteToStream'] = $stream;
                        break;
                    }
                }
            }
        }
    }
    if (!$result and $throwIfNotWritable) {
        throw new Q_Exception_CantWriteToPath();
    }
}
Esempio n. 7
0
/**
 * This tool contains functionality to show things in columns
 * @class Q columns
 * @constructor
 * @param {array}   [options] Provide options for this tool
 *  @param {array}  [options.animation] For customizing animated transitions
 *  @param {integer}  [options.animation.duration] The duration of the transition in milliseconds, defaults to 500
 *  @param {array}  [options.animation.hide] The css properties in "hide" state of animation
 *  @param {array}  [options.animation.show] The css properties in "show" state of animation
 *  @param {array}  [options.back] For customizing the back button on mobile
 *  @param {string}  [options.back.src] The src of the image to use for the back button
 *  @param {boolean} [options.back.triggerFromTitle] Whether the whole title would be a trigger for the back button. Defaults to true.
 *  @param {boolean} [options.back.hide] Whether to hide the back button. Defaults to false, but you can pass true on android, for example.
 *  @param {array}  [options.close] For customizing the back button on desktop and tablet
 *  @param {string}  [options.close.src] The src of the image to use for the close button
 *  @param {string}  [options.title] You can put a default title for all columns here (which is shown as they are loading)
 *  @param {string}  [options.column] You can put a default content for all columns here (which is shown as they are loading)
 *  @param {array}  [options.clickable] If not null, enables the Q/clickable tool with options from here. Defaults to null.
 *  @param {array}  [options.scrollbarsAutoHide] If not null, enables Q/scrollbarsAutoHide functionality with options from here. Enabled by default.
 *  @param {boolean} [options.fullscreen] Whether to use fullscreen mode on mobile phones, using document to scroll instead of relying on possibly buggy "overflow" CSS implementation. Defaults to true on Android, false everywhere else.
 *  @param {array}   [options.columns] In PHP only, an array of $name => $column pairs, where $column is in the form array('title' => $html, 'content' => $html, 'close' => true)
 * @return {string}
 */
function Q_columns_tool($options)
{
    $jsOptions = array('animation', 'back', 'close', 'title', 'scrollbarsAutoHide', 'fullscreen');
    Q_Response::setToolOptions(Q::take($options, $jsOptions));
    if (!isset($options['columns'])) {
        return '';
    }
    Q_Response::addScript('plugins/Q/js/tools/columns.js');
    Q_Response::addStylesheet('plugins/Q/css/columns.css');
    $result = '<div class="Q_columns_container Q_clearfix">';
    $columns = array();
    $i = 0;
    $closeSrc = Q::ifset($options, 'close', 'src', 'plugins/Q/img/x.png');
    $backSrc = Q::ifset($options, 'back', 'src', 'plugins/Q/img/back-v.png');
    foreach ($options['columns'] as $name => $column) {
        $close = Q::ifset($column, 'close', $i > 0);
        $Q_close = Q_Request::isMobile() ? 'Q_close' : 'Q_close Q_back';
        $closeHtml = !$close ? '' : (Q_Request::isMobile() ? '<div class="Q_close Q_back">' . Q_Html::img($backSrc, 'Back') . '</div>' : '<div class="Q_close">' . Q_Html::img($closeSrc, 'Close') . '</div>');
        $n = Q_Html::text($name);
        $columnClass = 'Q_column_' . Q_Utils::normalize($name) . ' Q_column_' . $i;
        if (isset($column['html'])) {
            $html = $column['html'];
            $columns[] = <<<EOT
\t<div class="Q_columns_column {$columnClass}" data-index="{$i}" data-name="{$n}">
\t\t{$html}
\t</div>
EOT;
        } else {
            $titleHtml = Q::ifset($column, 'title', '[title]');
            $columnHtml = Q::ifset($column, 'column', '[column]');
            $classes = $columnClass . ' ' . Q::ifset($column, 'class', '');
            $attrs = '';
            if (isset($column['data'])) {
                $json = Q::json_encode($column['data']);
                $attrs = 'data-more="' . Q_Html::text($json) . '"';
                foreach ($column['data'] as $k => $v) {
                    $attrs .= 'data-' . Q_Html::text($k) . '="' . Q_Html::text($v) . '" ';
                }
            }
            $data = Q::ifset($column, 'data', '');
            $columns[] = <<<EOT
\t<div class="Q_columns_column {$classes}" data-index="{$i}" data-name="{$n}" {$attrs}>
\t\t<div class="Q_columns_title">
\t\t\t{$closeHtml}
\t\t\t<h2 class="Q_title_slot">{$titleHtml}</h2>
\t\t</div>
\t\t<div class="Q_column_slot">{$columnHtml}</div>
\t</div>
EOT;
        }
        ++$i;
    }
    $result .= "\n" . implode("\n", $columns) . "\n</div>";
    return $result;
}
Esempio n. 8
0
/**
 * We are going to implement a subset of the OAuth 1.0a functionality for now,
 * and later we can expand it to match the full OAuth specification.
 */
function Users_authorize_response()
{
    if (Q_Response::getErrors()) {
        Q_Dispatcher::showErrors();
    }
    $response_type = 'token';
    $token_type = 'bearer';
    $client_id = $_REQUEST['client_id'];
    $state = $_REQUEST['state'];
    $skip = Q::ifset($_REQUEST, 'skip', false);
    $scope = Users_OAuth::requestedScope(true, $scopes);
    $client = Users_User::fetch($client_id, true);
    if (!$client) {
        throw new Q_Exception_MissingRow(array('table' => 'client user', 'criteria' => "id = '{$client_id}'"), 'client_id');
    }
    if (empty($client->url)) {
        throw new Q_Exception("Client app needs to register url", 'client_id');
    }
    $redirect_uri = Q::ifset($_REQUEST, 'redirect_uri', $client->url);
    $user = Users::loggedInUser();
    $oa = null;
    if (isset(Users::$cache['oAuth'])) {
        $oa = Users::$cache['oAuth'];
    } else {
        if ($user) {
            $oa = new Users_OAuth();
            $oa->client_id = $client_id;
            $oa->userId = $user->id;
            $oa->state = $state;
            $oa = $oa->retrieve();
        }
    }
    $remaining = $scope;
    if ($oa and $oa->wasRetrieved()) {
        // User is logged in and already has a token for this client_id and state
        $paths = Q_Config::get('Users', 'authorize', 'clients', Q::app(), 'redirectPaths', false);
        $path = substr($redirect_uri, strlen($client->url) + 1);
        $p = array('response_type' => $response_type, 'token_type' => $token_type, 'access_token' => $oa->access_token, 'expires_in' => $oa->token_expires_seconds, 'scope' => implode(' ', $scope), 'state' => $oa->state);
        $p = Q_Utils::sign($p, 'Q.Users.oAuth');
        // the redirect uri could be a native app url scheme
        $s = strpos($redirect_uri, '#') === false ? '#' : '&';
        $redirect_uri = Q_Uri::from($redirect_uri . $s . http_build_query($p), false)->toUrl();
        if (!Q::startsWith($redirect_uri, $client->url) or is_array($paths) and !in_array($path, $paths)) {
            throw new Users_Exception_Redirect(array('uri' => $redirect_uri));
        }
        Q_Response::redirect($redirect_uri);
        return false;
    }
    $terms_label = Users::termsLabel('authorize');
    Q_Response::setScriptData('Q.Users.authorize', compact('client_id', 'redirect_uri', 'scope', 'scopes', 'remaining', 'state', 'response_type', 'skip'));
    $content = Q::view('Users/content/authorize.php', compact('client', 'user', 'redirect_uri', 'scope', 'scopes', 'remaining', 'state', 'terms_label', 'response_type', 'skip'));
    Q_Response::setSlot('content', $content);
    Q_Response::setSlot('column0', $content);
    return true;
}
Esempio n. 9
0
function Websites_0_8_Users_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"');
    }
    Users_Label::addLabel('Websites/admins', $userId, 'Website Admins', 'labels/Websites/admins', false);
    if (!file_exists('Websites')) {
        Q_Utils::symlink(WEBSITES_PLUGIN_FILES_DIR . DS . 'Websites' . DS . 'icons' . DS . 'labels' . DS . 'Websites', USERS_PLUGIN_FILES_DIR . DS . 'Users' . DS . 'icons' . DS . 'Websites');
    }
}
Esempio n. 10
0
/**
 * Adds a label to the system. Fills the "label" (and possibly "icon") slot.
 * @param {array} $_REQUEST
 * @param {string} $_REQUEST.title The title of the label
 * @param {string} [$_REQUEST.label] You can override the label to use
 * @param {string} [$_REQUEST.icon] Optional path to an icon
 * @param {string} [$_REQUEST.userId=Users::loggedInUser(true)->id] You can override the user id, if another plugin adds a hook that allows you to do this
 */
function Users_label_post($params = array())
{
    $req = array_merge($_REQUEST, $params);
    Q_Request::requireFields(array('title'), $req, true);
    $loggedInUserId = Users::loggedInUser(true)->id;
    $userId = Q::ifset($req, 'userId', $loggedInUserId);
    $icon = Q::ifset($req, 'icon', null);
    $title = Q::ifset($req, 'title', null);
    $l = Q::ifset($req, 'label', 'Users/' . Q_Utils::normalize($title));
    $label = Users_Label::addLabel($l, $userId, $title, $icon);
    Q_Response::setSlot('label', $label->exportArray());
}
Esempio n. 11
0
/**
 * This is the default handler for the Q/responseExtras event.
 * It should not be invoked during AJAX requests, and especially
 * not during JSONP requests. It will output things like the nonce,
 * which prevents CSRF attacks, but is only supposed to be printed
 * on our webpages and not also given to anyone who does a JSONP request.
 */
function Q_before_Q_responseExtras()
{
    $app = Q_Config::expect('Q', 'app');
    $uri = Q_Dispatcher::uri();
    $url = Q_Request::url(true);
    $base_url = Q_Request::baseUrl();
    $ajax = Q_Request::isAjax();
    if (!$uri) {
        return;
    }
    $info = array('url' => $url, 'uriString' => (string) $uri);
    if ($uri) {
        $info['uri'] = $uri->toArray();
    }
    if (!$ajax) {
        $info = array_merge(array('app' => Q_Config::expect('Q', 'app')), $info, array('proxies' => Q_Config::get('Q', 'proxies', array()), 'baseUrl' => $base_url, 'proxyBaseUrl' => Q_Uri::url($base_url), 'proxyUrl' => Q_Uri::url($url), 'sessionName' => Q_Session::name(), 'nodeUrl' => Q_Utils::nodeUrl(), 'slotNames' => Q_Config::get("Q", "response", "slotNames", array('content', 'dashboard', 'title', 'notices'))));
    }
    foreach ($info as $k => $v) {
        Q_Response::setScriptData("Q.info.{$k}", $v);
    }
    if (!$ajax) {
        $uris = Q_Config::get('Q', 'javascript', 'uris', array());
        $urls = array();
        foreach ($uris as $u) {
            $urls["{$u}"] = Q_Uri::url("{$u}");
        }
        Q_Response::setScriptData('Q.urls', $urls);
    }
    // Export more variables to inline js
    $nonce = isset($_SESSION['Q']['nonce']) ? $_SESSION['Q']['nonce'] : null;
    if ($nonce) {
        Q_Response::setScriptData('Q.nonce', $nonce);
    }
    // Attach stylesheets and scripts
    foreach (Q_Config::get('Q', 'javascript', 'responseExtras', array()) as $src => $b) {
        if (!$b) {
            continue;
        }
        Q_Response::addScript($src);
    }
    foreach (Q_Config::get('Q', 'stylesheets', 'responseExtras', array()) as $src => $media) {
        if (!$media) {
            continue;
        }
        if ($media === true) {
            $media = 'screen,print';
        }
        Q_Response::addStylesheet($src, null, $media);
    }
}
Esempio n. 12
0
/**
 * Generates a form with inputs that modify various streams
 * @class Streams form
 * @constructor
 * @param {array} $options
 *  An associative array of parameters, containing:
 * @param {array} [$options.fields] an associative array of $id => $fieldinfo pairs,
 *   where $id is the id to append to the tool's id, to generate the input's id,
 *   and fieldinfo is either an associative array with the following fields,
 *   or a regular array consisting of fields in the following order:
 *     "publisherId" => Required. The id of the user publishing the stream
 *     "streamName" => Required. The name of the stream
 *     "field" => The stream field to edit, or "attribute:$attributeName" for an attribute.
 *     "input" => The type of the input (@see Q_Html::smartTag())
 *     "attributes" => Additional attributes for the input
 *     "options" => options for the input (if type is "select", "checkboxes" or "radios")
 *     "params" => array of extra parameters to Q_Html::smartTag
 */
function Streams_form_tool($options)
{
    $fields = Q::ifset($options, 'fields', array());
    $defaults = array('publisherId' => null, 'streamName' => null, 'field' => null, 'type' => 'text', 'attributes' => array(), 'value' => array(), 'options' => array(), 'params' => array());
    $sections = array();
    $hidden = array();
    $contents = '';
    foreach ($fields as $id => $field) {
        if (Q::isAssociative($field)) {
            $r = Q::take($field, $defaults);
        } else {
            $c = count($field);
            if ($c < 4) {
                throw new Q_Exception("Streams/form tool: field needs at least 4 values");
            }
            $r = array('publisherId' => $field[0], 'streamName' => $field[1], 'field' => $field[2], 'type' => $field[3], 'attributes' => isset($field[4]) ? $field[4] : array(), 'value' => isset($field[5]) ? $field[5] : '', 'options' => isset($field[6]) ? $field[6] : null, 'params' => isset($field[7]) ? $field[7] : null);
        }
        $r['attributes']['name'] = "input_{$id}";
        if (!isset($r['type'])) {
            var_dump($r['type']);
            exit;
        }
        $stream = Streams::fetchOne(null, $r['publisherId'], $r['streamName']);
        if ($stream) {
            if (substr($r['field'], 0, 10) === 'attribute:') {
                $attribute = trim(substr($r['field'], 10));
                $value = $stream->get($attribute, $r['value']);
            } else {
                $field = $r['field'];
                $value = $stream->{$field};
            }
        } else {
            $value = $r['value'];
        }
        $tag = Q_Html::smartTag($r['type'], $r['attributes'], $value, $r['options'], $r['params']);
        $class1 = 'publisherId_' . Q_Utils::normalize($r['publisherId']);
        $class2 = 'streamName_' . Q_Utils::normalize($r['streamName']);
        $contents .= "<span class='Q_before {$class1} {$class2}'></span>" . Q_Html::tag('span', array('data-publisherId' => $r['publisherId'], 'data-streamName' => $r['streamName'], 'data-field' => $r['field'], 'data-type' => $r['type'], 'class' => "{$class1} {$class2}"), $tag);
        $hidden[$id] = array(!!$stream, $r['publisherId'], $r['streamName'], $r['field']);
    }
    $contents .= Q_Html::hidden(array('inputs' => Q::json_encode($hidden)));
    return Q_Html::form('Streams/form', 'post', array(), $contents);
    //
    // $fields = array('onSubmit', 'onResponse', 'onSuccess', 'slotsToRequest', 'loader', 'contentElements');
    // Q_Response::setToolOptions(Q::take($options, $fields));
    // Q_Response::addScript('plugins/Q/js/tools/form.js');
    // Q_Response::addStylesheet('plugins/Q/css/form.css');
    // return $result;
}
Esempio n. 13
0
/**
 * Removes a label from the system.
 * @param {array} $_REQUEST
 * @param {string} [$_REQUEST.title] Find it by title
 * @param {string} [$_REQUEST.label] Find it by label
 * @param {string} [$_REQUEST.userId=Users::loggedInUser(true)->id] You can override the user id, if another plugin adds a hook that allows you to do this
 */
function Users_label_delete($params = array())
{
    $req = array_merge($_REQUEST, $params);
    $loggedInUserId = Users::loggedInUser(true)->id;
    $userId = Q::ifset($req, 'userId', $loggedInUserId);
    $l = Q::ifset($req, 'label', null);
    if (!$l) {
        if ($title = Q::ifset($req, 'title', null)) {
            $l = 'Users/' . Q_Utils::normalize($title);
        } else {
            throw new Q_Exception_RequiredField(array('field' => 'label'));
        }
    }
    return !!Users_Label::removeLabel($l, $userId);
}
Esempio n. 14
0
function Q_filters_googleClosureCompiler($params)
{
    $content = implode("\n\n", $params['parts']);
    $compilation_level = isset($params['compilation_level']) ? $params['compilation_level'] : 'SIMPLE_OPTIMIZATIONS';
    $service_url = "http://closure-compiler.appspot.com/compile";
    $options = array('js_code' => $content, 'compilation_level' => $compilation_level, 'output_format' => 'text', 'output_info' => 'compiled_code');
    $result = Q_Utils::post($service_url, $options);
    if ($error = substr($result, 0, 5) === 'Error') {
        throw new Q_Exception("Google Closure Compiler:\n" . $result);
    }
    if (!trim($result)) {
        $options['output_info'] = 'errors';
        throw new Q_Exception("Google Closure Compiler:\n" . Q_Utils::post($service_url, $options));
    }
    return $result;
}
Esempio n. 15
0
function Q_after_Q_tool_render($params, &$result)
{
    $info = $params['info'];
    $extra = $params['extra'];
    if (!is_array($extra)) {
        $extra = array();
    }
    $id_prefix = Q_Html::getIdPrefix();
    $tool_ids = Q_Html::getToolIds();
    $tag = Q::ifset($extra, 'tag', 'div');
    if (empty($tag)) {
        Q_Html::popIdPrefix();
        return;
    }
    $classes = '';
    $data_options = '';
    $count = count($info);
    foreach ($info as $name => $opt) {
        $classes = ($classes ? "{$classes} " : $classes) . implode('_', explode('/', $name)) . '_tool';
        $options = Q_Response::getToolOptions($name);
        if (isset($options)) {
            $friendly_options = str_replace(array('&quot;', '\\/'), array('"', '/'), Q_Html::text(Q::json_encode($options)));
        } else {
            $friendly_options = '';
        }
        $normalized = Q_Utils::normalize($name, '-');
        if (isset($options) or $count > 1) {
            $id = $tool_ids[$name];
            $id_string = $count > 1 ? "{$id} " : '';
            $data_options .= " data-{$normalized}='{$id_string}{$friendly_options}'";
        }
        $names[] = $name;
    }
    if (isset($extra['classes'])) {
        $classes .= ' ' . $extra['classes'];
    }
    $attributes = isset($extra['attributes']) ? ' ' . Q_Html::attributes($extra['attributes']) : '';
    $data_retain = !empty($extra['retain']) || Q_Response::shouldRetainTool($id_prefix) ? " data-Q-retain=''" : '';
    $data_replace = !empty($extra['replace']) || Q_Response::shouldReplaceWithTool($id_prefix) ? " data-Q-replace=''" : '';
    $names = $count === 1 ? ' ' . key($info) : 's ' . implode(" ", $names);
    $ajax = Q_Request::isAjax();
    $result = "<{$tag} id='{$id_prefix}tool' " . "class='Q_tool {$classes}'{$data_options}{$data_retain}{$data_replace}{$attributes}>" . "{$result}</{$tag}>";
    if (!Q_Request::isAjax()) {
        $result = "<!--\nbegin tool{$names}\n-->{$result}<!--\nend tool{$names} \n-->";
    }
    Q_Html::popIdPrefix();
}
Esempio n. 16
0
 /**
  * Saves a file, usually sent by the client
  * @method save
  * @static
  * @param {array} $params 
  * @param {string} [$params.data] the file data
  * @param {string} [$params.path="uploads"] parent path under web dir (see subpath)
  * @param {string} [$params.subpath=""] subpath that should follow the path, to save the image under
  * @param {string} [$params.name] override the name of the file, after the subpath
  * @param {string} [$params.skipAccess=false] if true, skips the check for authorization to write files there
  * @param {boolean} [$params.audio] set this to true if the file is an audio file
  * @return {array} Returns array containing ($name => $tailUrl) pair
  */
 static function save($params)
 {
     if (empty($params['data'])) {
         throw new Q_Exception(array('field' => 'file'), 'data');
     }
     // check whether we can write to this path, and create dirs if needed
     $data = $params['data'];
     $audio = $params['audio'];
     $path = isset($params['path']) ? $params['path'] : 'uploads';
     $subpath = isset($params['subpath']) ? $params['subpath'] : '';
     $realPath = Q::realPath(APP_WEB_DIR . DS . $path);
     if ($realPath === false) {
         throw new Q_Exception_MissingFile(array('filename' => APP_WEB_DIR . DS . $path));
     }
     $name = isset($params['name']) ? $params['name'] : 'file';
     if (!preg_match('/^[\\w.-]+$/', $name)) {
         $info = pathinfo($name);
         $name = Q_Utils::normalize($info['filename']) . '.' . $info['extension'];
     }
     // TODO: recognize some extensions maybe
     $writePath = $realPath . ($subpath ? DS . $subpath : '');
     $lastChar = substr($writePath, -1);
     if ($lastChar !== DS and $lastChar !== '/') {
         $writePath .= DS;
     }
     $skipAccess = !empty($params['skipAccess']);
     Q_Utils::canWriteToPath($writePath, $skipAccess ? null : true, true);
     file_put_contents($writePath . $name, $data);
     $size = filesize($writePath . $name);
     $tailUrl = $subpath ? "{$path}/{$subpath}/{$name}" : "{$path}/{$name}";
     /**
      * @event Q/file/save {after}
      * @param {string} user the user
      * @param {string} path the path in the url
      * @param {string} subpath the subpath in the url
      * @param {string} name the actual name of the file
      * @param {string} writePath the actual folder where the path is written
      * @param {string} data the data written to the file
      * @param {string} tailUrl consists of $path/[$subpath/]$name
      * @param {integer} size the size of the file that was written
      * @param {boolean} skipAccess whether we are skipping access checks
      * @param {boolean} audio whether the file is audio
      */
     Q::event('Q/file/save', compact('path', 'subpath', 'name', 'writePath', 'data', 'tailUrl', 'size', 'skipAccess', 'audio'), 'after');
     return array($name => $tailUrl);
 }
Esempio n. 17
0
function Users_device_post()
{
    $user = Users::loggedInUser(true);
    $token = isset($_REQUEST['token']) ? $_REQUEST['token'] : null;
    $platform = Q_Request::platform();
    $version = Q_Request::OSVersion();
    $formFactor = Q_Request::isMobile() ? 'mobile' : (Q_Request::isTablet() ? 'tablet' : null);
    $device = new Users_Device();
    $device->userId = $user->id;
    $device->deviceId = $token;
    $device->platform = $platform;
    $device->version = $version;
    $device->formFactor = $formFactor;
    $device->sessionId = Q_Session::id();
    $_SESSION['Users']['deviceId'] = $token;
    Q_Response::setSlot('data', !!$device->save(true));
    Q_Utils::sendToNode(array("Q/method" => "Users/device", "userId" => $user->id, "deviceId" => $token));
}
Esempio n. 18
0
/**
 * This tool renders ways to get in touch
 *
 * @param array [$options] An associative array of options, containing:
 *   @param {string|Users_User} [$options.user] Required. The user object or id of the user exposing their primary identifiers for getting in touch.
 *   @param {boolean|string} [$options.email] Pass true here to use the primary verified email address, if any. Or pass the string label for this button.
 *   @param {string} [$options.emailSubject] Fill this if you want the email subject to be automatically filled in
 *   @param {string} [$options.emailBody] Fill this if you want the email body to be automatically filled in
 *   @param {boolean|string} [$options.sms] Pass true here to allow texting the primary verified mobile number, if any. Or pass the string label for this button.
 *   @param {boolean|string} [$options.call] Pass true here to allow calling the primary verified mobile number, if any. Or pass the string label for this button.
 *   @param {string} [$options.tag] The type of tag to use, defaults to "button"
 *   @param {string} [$options.class] Any classes to add to the tags
 *   @param {string} [$options.between] Any HTML to put between the elements
 */
function Users_getintouch_tool($options)
{
    $tag = 'button';
    $class = null;
    $between = '';
    $user = null;
    $emailSubject = '';
    $emailBody = '';
    extract($options, EXTR_IF_EXISTS);
    if (!$user) {
        throw new Q_Exception_RequiredField(array('field' => 'user'));
    }
    if (is_string($user)) {
        $userId = $user;
        $user = Users_User::fetch($userId);
        if (!$user) {
            throw new Q_Exception_MissingRow(array('table' => 'user', 'criteria' => "id={$userId}"));
        }
    }
    $ways = array();
    $email = $sms = $call = false;
    if (!empty($options['email']) and $user->emailAddress) {
        $email = is_string($options['email']) ? $options['email'] : "Email me";
        $email = Q_Html::img("plugins/Users/img/email.png") . $email;
        $ways['email'] = Q_Html::tag($tag, array('id' => 'email', 'class' => $class), $email);
        Q_Response::setToolOptions(array('emailAddress' => Q_Utils::obfuscate($user->emailAddress), 'emailSubject' => Q_Utils::obfuscate($emailSubject), 'emailBody' => Q_Utils::obfuscate($emailBody)));
    }
    if (Q_Request::isMobile()) {
        $obfuscated_mobileNumber = Q_Utils::obfuscate($user->mobileNumber);
        if (!empty($options['sms']) and $user->mobileNumber) {
            $sms = is_string($options['sms']) ? $options['sms'] : "Text me";
            $sms = Q_Html::img("plugins/Users/img/sms.png") . $sms;
            $ways['sms'] = Q_Html::tag($tag, array('id' => 'sms', 'class' => $class), $sms);
            Q_Response::setToolOptions(array('mobileNumber' => $obfuscated_mobileNumber));
        }
        if (!empty($options['call']) and $user->mobileNumber) {
            $call = is_string($options['call']) ? $options['call'] : "Call me";
            $call = Q_Html::img("plugins/Users/img/call.png") . $call;
            $ways['call'] = Q_Html::tag($tag, array('id' => 'call', 'class' => $class), $call);
            Q_Response::setToolOptions(array('mobileNumber' => $obfuscated_mobileNumber));
        }
    }
    return implode($between, $ways);
}
Esempio n. 19
0
function Streams_0_8_1_Streams_mysql()
{
    $app = Q_Config::expect('Q', 'app');
    // template for community stream
    $stream = new Streams_Stream();
    $stream->publisherId = '';
    $stream->name = 'Streams/community/';
    $stream->type = 'Streams/template';
    $stream->title = "Community";
    $stream->content = '';
    $readLevel = Streams::$READ_LEVEL['content'];
    $writeLevel = Streams::$WRITE_LEVEL['join'];
    $adminLevel = Streams::$ADMIN_LEVEL['invite'];
    $stream->save();
    // app community stream, for announcements
    Streams::create($app, $app, 'Streams/community', array('skipAccess' => true, 'name' => 'Streams/community/main', 'title' => "{$app} Community"));
    // symlink the labels folder
    if (!file_exists('Streams')) {
        Q_Utils::symlink(STREAMS_PLUGIN_FILES_DIR . DS . 'Streams' . DS . 'icons' . DS . 'labels' . DS . 'Streams', USERS_PLUGIN_FILES_DIR . DS . 'Users' . DS . 'icons' . DS . 'Streams');
    }
}
Esempio n. 20
0
 /**
  * Saves a file, usually sent by the client
  * @method save
  * @static
  * @param {array} $params 
  * @param {string} [$params.data] the file data
  * @param {string} [$params.path="uploads"] parent path under web dir (see subpath)
  * @param {string} [$params.subpath=""] subpath that should follow the path, to save the image under
  * @param {string} [$params.name] override the name of the file, after the subpath
  * @param {string} [$params.skipAccess=false] if true, skips the check for authorization to write files there
  * @return {array} Returns array containing ($name => $tailUrl) pair
  */
 static function save($params)
 {
     if (empty($params['data'])) {
         throw new Q_Exception(array('field' => 'file'), 'data');
     }
     // check whether we can write to this path, and create dirs if needed
     $data = $params['data'];
     $path = isset($params['path']) ? $params['path'] : 'uploads';
     $subpath = isset($params['subpath']) ? $params['subpath'] : '';
     $realPath = Q::realPath(APP_WEB_DIR . DS . $path);
     if ($realPath === false) {
         throw new Q_Exception_MissingFile(array('filename' => APP_WEB_DIR . DS . $path));
     }
     $name = isset($params['name']) ? $params['name'] : 'file';
     if (!preg_match('/^[\\w.-]+$/', $name)) {
         $info = pathinfo($name);
         $name = Q_Utils::normalize($info['filename']) . '.' . $info['extension'];
     }
     // TODO: recognize some extensions maybe
     $writePath = $realPath . ($subpath ? DS . $subpath : '');
     $lastChar = substr($writePath, -1);
     if ($lastChar !== DS and $lastChar !== '/') {
         $writePath .= DS;
     }
     $throwIfNotWritable = empty($params['skipAccess']) ? true : null;
     Q_Utils::canWriteToPath($writePath, $throwIfNotWritable, true);
     file_put_contents($writePath . DS . $name, $data);
     $tailUrl = $subpath ? "{$path}/{$subpath}/{$name}" : "{$path}/{$name}";
     /**
      * @event Q/file/save {after}
      * @param {string} user
      * @param {string} path
      * @param {string} subpath
      * @param {string} name
      * @param {string} writePath
      * @param {string} data
      */
     Q::event('Q/file/save', compact('path', 'subpath', 'name', 'writePath', 'data', 'tailUrl'), 'after');
     return array($name => $tailUrl);
 }
Esempio n. 21
0
function Users_after_Q_session_write($params)
{
    Q::$state['session'] = true;
    if (!$params['changed']) {
        return;
    }
    // Q::autoload('Db');
    // Q::autoload('Db_Mysql');
    // Q::autoload('Db_Result');
    // Q::autoload('Db_Expression');
    // Q::autoload('Db_Query');
    // Q::autoload('Db_Query_Mysql');
    // Q::autoload('Db_Row');
    // Q::autoload('Base_Users_Session');
    // Q::autoload('Base_Users');
    // Q::autoload('Users');
    Q::autoload('Q_Utils');
    Q::autoload('Q_Config');
    Q::autoload('Q_Session');
    $id = Q_Session::id();
    if (!$id) {
        return;
    }
    $parts = explode('-', $id);
    $duration = count($parts) > 1 ? $parts[0] : 0;
    $content = Q::json_encode($_SESSION, JSON_FORCE_OBJECT);
    if (Users::$loggedOut) {
        Q_Utils::sendToNode(array("Q/method" => "Users/session", "sessionId" => $id, "content" => null, "duration" => $duration));
    } else {
        if (Q_Session::id() and !empty($_SERVER['HTTP_HOST'])) {
            try {
                Q_Utils::sendToNode(array("Q/method" => "Users/session", "sessionId" => $id, "content" => $content, "duration" => $duration));
            } catch (Exception $e) {
                // don't throw here, it would only result in a mysterious fatal error
            }
        }
    }
}
Esempio n. 22
0
function Users_after_Q_image_save($params, &$return)
{
    extract($params);
    /**
     * @var string $path
     * @var string $subpath
     * @var Users_User $user
     */
    $user = Users::loggedInUser(true);
    $fullpath = $path . ($subpath ? DS . $subpath : '');
    $splitId = Q_Utils::splitId($user->id);
    $prefix = "uploads/Users/{$splitId}/icon";
    if (substr($fullpath, 0, strlen($prefix)) === $prefix) {
        if ($user->icon != $subpath) {
            $user->icon = Q_Html::themedUrl("{$path}/{$subpath}");
            $user->save();
            // triggers any registered hooks
            Users::$cache['iconUrlWasChanged'] = true;
        } else {
            Users::$cache['iconUrlWasChanged'] = false;
        }
    }
}
Esempio n. 23
0
function Users_after_Q_session_destroy($params)
{
    Q::$state['session'] = true;
    //  Q::autoload('Db');
    //  Q::autoload('Db_Mysql');
    //  Q::autoload('Db_Result');
    //  Q::autoload('Db_Expression');
    //  Q::autoload('Db_Query');
    //  Q::autoload('Db_Query_Mysql');
    //  Q::autoload('Db_Row');
    //  Q::autoload('Base_Users_Session');
    //  Q::autoload('Base_Users');
    //  Q::autoload('Users');
    Q::autoload('Q_Utils');
    Q::autoload('Q_Config');
    Q::autoload('Q_Session');
    $id = Q_Session::id();
    if (!$id) {
        return;
    }
    $content = Q::json_encode($_SESSION, JSON_FORCE_OBJECT);
    Q_Utils::sendToNode(array("Q/method" => "Users/session", "sessionId" => $id, "content" => null, "updatedTime" => null, "destroyed" => true));
}
Esempio n. 24
0
 /**
  * Return colored text that you can output in logs or text mode
  * Pass an exception or 
  * @param {string|Exception} $exception The exception or an exception message. If the later, you must pass three more arguments.
  * @param {string} [$file]
  * @param {string} [$line]
  * @param {string} [$trace]
  * @return {string}
  */
 static function coloredString($message, $file = null, $line = null, $trace = null)
 {
     if ($message instanceof Exception) {
         $e = $message;
         $traceString = is_callable(array($e, 'getTraceAsStringEx')) ? $e->getTraceAsStringEx() : $e->getTraceAsString();
         return self::coloredString($e->getMessage(), $e->getFile(), $e->getLine(), $traceString);
     }
     $colors = Q_Config::get('Q', 'exception', 'colors', array());
     Q::autoload('Q_Utils');
     $fields = array('message' => $message, 'fileAndLine' => "in {$file} ({$line})", 'trace' => $trace);
     foreach ($fields as $f => $v) {
         $c0 = isset($colors[$f][0]) ? $colors[$f][0] : null;
         $c1 = isset($colors[$f][1]) ? $colors[$f][1] : null;
         $fields[$f] = Q_Utils::colored($v, $c0, $c1);
     }
     $reset = Q_Utils::colored("", "", "");
     return "{$fields['message']}\n\n{$fields['fileAndLine']}\n{$fields['trace']}\n";
 }
Esempio n. 25
0
 function resendActivationMessage($subject = null, $view = null, $fields = array(), $options = array())
 {
     if (!isset($subject)) {
         $subject = Q_Config::get('Users', 'transactional', 'resend', 'subject', Q_Config::get('Users', 'transactional', 'activation', 'subject', 'Did you forget your passphrase?'));
     }
     if (!isset($view)) {
         $view = Q_Config::get('Users', 'transactional', 'resend', 'body', Q_Config::get('Users', 'transactional', 'activation', 'body', 'Users/email/activation.php'));
     }
     if (!isset($options['html'])) {
         $options['html'] = true;
     }
     $user = $this->get('user', null);
     if (!$user) {
         $user = new Users_User();
         $user->id = $this->userId;
         if (!$user->retrieve()) {
             throw new Q_Exception_NotVerified(array('type' => 'email address'), 'emailAddress');
         }
     }
     $minutes = Q_Config::get('Users', 'activation', 'expires', 60 * 24 * 7);
     $this->activationCode = strtolower(Q_Utils::unique(7));
     $this->activationCodeExpires = new Db_Expression("CURRENT_TIMESTAMP + INTERVAL {$minutes} MINUTE");
     $this->authCode = md5(microtime() + mt_rand());
     $link = 'Users/activate?p=1&code=' . urlencode($this->activationCode) . ' emailAddress=' . urlencode($this->address);
     /**
      * @event Users/resend {before}
      * @param {string} user
      * @param {string} email
      */
     Q::event('Users/resend', compact('user', 'email', 'link'), 'before');
     $this->save();
     $email = $this;
     $fields2 = array_merge($fields, array('user' => $user, 'email' => $this, 'app' => Q_Config::expect('Q', 'app'), 'baseUrl' => Q_Request::baseUrl(), 'link' => $link));
     $this->sendMessage($subject, $view, $fields2, $options);
     // may throw exception if badly configured
     /**
      * @event Users/resend {after}
      * @param {string} user
      * @param {string} email
      */
     Q::event('Users/resend', compact('user', 'email'), 'after');
 }
Esempio n. 26
0
 /**
  * @method links
  * @static
  * @param {array} $contact_info An array of key => value pairs, where keys can be:
  *
  * * "email" => the user's email address
  * * "mobile" => the user's mobile number
  * * "email_hashed" => the standard hash of the user's email address
  * * "mobile_hashed" => the standard hash of the user's mobile number
  * * "facebook" => the user's facebook uid
  * * "twitter" => the user's twitter uid
  *
  * @return {array}
  *  Returns an array of all links to this user's contact info
  */
 static function links($contact_info)
 {
     $links = array();
     $identifiers = array();
     if (!empty($contact_info['email'])) {
         Q_Valid::email($contact_info['email'], $emailAddress);
         $identifiers[] = "email_hashed:" . Q_Utils::hash($emailAddress);
     }
     if (!empty($contact_info['mobile'])) {
         Q_Valid::phone($contact_info['mobile'], $mobileNumber);
         $identifiers[] = "mobile_hashed:" . Q_Utils::hash($mobileNumber);
     }
     if (!empty($contact_info['email_hashed'])) {
         $identifiers[] = "email_hashed" . $contact_info['email_hashed'];
     }
     if (!empty($contact_info['mobile_hashed'])) {
         $identifiers[] = "mobile_hashed:" . $contact_info['mobile_hashed'];
     }
     if (!empty($contact_info['facebook'])) {
         $identifiers[] = "facebook:" . $contact_info['facebook'];
     }
     if (!empty($contact_info['twitter'])) {
         $identifiers[] = "twitter:" . $contact_info['twitter'];
     }
     return Users_Link::select('*')->where(array('identifier' => $identifiers))->fetchDbRows();
 }
function Users_before_Q_Utils_canWriteToPath($params, &$result)
{
    extract($params);
    /**
     * @var $path
     * @var $throwIfNotWritable
     * @var $mkdirIfMissing
     */
    // The Users plugin requires that a user be logged in before uploading a file,
    // and only in the proper directories.
    $user = Users::loggedInUser($throwIfNotWritable);
    if (!$user) {
        return false;
    }
    $app = Q_Config::expect('Q', 'app');
    $subpaths = Q_Config::get('Users', 'paths', 'uploads', array('files/{{app}}/uploads/Users/{{userId}}' => true));
    $paths = array();
    $path = str_replace(array("/", "\\"), DS, $path);
    foreach ($subpaths as $subpath => $can_write) {
        if (!$can_write) {
            continue;
        }
        $subpath = Q::interpolate($subpath, array('userId' => Q_Utils::splitId($user->id), 'app' => $app));
        if ($subpath and ($subpath[0] !== '/' or $subpath[0] !== DS)) {
            $subpath = DS . $subpath;
        }
        $last_char = substr($subpath, -1);
        if ($subpath and $last_char !== '/' and $last_char !== DS) {
            $subpath .= DS;
        }
        $paths[] = APP_DIR . $subpath;
        foreach (Q_Config::get('Q', 'plugins', array()) as $plugin) {
            $c = strtoupper($plugin) . '_PLUGIN_DIR';
            if (defined($c)) {
                $paths[] = constant($c) . $subpath;
            }
        }
        $paths[] = Q_DIR . $subpath;
    }
    if (strpos($path, "../") === false and strpos($path, ".." . DS) === false) {
        foreach ($paths as $p) {
            $p = str_replace(array("/", "\\"), DS, $p);
            $len = strlen($p);
            if (strncmp($path, $p, $len) === 0) {
                // we can write to this path
                if ($mkdirIfMissing and !file_exists($path)) {
                    $mode = is_integer($mkdirIfMissing) ? $mkdirIfMissing : 0777;
                    $mask = umask(Q_Config::get('Q', 'internal', 'umask', 00));
                    if (!@mkdir($path, $mode, true)) {
                        throw new Q_Exception_FilePermissions(array('action' => 'create', 'filename' => $path, 'recommendation' => ' Please set your files directory to be writable.'));
                    }
                    umask($mask);
                    $dir3 = $path;
                    do {
                        chmod($dir3, $mode);
                        $dir3 = dirname($dir3);
                    } while ($dir3 and $dir3 != $p and $dir3 . DS != $p);
                }
                $result = true;
                return;
            }
        }
    }
    if ($throwIfNotWritable) {
        throw new Q_Exception_CantWriteToPath();
    }
    $result = false;
}
Esempio n. 28
0
 /**
  * Unsubcsribe from all or specific stream's messages
  * @method unsubscribe
  * @param $options=array() {array}
  *  "userId": The user who is unsubscribing from the stream. Defaults to the logged-in user.
  *  "skipAccess": if true, skip access check for whether user can unsubscribe
  * @return {boolean}
  */
 function unsubscribe($options = array())
 {
     $stream = $this->fetchAsUser($options, $userId);
     if (empty($options['skipAccess']) and !$stream->testReadLevel('messages')) {
         if (!$stream->testReadLevel('see')) {
             throw new Streams_Exception_NoSuchStream();
         }
         throw new Users_Exception_NotAuthorized();
     }
     $participant = $stream->join(array("userId" => $userId, 'subscribed' => false, 'noVisit' => true, "skipAccess" => Q::ifset($options, 'skipAccess', false)));
     Q_Utils::sendToNode(array("Q/method" => "Streams/Stream/unsubscribe", "stream" => Q::json_encode($stream->toArray()), "participant" => Q::json_encode($participant), "success" => Q::json_encode(!!$participant)));
     // Post Streams/unsubscribe message to the stream
     $stream->post($userId, array('type' => 'Streams/unsubscribe'), true);
     // Now post Streams/unsubscribed message to Streams/participating
     Streams_Message::post($userId, $userId, 'Streams/participating', array('type' => 'Streams/unsubscribed', 'instructions' => Q::json_encode(array('publisherId' => $stream->publisherId, 'streamName' => $stream->name))), true);
     return !!$participant;
 }
Esempio n. 29
0
 /**
  * Sends asynchronous internal message to Node.js
  *  If "Q.clientId" is in $_REQUEST, adds it into the data
  * @method sendToNode
  * @static
  * @param {array} $data Associative array of data of the message to send.
  *  It should contain the key "Q/method" so Node can decide what to do with the message.
  * @param {string|array} [$url=null] and url to query. Default to 'Q/nodeInternal' config value and path '/Q/node'
  * @param {boolean} [$throwIfRefused=false] Pass true here to throw an exception whenever Node process is not running or refuses the request
  */
 static function sendToNode($data, $url = null, $throwIfRefused = false)
 {
     if (!is_array($data)) {
         throw new Q_Exception_WrongType(array('field' => 'data', 'type' => 'array'));
     }
     if (empty($data['Q/method'])) {
         throw new Q_Exception_RequiredField(array('field' => 'Q/method'));
     }
     $ssid = Q_Request::special('clientId', null);
     if (isset($ssid)) {
         $data['Q.clientId'] = $ssid;
     }
     // The following hook may modify the url
     /**
      * @event Q/Utils/sendToNode {before}
      * @param {array} data
      * @param {string|array} 'url'
      */
     Q::event('Q/Utils/sendToNode', array('data' => $data, 'url' => $url), 'before');
     if (!$url) {
         $nodeh = Q_Config::get('Q', 'nodeInternal', 'host', null);
         $nodep = Q_Config::get('Q', 'nodeInternal', 'port', null);
         $url = $nodep && $nodeh ? "http://{$nodeh}:{$nodep}/Q/node" : false;
     }
     if (!$url) {
         $result = false;
     } else {
         // Should we switch to sending JSON over TCP?
         $result = Q_Utils::postAsync($url, self::sign($data), null, Q_UTILS_INTERNAL_TIMEOUT, $throwIfRefused);
     }
     return $result;
     //		if (!$result) {
     //			throw new Q_Exception_SendingToNode(array('method' => $data['Q/method']));
     //		}
 }
Esempio n. 30
0
/**
 * 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');
}