function Streams_after_Q_objects() { $user = Users::loggedInUser(); if (!$user) { return; } $invite = Streams::$followedInvite; if (!$invite) { return; } $displayName = $user->displayName(); if ($displayName) { return; } $stream = new Streams_Stream(); $stream->publisherId = $invite->publisherId; $stream->name = $invite->streamName; if (!$stream->retrieve()) { throw new Q_Exception_MissingRow(array('table' => 'stream', 'criteria' => 'with that name'), 'streamName'); } // Prepare the complete invite dialog $invitingUser = Users_User::fetch($invite->invitingUserId); list($relations, $related) = Streams::related($user->id, $stream->publisherId, $stream->name, false); $params = array('displayName' => null, 'action' => 'Streams/basic', 'icon' => $user->iconUrl(), 'token' => $invite->token, 'user' => array('icon' => $invitingUser->iconUrl(), 'displayName' => $invitingUser->displayName(array('fullAccess' => true))), 'stream' => $stream->exportArray(), 'relations' => Db::exportArray($relations), 'related' => Db::exportArray($related)); $config = Streams_Stream::getConfigField($stream->type, 'invite', array()); $defaults = Q::ifset($config, 'dialog', array()); $tree = new Q_Tree($defaults); if ($tree->merge($params)) { $dialogData = $tree->getAll(); if ($dialogData) { Q_Response::setScriptData('Q.plugins.Streams.invite.dialog', $dialogData); Q_Response::addTemplate('Streams/invite/complete'); } } }
/** * Loads the configuration and plugins in the right order * @method configure * @static * @param boolean [$force_reload=false] If true, forces the reload of the cache. * Otherwise it happens only if Q/configServer/interval seconds * have passed since the last time. * @throws {Q_Exception_MissingPlugin} */ static function configure($force_reload = false) { $app_tree = new Q_Tree(); // check if config need to be reloaded if (Q_Cache::connected()) { // we need to know reload interval $app_tree->load('config/Q.json'); $app_tree->load('config/app.json'); $app_tree->load('local/app.json'); $config_files = $app_tree->get('Q', 'configFiles', array()); foreach ($config_files as $cf) { $app_tree->merge(Q_Config::getFromServer($cf)); } // second round to catch configFiles inside configFiles $config_files = $app_tree->get('Q', 'configFiles', array()); foreach ($config_files as $cf) { $app_tree->merge(Q_Config::getFromServer($cf)); } $interval = $app_tree->get('Q', 'configServer', 'interval', 60); // reload each minute by default $app_tree->clear(null); $timestamp = Q_Cache::get("Q_Config\tupdate_time"); if (!isset($timestamp) || time() - $timestamp > $interval) { $force_reload = true; } } if ($force_reload) { $old_setting = Q_Cache::ignore(true); } Q_Config::clear(null); // clear the config Q_Config::load('config/Q.json'); // Get the app config, but don't load it yet $app_tree->load('config/app.json'); $app_tree->load('local/app.json'); // Load all the plugin config files first $paths = explode(PS, get_include_path()); $plugins = $app_tree->get('Q', 'plugins', array()); if (!in_array('Q', $plugins)) { array_unshift($plugins, 'Q'); } global $Q_Bootstrap_config_plugin_limit; $i = 0; foreach ($plugins as $k => $v) { ++$i; if (isset($Q_Bootstrap_config_plugin_limit) and $i > $Q_Bootstrap_config_plugin_limit) { continue; } $plugin = is_numeric($k) ? $v : $k; $plugin_path = Q::realPath('plugins' . DS . $v); if (!$plugin_path) { throw new Q_Exception_MissingPlugin(compact('plugin')); } Q_Config::load($plugin_path . DS . 'config' . DS . 'plugin.json'); array_splice($paths, 1, 0, array($plugin_path)); $PLUGIN = strtoupper($plugin); if (!defined($PLUGIN . '_PLUGIN_DIR')) { define($PLUGIN . '_PLUGIN_DIR', $plugin_path); } if (!defined($PLUGIN . '_PLUGIN_CONFIG_DIR')) { define($PLUGIN . '_PLUGIN_CONFIG_DIR', $plugin_path . DS . 'config'); } if (!defined($PLUGIN . '_PLUGIN_CLASSES_DIR')) { define($PLUGIN . '_PLUGIN_CLASSES_DIR', $plugin_path . DS . 'classes'); } if (!defined($PLUGIN . '_PLUGIN_FILES_DIR')) { define($PLUGIN . '_PLUGIN_FILES_DIR', $plugin_path . DS . 'files'); } if (!defined($PLUGIN . '_PLUGIN_HANDLERS_DIR')) { define($PLUGIN . '_PLUGIN_HANDLERS_DIR', $plugin_path . DS . 'handlers'); } if (!defined($PLUGIN . '_PLUGIN_PLUGINS_DIR')) { define($PLUGIN . '_PLUGIN_PLUGINS_DIR', $plugin_path . DS . 'plugins'); } if (!defined($PLUGIN . '_PLUGIN_SCRIPTS_DIR')) { define($PLUGIN . '_PLUGIN_SCRIPTS_DIR', $plugin_path . DS . 'scripts'); } if (!defined($PLUGIN . '_PLUGIN_VIEWS_DIR')) { define($PLUGIN . '_PLUGIN_VIEWS_DIR', $plugin_path . DS . 'views'); } if (!defined($PLUGIN . '_PLUGIN_TESTS_DIR')) { define($PLUGIN . '_PLUGIN_TESTS_DIR', $plugin_path . DS . 'tests'); } if (!defined($PLUGIN . '_PLUGIN_WEB_DIR')) { define($PLUGIN . '_PLUGIN_WEB_DIR', $plugin_path . DS . 'web'); } self::$plugins[$plugin] = $plugin_path; } $paths = array_unique($paths); set_include_path(implode(PS, $paths)); // Now, we can merge in our app's config Q_Config::merge($app_tree); // Now, load any other files we were supposed to load $config_files = Q_Config::get('Q', 'configFiles', array()); foreach ($config_files as $cf) { Q_Config::merge(Q_Config::getFromServer($cf)); } // second round to catch configFiles inside configFiles $config_files = Q_Config::get('Q', 'configFiles', array()); foreach ($config_files as $cf) { Q_Config::merge(Q_Config::getFromServer($cf)); } $script_files = Q_Config::get('Q', 'scriptFiles', array()); foreach ($script_files as $cf) { Q::includeFile($cf); } error_reporting(Q_Config::get('Q', 'errorReporting', E_ALL)); if (isset($old_setting)) { Q_Cache::ignore($old_setting); } set_time_limit(Q_Config::get('Q', 'internal', 'phpTimeout', 30)); self::setDefaultTimezone(); }
/** * Modify a config file by merging over new data * Config file is searched in APP_DIR/files forder. If config server url is defined * the filename is searched on config server * @method setOnServer * @static * @param {string} $filename The name of the config file. If config server is defined, file is changed there * @param {array} $data The data to merge to the file * @param {boolean} [$clear=false] Weather data shall be merged over or cleared and set * @return {boolean} Wheather data was successfuly merged in */ static function setOnServer($filename, $data, $clear = false) { if (!is_array($data)) { throw new Q_Exception_WrongType(array('field' => 'data', 'type' => 'array')); } if (is_string($clear)) { $clear = json_decode($clear); } if ($cs = self::serverInfo()) { // request config server if (!empty($cs['url'])) { if (!empty($cs['internal'])) { // query "internal" Qbix server return Q_Utils::queryInternal('Q/Config', array('Q/method' => 'set', 'filename' => $filename, 'data' => $data, 'clear' => $clear), $cs['url']); } else { // query "external" Qbix server return Q_Utils::queryExternal('Q/Config', array('Q/method' => 'set', 'filename' => $filename, 'data' => $data, 'clear' => $clear), $cs['url']); } } } // save local file, return empty tree if file does not exists $tree = new Q_Tree(); if (defined('APP_DIR')) { $filename = APP_DIR . DS . 'files' . DS . $filename; } else { throw new Q_Exception("'APP_DIR' is not defined"); } if (!file_exists($filename)) { $dir = dirname(str_replace('/', DS, $filename)); if (!is_dir($dir)) { $mask = umask(Q_Config::get('Q', 'internal', 'umask', 00)); if (!mkdir($dir, 0777, true)) { return false; } umask($mask); } elseif (!is_writable($dir)) { return false; } } elseif (!$clear) { $tree->load($filename); } $tree->merge($data); return $tree->save($filename); }
/** * @method writeHandler * @static * @param {string} $id * @param {string} $sess_data * @return {boolean} */ static function writeHandler($id, $sess_data) { try { // if the request is AJAX request that came without session cookie, then do not write session, ignore it if (Q_Request::isAjax() && !isset($_COOKIE[self::name()])) { return false; } // don't save sessions when running from command-line (cli) if (php_sapi_name() == 'cli') { return false; } $our_SESSION = $_SESSION; $old_data = self::$sess_data; $changed = $sess_data !== $old_data; $result = false; /** * @event Q/session/write {before} * @param {string} id * @param {string} sess_data * @param {string} old_data * @param {boolean} changed * @return {boolean} */ if (false === Q::event('Q/session/write', compact('id', 'sess_data', 'old_data', 'changed'), 'before')) { return false; } if (empty(self::$session_save_path)) { self::$session_save_path = self::savePath(); } if (!empty(self::$session_db_connection)) { // Create a new row to be saved in the session table $db_row_class = self::$session_db_row_class; // Make sure it has a primary key! if (count(self::$session_db_row->getPrimaryKey()) != 1) { throw new Q_Exception("The primary key of " . self::$session_db_row_class . " has to consist of exactly 1 field!"); } $id_field = self::$session_db_id_field; $data_field = self::$session_db_data_field; $updated_field = self::$session_db_updated_field; $duration_field = self::$session_db_duration_field; $row = self::$session_db_row; $row->{$id_field} = $id; } else { $duration_name = self::durationName(); $id1 = substr($id, 0, 4); $id2 = substr($id, 4); $ssp = self::$session_save_path; $sess_file = $ssp . DS . "{$duration_name}/{$id1}/{$id2}"; $dir = $ssp . DS . "{$duration_name}/{$id1}/"; } if ($changed) { // Apparently, we want to save some changes. // The convention to avoid locking is that everything // stored in sessions must be mergeable using the // Q_Tree merge algorithm. // So we will retrieve the latest session data again, // merge our changes over it, and save. $params = array('id_field' => $id_field, 'data_field' => $data_field, 'updated_field' => $updated_field, 'duration_field' => $duration_field, 'changed' => $changed, 'sess_data' => $sess_data, 'old_data' => $old_data); if (!empty(self::$session_db_connection)) { $row->retrieve(); $existing_data = Q::ifset($row, $data_field, ""); $params['row'] = $row; } else { if (!is_dir($dir)) { mkdir($dir, fileperms($ssp), true); } if (!is_writable($dir)) { // alert the developer to this problem Q::log("{$sess_file} is not writable", 'fatal'); die("{$sess_file} is not writable"); } $file = fopen($sess_file, "w"); if (!$file) { return false; } $params['row'] = $row; $maxlength = Q_Config::get('Q', 'session', 'maxlength', 4095); $existing_data = fread($file, $maxlength); } $_SESSION = session_decode($existing_data); if (!$_SESSION) { $_SESSION = array(); } $t = new Q_Tree($_SESSION); $t->merge($our_SESSION); $_SESSION = $t->getAll(); $params['existing_data'] = $existing_data; $params['merged_data'] = $merged_data = session_encode(); /** * @event Q/session/save {before} * @param {string} sess_data * @param {string} old_data * @param {string} existing_data * @param {string} merged_data * @param {boolean} changed * @param {Db_Row} row * @return {boolean} */ if (false === Q::event('Q/session/save', $params, 'before')) { return false; } if (!empty(self::$session_db_connection)) { $row->{$data_field} = $merged_data; $row->{$duration_field} = Q_Config::get('Q', 'session', 'durations', Q_Request::formFactor(), Q_Config::expect('Q', 'session', 'durations', 'session')); $row->save(); $result = true; } else { $result = fwrite($file, $merged_data); fclose($file); } } /** * @event Q/session/write {after} * @param {string} id * @param {boolean} changed * @param {string} sess_data * @param {string} old_data * @param {string} existing_data * @param {string} merged_data * @param {string} data_field * @param {string} updated_field * @param {string} duration_field * @param {string} sess_file * @param {integer} row * @return {mixed} */ $result = Q::event('Q/session/write', compact('id', 'data_field', 'updated_field', 'duration_field', 'sess_file', 'row', 'changed', 'sess_data', 'old_data', 'existing_data', 'merged_data'), 'after'); return $result; } catch (Exception $e) { Q::log("Exception when writing session {$id}: " . $e->getMessage()); throw $e; } }