Get the plugin manager for the application.
public static pluginManager ( ) : Gdn_PluginManager | ||
Результат | Gdn_PluginManager |
/** * Find available social plugins. * * @return array|mixed * @throws Exception */ protected function getConnections() { $this->fireEvent('GetConnections'); $connections = []; $addons = Gdn::addonManager()->lookupAllByType(\Vanilla\Addon::TYPE_ADDON); foreach ($addons as $addonName => $addon) { $addonInfo = $addon->getInfo(); // Limit to designated social addons. if (!array_key_exists('socialConnect', $addonInfo)) { continue; } // See if addon is enabled. $isEnabled = Gdn::addonManager()->isEnabled($addonName, \Vanilla\Addon::TYPE_ADDON); setValue('enabled', $addonInfo, $isEnabled); // See if we can detect whether connection is configured. $isConfigured = null; if ($isEnabled) { $pluginInstance = Gdn::pluginManager()->getPluginInstance($addonName, Gdn_PluginManager::ACCESS_PLUGINNAME); if (method_exists($pluginInstance, 'isConfigured')) { $isConfigured = $pluginInstance->isConfigured(); } } setValue('configured', $addonInfo, $isConfigured); // Add the connection. $connections[$addonName] = $addonInfo; } return $connections; }
/** * Override the default dashboard page with the new stats one. */ public function gdn_dispatcher_beforeDispatch_handler($Sender) { $Enabled = c('Garden.Analytics.Enabled', true); if ($Enabled && !Gdn::pluginManager()->hasNewMethod('SettingsController', 'Index')) { Gdn::pluginManager()->registerNewMethod('VanillaStatsPlugin', 'StatsDashboard', 'SettingsController', 'Index'); } }
/** * Is the application/plugin/theme removable? * * @param string $Type self::TYPE_APPLICATION or self::TYPE_PLUGIN or self::TYPE_THEME * @param string $Name * @return boolean */ public static function isRemovable($Type, $Name) { switch ($Type) { case self::TYPE_APPLICATION: $ApplicationManager = Gdn::Factory('ApplicationManager'); if ($IsRemovable = !array_key_exists($Name, $ApplicationManager->EnabledApplications())) { $ApplicationInfo = arrayValue($Name, $ApplicationManager->AvailableApplications(), array()); $ApplicationFolder = arrayValue('Folder', $ApplicationInfo, ''); $IsRemovable = IsWritable(PATH_APPLICATIONS . DS . $ApplicationFolder); } break; case self::TYPE_PLUGIN: if ($IsRemovable = !array_key_exists($Name, Gdn::pluginManager()->EnabledPlugins())) { $PluginInfo = arrayValue($Name, Gdn::pluginManager()->AvailablePlugins(), false); $PluginFolder = arrayValue('Folder', $PluginInfo, false); $IsRemovable = IsWritable(PATH_PLUGINS . DS . $PluginFolder); } break; case self::TYPE_THEME: // TODO $IsRemovable = false; break; } return $IsRemovable; }
/** * Reload the locale system. */ public function refresh() { $LocalName = $this->current(); $ApplicationWhiteList = Gdn::applicationManager()->enabledApplicationFolders(); $PluginWhiteList = Gdn::pluginManager()->enabledPluginFolders(); $ForceRemapping = true; $this->set($LocalName, $ApplicationWhiteList, $PluginWhiteList, $ForceRemapping); }
/** * Remove plugins that are not mobile friendly! */ public function gdn_dispatcher_afterAnalyzeRequest_handler($Sender) { // Remove plugins so they don't mess up layout or functionality. $inPublicDashboard = $Sender->application() == 'dashboard' && in_array($Sender->controller(), array('Activity', 'Profile', 'Search')); if (in_array($Sender->application(), array('vanilla', 'conversations')) || $inPublicDashboard) { Gdn::pluginManager()->removeMobileUnfriendlyPlugins(); } saveToConfig('Garden.Format.EmbedSize', '240x135', false); }
/** * Looks through the themes directory for valid themes. * * The themes are returned as an associative array of "Theme Name" => "Theme Info Array". * * @param bool $force Deprecated. * @return array Returns the available themes in an array. */ public function availableThemes($force = false) { $addons = $this->addonManager->lookupAllByType(Addon::TYPE_THEME); $result = []; /* @var Addon $addon */ foreach ($addons as $addon) { $result[$addon->getRawKey()] = Gdn::pluginManager()->calcOldInfoArray($addon); } return $result; }
/** * Fires an event for initializing static members in the calling class. * * @return bool Whether the event was fired. * @throws Exception */ public static function initStatic() { if (!self::$initStaticFired) { self::$initStaticFired = true; Gdn::pluginManager()->fireAs(get_called_class()); Gdn::pluginManager()->fireEvent('InitStatic'); return true; } return false; }
/** * Remove mobile rendering from our custom non-forum pages. * * @param $sender */ public function base_render_before($sender) { $userFacing = $sender->MasterView == 'default' || $sender->MasterView == ''; $onForumPage = !in_array(strtolower($sender->Application), array('vanilla', 'conversations', 'dashboard')); if ($userFacing && isMobile() && $onForumPage) { // Use the main theme instead of mobile $sender->Theme = c('Garden.Theme'); Gdn::pluginManager()->unregisterPlugin('MobileThemeHooks'); } }
public function gdn_dispatcher_afterAnalyzeRequest_handler($sender) { $inPublicDashboard = in_array($sender->controller(), array('Activity', 'Profile', 'Search')); if (in_array($sender->application(), array('vanilla', 'conversations')) || $inPublicDashboard) { Gdn::pluginManager()->removeMobileUnfriendlyPlugins(); } saveToConfig('Garden.Format.EmbedSize', '240x135', false); saveToConfig('Vanilla.AdminCheckboxes.Use', false, false); //the table discussions layout takes up too much space on small screens saveToConfig('Vanilla.Discussions.Layout', 'modern', false); }
/** * * * @since 2.0.18 * @access public * @return array Category IDs. */ public static function categoryWatch($AllDiscussions = true) { $Categories = self::categories(); $AllCount = count($Categories); $Watch = array(); foreach ($Categories as $CategoryID => $Category) { if ($AllDiscussions && val('HideAllDiscussions', $Category)) { continue; } if ($Category['PermsDiscussionsView'] && $Category['Following']) { $Watch[] = $CategoryID; } } Gdn::pluginManager()->EventArguments['CategoryIDs'] =& $Watch; Gdn::pluginManager()->fireEvent('CategoryWatch'); if ($AllCount == count($Watch)) { return true; } return $Watch; }
/** * Validate captcha. * * @param mixed $value * @return boolean validity of captcha submission */ public static function validate($value = null) { if (is_null($value)) { // Get captcha text $captchaText = null; Gdn::pluginManager()->EventArguments['captchatext'] =& $captchaText; Gdn::pluginManager()->fireAs('captcha')->fireEvent('get', ['captcha' => $value]); $value = $captchaText; } if (is_null($value)) { return false; } // Validate captcha text // Assume invalid submission $valid = false; Gdn::pluginManager()->EventArguments['captchavalid'] =& $valid; Gdn::pluginManager()->fireAs('captcha')->fireEvent('validate', ['captcha' => $value]); $isValid = $valid ? true : false; unset(Gdn::pluginManager()->EventArguments['captchavalid']); return $isValid; }
/** * If passed path leads to an image, return size * * @param string $Path Path to file. * @return array [0] => Height, [1] => Width. */ public static function getImageSize($Path) { // Static FireEvent for intercepting non-local files. $Sender = new stdClass(); $Sender->Returns = array(); $Sender->EventArguments = array(); $Sender->EventArguments['Path'] =& $Path; $Sender->EventArguments['Parsed'] = Gdn_Upload::parse($Path); Gdn::pluginManager()->callEventHandlers($Sender, 'Gdn_Upload', 'CopyLocal'); if (!in_array(strtolower(pathinfo($Path, PATHINFO_EXTENSION)), array('gif', 'jpg', 'jpeg', 'png'))) { return array(0, 0); } $ImageSize = @getimagesize($Path); if (is_array($ImageSize)) { if (!in_array($ImageSize[2], array(IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG))) { return array(0, 0); } return array($ImageSize[0], $ImageSize[1]); } return array(0, 0); }
/** * Attach mappings for vanilla extension folders. * * @param string $ExtensionType The type of extension to map. * This should be one of: CONTEXT_THEME, CONTEXT_PLUGIN, CONTEXT_APPLICATION. */ public static function attach($ExtensionType) { switch ($ExtensionType) { case self::CONTEXT_APPLICATION: if (Gdn::applicationManager() instanceof Gdn_ApplicationManager) { $EnabledApplications = Gdn::applicationManager()->enabledApplicationFolders(); foreach ($EnabledApplications as $EnabledApplication) { self::attachApplication($EnabledApplication); } } break; case self::CONTEXT_PLUGIN: if (Gdn::pluginManager() instanceof Gdn_PluginManager) { foreach (Gdn::pluginManager()->searchPaths() as $SearchPath => $SearchPathName) { if ($SearchPathName === true || $SearchPathName == 1) { $SearchPathName = md5($SearchPath); } // If we have already loaded the plugin manager, use its internal folder list if (Gdn::pluginManager()->started()) { $Folders = Gdn::pluginManager()->enabledPluginFolders($SearchPath); foreach ($Folders as $PluginFolder) { $FullPluginPath = combinePaths(array($SearchPath, $PluginFolder)); self::registerMap(self::MAP_LIBRARY, self::CONTEXT_PLUGIN, $FullPluginPath, array('SearchSubfolders' => true, 'Extension' => $SearchPathName, 'Structure' => Gdn_Autoloader_Map::STRUCTURE_SPLIT, 'SplitTopic' => strtolower($PluginFolder), 'PreWarm' => true)); } $PluginMap = self::getMap(self::MAP_LIBRARY, self::CONTEXT_PLUGIN); if ($PluginMap && !$PluginMap->mapIsOnDisk()) { Gdn::pluginManager()->forceAutoloaderIndex(); } } } } break; case self::CONTEXT_THEME: break; } }
/** * Manage list of plugins. * * @since 2.0.0 * @access public * @param string $Filter 'enabled', 'disabled', or 'all' (default) * @param string $PluginName Unique ID of plugin to be modified. * @param string $TransientKey Security token. */ public function plugins($Filter = '', $PluginName = '', $TransientKey = '') { $this->permission('Garden.Settings.Manage'); // Page setup $this->addJsFile('addons.js'); $this->title(t('Plugins')); $this->addSideMenu('dashboard/settings/plugins'); // Validate and set properties $Session = Gdn::session(); if ($PluginName && !$Session->validateTransientKey($TransientKey)) { $PluginName = ''; } if (!in_array($Filter, array('enabled', 'disabled'))) { $Filter = 'all'; } $this->Filter = $Filter; // Retrieve all available plugins from the plugins directory $this->EnabledPlugins = Gdn::pluginManager()->enabledPlugins(); self::sortAddons($this->EnabledPlugins); $this->AvailablePlugins = Gdn::pluginManager()->availablePlugins(); self::sortAddons($this->AvailablePlugins); if ($PluginName != '') { try { $this->EventArguments['PluginName'] = $PluginName; if (array_key_exists($PluginName, $this->EnabledPlugins) === true) { Gdn::pluginManager()->disablePlugin($PluginName); Gdn_LibraryMap::clearCache(); $this->fireEvent('AfterDisablePlugin'); } else { $Validation = new Gdn_Validation(); if (!Gdn::pluginManager()->enablePlugin($PluginName, $Validation)) { $this->Form->setValidationResults($Validation->results()); } else { Gdn_LibraryMap::ClearCache(); } $this->EventArguments['Validation'] = $Validation; $this->fireEvent('AfterEnablePlugin'); } } catch (Exception $e) { $this->Form->addError($e); } if ($this->Form->errorCount() == 0) { redirect('/settings/plugins/' . $this->Filter); } } $this->render(); }
/** * Handle toggling this version of embedding on and off. Take care of disabling the other version of embed (the old plugin). * * @param string $Toggle * @param string $TransientKey * @return boolean * @throws Gdn_UserException */ private function toggle($Toggle = '', $TransientKey = '') { if (in_array($Toggle, array('enable', 'disable')) && Gdn::session()->validateTransientKey($TransientKey)) { if ($Toggle == 'enable' && array_key_exists('embedvanilla', Gdn::pluginManager()->enabledPlugins())) { throw new Gdn_UserException('You must disable the "Embed Vanilla" plugin before continuing.'); } // Do the toggle saveToConfig('Garden.Embed.Allow', $Toggle == 'enable' ? true : false); return true; } return false; }
/** * * * @param null $AddonCode * @param bool $Explicit * @param bool $Drop * @throws Exception */ public function runStructure($AddonCode = null, $Explicit = false, $Drop = false) { // Get the structure files for all of the enabled applications. $ApplicationManager = new Gdn_ApplicationManager(); $Apps = $ApplicationManager->EnabledApplications(); $AppNames = consolidateArrayValuesByKey($Apps, 'Folder'); $Paths = array(); foreach ($Apps as $Key => $AppInfo) { $Path = PATH_APPLICATIONS . "/{$AppInfo['Folder']}/settings/structure.php"; if (file_exists($Path)) { $Paths[] = $Path; } Gdn::ApplicationManager()->RegisterPermissions($Key, $this->Validation); } // Execute the structures. $Database = Gdn::database(); $SQL = Gdn::sql(); $Structure = Gdn::structure(); foreach ($Paths as $Path) { include $Path; } // Execute the structures for all of the plugins. $PluginManager = Gdn::pluginManager(); $Registered = $PluginManager->RegisteredPlugins(); foreach ($Registered as $ClassName => $Enabled) { if (!$Enabled) { continue; } try { $Plugin = $PluginManager->GetPluginInstance($ClassName, Gdn_PluginManager::ACCESS_CLASSNAME); if (method_exists($Plugin, 'Structure')) { trace("{$ClassName}->Structure()"); $Plugin->Structure(); } } catch (Exception $Ex) { // Do nothing, plugin wouldn't load/structure. if (Debug()) { throw $Ex; } } } $this->fireEvent('AfterStructure'); }
/** * Takes the path to an asset (image, js file, css file, etc) and prepends the web root. * * @param string $Destination The path to the asset. * @param boolean $WithDomain Whether or not to include the domain. * @param boolean $AddVersion Whether or not to add a cache-busting querystring parameter to the URL. * @param string $Version Forced version, skips auto-lookup. * @return string Returns the URL to the asset. */ function asset($Destination = '', $WithDomain = false, $AddVersion = false, $Version = null) { $Destination = str_replace('\\', '/', $Destination); if (IsUrl($Destination)) { $Result = $Destination; } else { $Result = Gdn::request()->urlDomain($WithDomain) . Gdn::request()->assetRoot() . '/' . ltrim($Destination, '/'); } if ($AddVersion) { if (strpos($Result, '?') === false) { $Result .= '?'; } else { $Result .= '&'; } // Figure out which version to put after the asset. if (is_null($Version)) { $Version = APPLICATION_VERSION; if (preg_match('`^/([^/]+)/([^/]+)/`', $Destination, $Matches)) { $Type = $Matches[1]; $Key = $Matches[2]; static $ThemeVersion = null; switch ($Type) { case 'plugins': $PluginInfo = Gdn::pluginManager()->getPluginInfo($Key); $Version = val('Version', $PluginInfo, $Version); break; case 'applications': $AppInfo = Gdn::applicationManager()->getApplicationInfo(ucfirst($Key)); $Version = val('Version', $AppInfo, $Version); break; case 'themes': if ($ThemeVersion === null) { $ThemeInfo = Gdn::themeManager()->getThemeInfo(Theme()); if ($ThemeInfo !== false) { $ThemeVersion = val('Version', $ThemeInfo, $Version); } else { $ThemeVersion = $Version; } } $Version = $ThemeVersion; break; } } } $Result .= 'v=' . urlencode($Version); } return $Result; }
* Extension Startup * * Allow installed addons to execute startup and bootstrap procedures that they may have, here. */ // Bootstrapping. foreach (Gdn::addonManager()->getEnabled() as $addon) { /* @var Addon $addon */ if ($bootstrapPath = $addon->getSpecial('bootstrap')) { $bootstrapPath = $addon->path($bootstrapPath); include $bootstrapPath; } } // Themes startup Gdn::themeManager()->start(); // Plugins startup Gdn::pluginManager()->start(); /** * Locales * * Install any custom locales provided by applications and plugins, and set up * the locale management system. */ // Load the Garden locale system $gdnLocale = new Gdn_Locale(c('Garden.Locale', 'en'), Gdn::addonManager()); Gdn::factoryInstall(Gdn::AliasLocale, 'Gdn_Locale', null, Gdn::FactorySingleton, $gdnLocale); unset($gdnLocale); require_once PATH_LIBRARY_CORE . '/functions.validation.php'; // Start Authenticators Gdn::authenticator()->startAuthenticator(); /** * Bootstrap After
/** * */ protected function __construct() { // Initialize the canonical list. (emoji) $this->emoji = array('smile' => 'smile.png', 'smiley' => 'smiley.png', 'wink' => 'wink.png', 'blush' => 'blush.png', 'neutral' => 'neutral.png', 'relaxed' => 'relaxed.png', 'grin' => 'grin.png', 'joy' => 'joy.png', 'sweat_smile' => 'sweat_smile.png', 'lol' => 'lol.png', 'innocent' => 'innocent.png', 'naughty' => 'naughty.png', 'yum' => 'yum.png', 'relieved' => 'relieved.png', 'love' => 'love.png', 'sunglasses' => 'sunglasses.png', 'smirk' => 'smirk.png', 'expressionless' => 'expressionless.png', 'unamused' => 'unamused.png', 'sweat' => 'sweat.png', 'pensive' => 'pensive.png', 'confused' => 'confused.png', 'confounded' => 'confounded.png', 'kissing' => 'kissing.png', 'kissing_heart' => 'kissing_heart.png', 'kissing_smiling_eyes' => 'kissing_smiling_eyes.png', 'kissing_closed_eyes' => 'kissing_closed_eyes.png', 'tongue' => 'tongue.png', 'disappointed' => 'disappointed.png', 'worried' => 'worried.png', 'angry' => 'angry.png', 'rage' => 'rage.png', 'cry' => 'cry.png', 'persevere' => 'persevere.png', 'triumph' => 'triumph.png', 'frowning' => 'frowning.png', 'anguished' => 'anguished.png', 'fearful' => 'fearful.png', 'weary' => 'weary.png', 'sleepy' => 'sleepy.png', 'tired_face' => 'tired_face.png', 'grimace' => 'grimace.png', 'bawling' => 'bawling.png', 'open_mouth' => 'open_mouth.png', 'hushed' => 'hushed.png', 'cold_sweat' => 'cold_sweat.png', 'scream' => 'scream.png', 'astonished' => 'astonished.png', 'flushed' => 'flushed.png', 'sleeping' => 'sleeping.png', 'dizzy' => 'dizzy.png', 'no_mouth' => 'no_mouth.png', 'mask' => 'mask.png', 'star' => 'star.png', 'cookie' => 'cookie.png', 'warning' => 'warning.png', 'mrgreen' => 'mrgreen.png', 'heart' => 'heart.png', 'heartbreak' => 'heartbreak.png', 'kiss' => 'kiss.png', '+1' => '+1.png', '-1' => '-1.png', 'grey_question' => 'grey_question.png', 'trollface' => 'trollface.png'); // Some aliases self-referencing the canonical list. Use this syntax. // This is used in cases where emoji image cannot be found. $this->emoji['error'] =& $this->emoji['grey_question']; // Initialize the alias list. (emoticons) $this->aliases = array(':)' => 'smile', ':D' => 'lol', '=)' => 'smiley', ':(' => 'frowning', ';)' => 'wink', ':\\' => 'confused', ':/' => 'confused', ':o' => 'open_mouth', ':s' => 'confounded', ':p' => 'stuck_out_tongue', ":'(" => 'cry', ':|' => 'neutral', 'D:' => 'anguished', 'B)' => 'sunglasses', ':#' => 'grimace', ':*' => 'kiss', ':3' => 'blush', 'o:)' => 'innocent', '<3' => 'heart', '>:)' => 'naughty'); $this->archive = array('disappointed_relieved' => 'disappointed_relieved.png', 'dizzy_face' => 'dizzy.png', 'broken_heart' => 'heartbreak.png', 'grinning' => 'grin.png', 'heart_eyes' => 'love.png', 'neutral_face' => 'neutral.png', 'smiling_imp' => 'naughty.png', 'sob' => 'bawling.png', 'stuck_out_tongue' => 'tongue.png', 'stuck_out_tongue_winking_eye' => 'stuck_out_tongue_winking_eye.png', 'stuck_out_tongue_closed_eyes' => 'stuck_out_tongue_closed_eyes.png'); $this->editorList = array(':)' => 'smile', ':D' => 'lol', ':(' => 'disappointed', ';)' => 'wink', ':/' => 'confused', ':o' => 'open_mouth', ':s' => 'confounded', ':p' => 'stuck_out_tongue', ":'(" => 'cry', ':|' => 'neutral', 'B)' => 'sunglasses', ':#' => 'grimace', ':*' => 'kiss', '<3' => 'heart', 'o:)' => 'innocent', '>:)' => 'naughty'); if (C('Garden.EmojiSet') === 'none') { $this->enabled = false; } Gdn::pluginManager()->callEventHandlers($this, 'Emoji', 'Init', 'Handler'); // Add emoji to definition list for whole site. This used to be in the // advanced editor plugin, but since moving atmentions to core, had to // make sure they were still being added. This will make sure that // emoji autosuggest works. Note: emoji will not be core yet, so the only // way that this gets called is by the editor when it instantiates. Core // does not instantiate this class anywhere, so there will not be any // suggestions for emoji yet, but keep here for whenever Advanced Editor // is running. $c = Gdn::controller(); if ($c && $this->enabled) { $emojis = $this->getEmoji(); $emojiAssetPath = $this->getAssetPath(); $emoji = array(); foreach ($emojis as $name => $data) { $emoji[] = array("name" => "" . $name . "", "url" => Asset($emojiAssetPath . '/' . $data)); } $emoji = array('assetPath' => Asset($this->getAssetPath()), 'format' => $this->getFormat(), 'emoji' => $this->getEmoji()); $c->addDefinition('emoji', $emoji); } }
/** * Returns the url prefix for a given type. * If there is a plugin that wants to store uploads at a different location or in a different way then they register themselves by subscribing to the Gdn_Upload_GetUrls_Handler event. * After that they will be available here. * * @param string $Type The type of upload to get the prefix for. * @return string The url prefix. */ public static function urls($Type = null) { static $Urls = null; if ($Urls === null) { $Urls = array('' => asset('/uploads', true)); $Sender = new stdClass(); $Sender->Returns = array(); $Sender->EventArguments = array(); $Sender->EventArguments['Urls'] =& $Urls; Gdn::pluginManager()->callEventHandlers($Sender, 'Gdn_Upload', 'GetUrls'); } if ($Type === null) { return $Urls; } if (isset($Urls[$Type])) { return $Urls[$Type]; } return false; }
/** * The summary of all settings available. * * The menu items displayed here are collected from each application's * application controller and all plugin's definitions. * * @since 2.0.0 * @access public */ public function index() { $this->ApplicationFolder = 'dashboard'; $this->MasterView = 'setup'; // Fatal error if Garden has already been installed. $Installed = c('Garden.Installed'); if ($Installed) { throw new Gdn_UserException('Vanilla is installed!', 409); } if (!$this->_checkPrerequisites()) { $this->View = 'prerequisites'; } else { $this->View = 'configure'; // Make sure the user has copied the htaccess file over. if (!file_exists(PATH_ROOT . '/.htaccess')) { $this->setData('NoHtaccess', true); if ($this->Form->isPostBack()) { $htaccessAction = $this->Form->getFormValue('HtaccessAction'); switch ($htaccessAction) { case 'skip': break; case 'dist': $htaccessCopied = copy(PATH_ROOT . '/.htaccess.dist', PATH_ROOT . '/.htaccess'); if ($htaccessCopied === false) { $this->Form->addError(t('Unable to copy .htaccess.dist to .htaccess.', 'Unable to copy .htaccess.dist to .htaccess. You may need to manually copy this file.')); } break; default: $this->Form->addError(t('You are missing Vanilla\'s .htaccess file.', 'You are missing an <b>.htaccess</b> file. This file can be automatically created from Vanilla\'s <b>.htaccess.dist</b>. However, it may not have been copied if you are using FTP to upload your files because this file is hidden. Make sure you\'ve copied the <b>.htaccess.dist</b> file before continuing.')); } } } $ApplicationManager = Gdn::applicationManager(); // Need to go through all of the setups for each application. Garden, if ($this->configure() && $this->Form->isPostBack()) { // Get list of applications to enable during install // Override by creating the config and adding this setting before install begins $AppNames = c('Garden.Install.Applications', array('Conversations', 'Vanilla')); try { // Step through the available applications, enabling each of them. foreach ($AppNames as $AppName) { $Validation = new Gdn_Validation(); $ApplicationManager->RegisterPermissions($AppName, $Validation); $ApplicationManager->EnableApplication($AppName, $Validation); } Gdn::pluginManager()->start(true); } catch (Exception $ex) { $this->Form->addError($ex); } if ($this->Form->errorCount() == 0) { // Save a variable so that the application knows it has been installed. // Now that the application is installed, select a more user friendly error page. $Config = array('Garden.Installed' => true); saveToConfig($Config); $this->setData('Installed', true); $this->fireAs('UpdateModel')->fireEvent('AfterStructure'); $this->fireEvent('Installed'); // Go to the dashboard. if ($this->deliveryType() === DELIVERY_TYPE_ALL) { redirect('/settings/gettingstarted'); } } elseif ($this->deliveryType() === DELIVERY_TYPE_DATA) { $maxCode = 0; $messages = array(); foreach ($this->Form->errors() as $row) { list($code, $message) = $row; $maxCode = max($maxCode, $code); $messages[] = $message; } throw new Gdn_UserException(implode(' ', $messages), $maxCode); } } } $this->render(); }
/** * Saves the specified image at $Target in the specified format with the * specified dimensions (or the existing dimensions if height/width are not provided. * * @param string The path to the source image. Typically this is the tmp file name returned by $this->ValidateUpload(); * @param string The full path to where the image should be saved, including image name. * @param int An integer value indicating the maximum allowed height of the image (in pixels). * @param int An integer value indicating the maximum allowed width of the image (in pixels). * @param array Options additional options for saving the image. * - <b>Crop</b>: Image proportions will always remain constrained. The Crop parameter is a boolean value indicating if the image should be cropped when one dimension (height or width) goes beyond the constrained proportions. * - <b>OutputType</b>: The format in which the output image should be saved. Options are: jpg, png, and gif. Default is jpg. * - <b>ImageQuality</b>: An integer value representing the qualityof the saved image. Ranging from 0 (worst quality, smaller file) to 100 (best quality, biggest file). * - <b>SourceX, SourceY</b>: If you want to create a thumbnail that is a crop of the image these are the coordinates of the thumbnail. * - <b>SourceHeight. SourceWidth</b>: If you want to create a thumbnail that is a crop of the image these are it's dimensions. */ public static function saveImageAs($Source, $Target, $Height = '', $Width = '', $Options = array()) { $Crop = false; $OutputType = ''; $ImageQuality = c('Garden.UploadImage.Quality', 100); // Make function work like it used to. $Args = func_get_args(); $SaveGif = false; if (count($Args) > 5) { $Crop = val(4, $Args, $Crop); $OutputType = val(5, $Args, $OutputType); $ImageQuality = val(6, $Args, $ImageQuality); } elseif (is_bool($Options)) { $Crop = $Options; } else { $Crop = val('Crop', $Options, $Crop); $OutputType = val('OutputType', $Options, $OutputType); $ImageQuality = val('ImageQuality', $Options, $ImageQuality); $SaveGif = val('SaveGif', $Options); } // Set some boundaries for $ImageQuality if ($ImageQuality < 10) { $ImageQuality = 10; } if ($ImageQuality > 100 || !is_numeric($ImageQuality)) { $ImageQuality = 100; } // Make sure type, height & width are properly defined. if (!function_exists('gd_info')) { throw new Exception(T('The uploaded file could not be processed because GD is not installed.')); } $GdInfo = gd_info(); $Size = getimagesize($Source); list($WidthSource, $HeightSource, $Type) = $Size; $WidthSource = val('SourceWidth', $Options, $WidthSource); $HeightSource = val('SourceHeight', $Options, $HeightSource); if ($Height == '' || !is_numeric($Height)) { $Height = $HeightSource; } if ($Width == '' || !is_numeric($Width)) { $Width = $WidthSource; } if (!$OutputType) { $OutputTypes = array(1 => 'gif', 2 => 'jpeg', 3 => 'png', 17 => 'ico'); $OutputType = val($Type, $OutputTypes, 'jpg'); } elseif ($Type == 17 && $OutputType != 'ico') { // Icons cannot be converted throw new Exception(T('Upload cannot convert icons.')); } // Figure out the target path. $TargetParsed = Gdn_Upload::parse($Target); $TargetPath = PATH_UPLOADS . '/' . ltrim($TargetParsed['Name'], '/'); if (!file_exists(dirname($TargetPath))) { mkdir(dirname($TargetPath), 0777, true); } // Don't resize if the source dimensions are smaller than the target dimensions or an icon $XCoord = val('SourceX', $Options, 0); $YCoord = val('SourceY', $Options, 0); if (($HeightSource > $Height || $WidthSource > $Width) && $Type != 17) { $AspectRatio = (double) $WidthSource / $HeightSource; if ($Crop === false) { if (round($Width / $AspectRatio) > $Height) { $Width = round($Height * $AspectRatio); } else { $Height = round($Width / $AspectRatio); } } else { $HeightDiff = $HeightSource - $Height; $WidthDiff = $WidthSource - $Width; if ($WidthDiff > $HeightDiff) { // Crop the original width down $NewWidthSource = round($Width * $HeightSource / $Height); // And set the original x position to the cropped start point. if (!isset($Options['SourceX'])) { $XCoord = round(($WidthSource - $NewWidthSource) / 2); } $WidthSource = $NewWidthSource; } else { // Crop the original height down $NewHeightSource = round($Height * $WidthSource / $Width); // And set the original y position to the cropped start point. if (!isset($Options['SourceY'])) { $YCoord = 0; // crop to top because most portraits show the face at the top. } $HeightSource = $NewHeightSource; } } } else { // Neither target dimension is larger than the original, so keep the original dimensions. $Height = $HeightSource; $Width = $WidthSource; } $Process = true; if ($WidthSource <= $Width && $HeightSource <= $Height && $Type == 1 && $SaveGif) { $Process = false; } // Never process icons if ($Type == 17) { $Process = false; } if ($Process) { // Create GD image from the provided file, but first check if we have the necessary tools $SourceImage = false; switch ($Type) { case 1: if (val('GIF Read Support', $GdInfo) || val('GIF Write Support', $GdInfo)) { $SourceImage = imagecreatefromgif($Source); } break; case 2: if (val('JPG Support', $GdInfo) || val('JPEG Support', $GdInfo)) { $SourceImage = imagecreatefromjpeg($Source); } break; case 3: if (val('PNG Support', $GdInfo)) { $SourceImage = imagecreatefrompng($Source); imagealphablending($SourceImage, true); } break; } if (!$SourceImage) { throw new Exception(sprintf(T('You cannot save images of this type (%s).'), $Type)); } // Create a new image from the raw source if (function_exists('imagecreatetruecolor')) { $TargetImage = imagecreatetruecolor($Width, $Height); // Only exists if GD2 is installed } else { $TargetImage = imagecreate($Width, $Height); // Always exists if any GD is installed } if ($OutputType == 'png') { imagealphablending($TargetImage, false); imagesavealpha($TargetImage, true); } imagecopyresampled($TargetImage, $SourceImage, 0, 0, $XCoord, $YCoord, $Width, $Height, $WidthSource, $HeightSource); imagedestroy($SourceImage); // Check for EXIF rotation tag, and rotate the image if present if (function_exists('exif_read_data') && ($Type == IMAGETYPE_JPEG || $Type == IMAGETYPE_TIFF_II || $Type == IMAGETYPE_TIFF_MM)) { $ImageExif = exif_read_data($Source); if (!empty($ImageExif['Orientation'])) { switch ($ImageExif['Orientation']) { case 3: $TargetImage = imagerotate($TargetImage, 180, 0); break; case 6: $TargetImage = imagerotate($TargetImage, -90, 0); list($Width, $Height) = array($Height, $Width); break; case 8: $TargetImage = imagerotate($TargetImage, 90, 0); list($Width, $Height) = array($Height, $Width); break; } } } // No need to check these, if we get here then whichever function we need will be available if ($OutputType == 'gif') { imagegif($TargetImage, $TargetPath); } elseif ($OutputType == 'png') { imagepng($TargetImage, $TargetPath, 10 - (int) ($ImageQuality / 10)); } elseif ($OutputType == 'ico') { self::imageIco($TargetImage, $TargetPath); } else { imagejpeg($TargetImage, $TargetPath, $ImageQuality); } } else { copy($Source, $TargetPath); } // Allow a plugin to move the file to a differnt location. $Sender = new stdClass(); $Sender->EventArguments = array(); $Sender->EventArguments['Path'] = $TargetPath; $Parsed = self::parse($TargetPath); $Parsed['Width'] = $Width; $Parsed['Height'] = $Height; $Sender->EventArguments['Parsed'] =& $Parsed; $Sender->Returns = array(); Gdn::pluginManager()->callEventHandlers($Sender, 'Gdn_Upload', 'SaveAs'); return $Sender->EventArguments['Parsed']; }
/** * Defines & retrieves the view and master view. Renders all content within * them to the screen. * * @param string $View * @param string $ControllerName * @param string $ApplicationFolder * @param string $AssetName The name of the asset container that the content should be rendered in. */ public function xRender($View = '', $ControllerName = false, $ApplicationFolder = false, $AssetName = 'Content') { // Remove the deliver type and method from the query string so they don't corrupt calls to Url. $this->Request->setValueOn(Gdn_Request::INPUT_GET, 'DeliveryType', null); $this->Request->setValueOn(Gdn_Request::INPUT_GET, 'DeliveryMethod', null); Gdn::pluginManager()->callEventHandlers($this, $this->ClassName, $this->RequestMethod, 'Render'); if ($this->_DeliveryType == DELIVERY_TYPE_NONE) { return; } // Handle deprecated StatusMessage values that may have been added by plugins $this->informMessage($this->StatusMessage); // If there were uncontrolled errors above the json data, wipe them out // before fetching it (otherwise the json will not be properly parsed // by javascript). if ($this->_DeliveryMethod == DELIVERY_METHOD_JSON) { if (ob_get_level()) { ob_clean(); } $this->contentType('application/json; charset=' . c('Garden.Charset', 'utf-8')); $this->setHeader('X-Content-Type-Options', 'nosniff'); // Cross-Origin Resource Sharing (CORS) $this->setAccessControl(); } if ($this->_DeliveryMethod == DELIVERY_METHOD_TEXT) { $this->contentType('text/plain'); } // Send headers to the browser $this->sendHeaders(); // Make sure to clear out the content asset collection if this is a syndication request if ($this->SyndicationMethod !== SYNDICATION_NONE) { $this->Assets['Content'] = ''; } // Define the view if (!in_array($this->_DeliveryType, array(DELIVERY_TYPE_BOOL, DELIVERY_TYPE_DATA))) { $View = $this->fetchView($View, $ControllerName, $ApplicationFolder); // Add the view to the asset container if necessary if ($this->_DeliveryType != DELIVERY_TYPE_VIEW) { $this->addAsset($AssetName, $View, 'Content'); } } // Redefine the view as the entire asset contents if necessary if ($this->_DeliveryType == DELIVERY_TYPE_ASSET) { $View = $this->getAsset($AssetName); } elseif ($this->_DeliveryType == DELIVERY_TYPE_BOOL) { // Or as a boolean if necessary $View = true; if (property_exists($this, 'Form') && is_object($this->Form)) { $View = $this->Form->errorCount() > 0 ? false : true; } } if ($this->_DeliveryType == DELIVERY_TYPE_MESSAGE && $this->Form) { $View = $this->Form->errors(); } if ($this->_DeliveryType == DELIVERY_TYPE_DATA) { $ExitRender = $this->renderData(); if ($ExitRender) { return; } } if ($this->_DeliveryMethod == DELIVERY_METHOD_JSON) { // Format the view as JSON with some extra information about the // success status of the form so that jQuery knows what to do // with the result. if ($this->_FormSaved === '') { // Allow for override $this->_FormSaved = property_exists($this, 'Form') && $this->Form->errorCount() == 0 ? true : false; } $this->setJson('FormSaved', $this->_FormSaved); $this->setJson('DeliveryType', $this->_DeliveryType); $this->setJson('Data', base64_encode($View instanceof Gdn_IModule ? $View->toString() : $View)); $this->setJson('InformMessages', $this->_InformMessages); $this->setJson('ErrorMessages', $this->_ErrorMessages); $this->setJson('RedirectUrl', $this->RedirectUrl); // Make sure the database connection is closed before exiting. $this->finalize(); if (!check_utf8($this->_Json['Data'])) { $this->_Json['Data'] = utf8_encode($this->_Json['Data']); } $Json = json_encode($this->_Json); $this->_Json['Data'] = $Json; exit($this->_Json['Data']); } else { if (count($this->_InformMessages) > 0 && $this->SyndicationMethod === SYNDICATION_NONE) { $this->addDefinition('InformMessageStack', base64_encode(json_encode($this->_InformMessages))); } if ($this->RedirectUrl != '' && $this->SyndicationMethod === SYNDICATION_NONE) { $this->addDefinition('RedirectUrl', $this->RedirectUrl); } if ($this->_DeliveryMethod == DELIVERY_METHOD_XHTML && debug()) { $this->addModule('TraceModule'); } // Render if ($this->_DeliveryType == DELIVERY_TYPE_BOOL) { echo $View ? 'TRUE' : 'FALSE'; } elseif ($this->_DeliveryType == DELIVERY_TYPE_ALL) { // Render $this->renderMaster(); } else { if ($View instanceof Gdn_IModule) { $View->render(); } else { echo $View; } } } }
/** * Authenticates the user with the provided Authenticator class. * * @param int $UserID The UserID to start the session with. * @param bool $SetIdentity Whether or not to set the identity (cookie) or make this a one request session. * @param bool $Persist If setting an identity, should we persist it beyond browser restart? */ public function start($UserID = false, $SetIdentity = true, $Persist = false) { if (!c('Garden.Installed', false)) { return; } // Retrieve the authenticated UserID from the Authenticator module. $UserModel = Gdn::authenticator()->getUserModel(); $this->UserID = $UserID !== false ? $UserID : Gdn::authenticator()->getIdentity(); $this->User = false; // Now retrieve user information if ($this->UserID > 0) { // Instantiate a UserModel to get session info $this->User = $UserModel->getSession($this->UserID); if ($this->User) { if ($SetIdentity) { Gdn::authenticator()->setIdentity($this->UserID, $Persist); Logger::event('session_start', Logger::INFO, 'Session started for {username}.'); Gdn::pluginManager()->callEventHandlers($this, 'Gdn_Session', 'Start'); } $UserModel->EventArguments['User'] =& $this->User; $UserModel->fireEvent('AfterGetSession'); $this->_Permissions = Gdn_Format::unserialize($this->User->Permissions); $this->_Preferences = Gdn_Format::unserialize($this->User->Preferences); $this->_Attributes = Gdn_Format::unserialize($this->User->Attributes); $this->_TransientKey = is_array($this->_Attributes) ? val('TransientKey', $this->_Attributes) : false; if ($this->_TransientKey === false) { $this->_TransientKey = $UserModel->setTransientKey($this->UserID); } // Save any visit-level information. if ($SetIdentity) { $UserModel->updateVisit($this->UserID); } } else { $this->UserID = 0; $this->User = false; $this->_TransientKey = getAppCookie('tk'); if ($SetIdentity) { Gdn::authenticator()->setIdentity(null); } } } else { // Grab the transient key from the cookie. This doesn't always get set but we'll try it here anyway. $this->_TransientKey = getAppCookie('tk'); } // Load guest permissions if necessary if ($this->UserID == 0) { $this->_Permissions = Gdn_Format::unserialize($UserModel->definePermissions(0)); } }
public static function discussionTypes() { if (!self::$_DiscussionTypes) { $DiscussionTypes = array('Discussion' => array('Singular' => 'Discussion', 'Plural' => 'Discussions', 'AddUrl' => '/post/discussion', 'AddText' => 'New Discussion')); Gdn::pluginManager()->EventArguments['Types'] =& $DiscussionTypes; Gdn::pluginManager()->FireAs('DiscussionModel')->fireEvent('DiscussionTypes'); self::$_DiscussionTypes = $DiscussionTypes; unset(Gdn::pluginManager()->EventArguments['Types']); } return self::$_DiscussionTypes; }
/** * Gets the short name of the currently active cache. * * This method retrieves the name of the active cache according to the config file. * It fires an event thereafter, allowing that value to be overridden * by loaded plugins. * * @return string shortname of current auto active cache */ public static function activeCache() { /* * There is a catch 22 with caching the config file. We need * an external way to define the cache layer before needing it * in the config. */ if (defined('CACHE_METHOD_OVERRIDE')) { $ActiveCache = CACHE_METHOD_OVERRIDE; } else { $ActiveCache = C('Cache.Method', false); } // This should only fire when cache is loading automatically if (!func_num_args() && Gdn::pluginManager() instanceof Gdn_PluginManager) { Gdn::pluginManager()->EventArguments['ActiveCache'] =& $ActiveCache; Gdn::pluginManager()->fireEvent('BeforeActiveCache'); } return $ActiveCache; }
/** * * * @return Smarty The smarty object used for rendering. */ public function smarty() { if (is_null($this->_Smarty)) { $Smarty = Gdn::factory('Smarty'); $Smarty->cache_dir = PATH_CACHE . DS . 'Smarty' . DS . 'cache'; $Smarty->compile_dir = PATH_CACHE . DS . 'Smarty' . DS . 'compile'; $Smarty->plugins_dir[] = PATH_LIBRARY . DS . 'vendors' . DS . 'SmartyPlugins'; // Gdn::PluginManager()->Trace = TRUE; Gdn::pluginManager()->callEventHandlers($Smarty, 'Gdn_Smarty', 'Init'); $this->_Smarty = $Smarty; } return $this->_Smarty; }
/** * * * @param $Sender * @throws Exception */ public function pluginController_dismissGettingStarted_create($Sender) { Gdn::pluginManager()->disablePlugin('GettingStarted'); echo 'TRUE'; }
/** * When enabled, disable other known editors that may clash with this one. * * If editor is loaded, then the other editors loaded after, there are CSS rules that hide them. * This way, the editor plugin always takes precedence. */ public function setup() { $pluginEditors = array('cleditor', 'ButtonBar', 'Emotify', 'FileUpload'); foreach ($pluginEditors as $pluginName) { Gdn::pluginManager()->disablePlugin($pluginName); } touchConfig(array('Garden.MobileInputFormatter' => 'TextEx', 'Plugins.editor.ForceWysiwyg' => false)); $this->structure(); }
/** * * * @return bool|null * @throws Exception */ public function save() { if (!$this->Dirty) { return null; } $this->EventArguments['ConfigDirty'] =& $this->Dirty; $this->EventArguments['ConfigNoSave'] = false; $this->EventArguments['ConfigType'] = $this->Type; $this->EventArguments['ConfigSource'] = $this->Source; $this->EventArguments['ConfigData'] = $this->Settings; $this->fireEvent('BeforeSave'); if ($this->EventArguments['ConfigNoSave']) { $this->Dirty = false; return true; } // Check for and fire callback if one exists if ($this->Callback && is_callable($this->Callback)) { $CallbackOptions = array(); if (!is_array($this->CallbackOptions)) { $this->CallbackOptions = array(); } $CallbackOptions = array_merge($CallbackOptions, $this->CallbackOptions, array('ConfigDirty' => $this->Dirty, 'ConfigType' => $this->Type, 'ConfigSource' => $this->Source, 'ConfigData' => $this->Settings, 'SourceObject' => $this)); $ConfigSaved = call_user_func($this->Callback, $CallbackOptions); if ($ConfigSaved) { $this->Dirty = false; return true; } } switch ($this->Type) { case 'file': if (empty($this->Source)) { trigger_error(errorMessage('You must specify a file path to be saved.', 'Configuration', 'Save'), E_USER_ERROR); } $CheckWrite = $this->Source; if (!file_exists($CheckWrite)) { $CheckWrite = dirname($CheckWrite); } if (!is_writable($CheckWrite)) { throw new Exception(sprintf(t("Unable to write to config file '%s' when saving."), $this->Source)); } $Group = $this->Group; $Data =& $this->Settings; ksort($Data); // Check for the case when the configuration is the group. if (is_array($Data) && count($Data) == 1 && array_key_exists($Group, $Data)) { $Data = $Data[$Group]; } // Do a sanity check on the config save. if ($this->Source == Gdn::config()->defaultPath()) { // Log root config changes try { $LogData = $this->Initial; $LogData['_New'] = $this->Settings; LogModel::insert('Edit', 'Configuration', $LogData); } catch (Exception $Ex) { } if (!isset($Data['Database'])) { if ($Pm = Gdn::pluginManager()) { $Pm->EventArguments['Data'] = $Data; $Pm->EventArguments['Backtrace'] = debug_backtrace(); $Pm->fireEvent('ConfigError'); } return false; } } // Write config data to string format, ready for saving $FileContents = Gdn_Configuration::format($Data, array('VariableName' => $Group, 'WrapPHP' => true, 'ByLine' => true)); if ($FileContents === false) { trigger_error(errorMessage('Failed to define configuration file contents.', 'Configuration', 'Save'), E_USER_ERROR); } // Save to cache if we're into that sort of thing $FileKey = sprintf(Gdn_Configuration::CONFIG_FILE_CACHE_KEY, $this->Source); if ($this->Configuration && $this->Configuration->caching() && Gdn::cache()->type() == Gdn_Cache::CACHE_TYPE_MEMORY && Gdn::cache()->activeEnabled()) { $CachedConfigData = Gdn::cache()->store($FileKey, $Data, array(Gdn_Cache::FEATURE_NOPREFIX => true, Gdn_Cache::FEATURE_EXPIRY => 3600)); } $TmpFile = tempnam(PATH_CONF, 'config'); $Result = false; if (file_put_contents($TmpFile, $FileContents) !== false) { chmod($TmpFile, 0775); $Result = rename($TmpFile, $this->Source); } if ($Result) { if (function_exists('apc_delete_file')) { // This fixes a bug with some configurations of apc. @apc_delete_file($this->Source); } elseif (function_exists('opcache_invalidate')) { @opcache_invalidate($this->Source); } } $this->Dirty = false; return $Result; break; case 'json': case 'array': case 'string': /** * How would these even save? String config data must be handled by * an event hook or callback, if at all. */ $this->Dirty = false; return false; break; } }