function echoScripts($directory) { $scriptFiles = array_diff(scandir($directory), array('..', '.')); foreach ($scriptFiles as $scriptFile) { if (endsWith($scriptFile, ".js")) { $path = combinePaths($directory, $scriptFile); echo "\t<!--suppress HtmlUnknownTarget --><script type=\"text/javascript\" src=\"{$path}\"></script>\n"; } } }
/** * Constructor. */ function __construct() { $this->PhpMailer = new PHPMailer(); $this->PhpMailer->CharSet = 'utf-8'; $this->PhpMailer->SingleTo = c('Garden.Email.SingleTo', false); $this->PhpMailer->PluginDir = combinePaths(array(PATH_LIBRARY, 'vendors/phpmailer/')); $this->PhpMailer->Hostname = c('Garden.Email.Hostname', ''); $this->PhpMailer->Encoding = 'quoted-printable'; $this->clear(); $this->addHeader('Precedence', 'list'); $this->addHeader('X-Auto-Response-Suppress', 'All'); parent::__construct(); }
/** * * * @param $Method * @param $RequestParameters * @param bool $Callback * @param bool $ParseResponse * @return array|bool|mixed|type * @throws Exception */ public function analytics($Method, $RequestParameters, $Callback = false, $ParseResponse = true) { $FullMethod = explode('/', $Method); if (sizeof($FullMethod) < 2) { array_unshift($FullMethod, "analytics"); } list($ApiController, $ApiMethod) = $FullMethod; $ApiController = strtolower($ApiController); $ApiMethod = stringEndsWith(strtolower($ApiMethod), '.json', true, true) . '.json'; $FinalURL = 'http://' . combinePaths(array($this->AnalyticsServer, $ApiController, $ApiMethod)); $RequestHeaders = array(); // Allow hooking of analytics events $this->EventArguments['AnalyticsMethod'] =& $Method; $this->EventArguments['AnalyticsArgs'] =& $RequestParameters; $this->EventArguments['AnalyticsUrl'] =& $FinalURL; $this->EventArguments['AnalyticsHeaders'] =& $RequestHeaders; $this->fireEvent('SendAnalytics'); // Sign request $this->sign($RequestParameters, true); $RequestMethod = val('RequestMethod', $RequestParameters, 'GET'); unset($RequestParameters['RequestMethod']); try { $ProxyRequest = new ProxyRequest(false, array('Method' => $RequestMethod, 'Timeout' => 10, 'Cookies' => false)); $Response = $ProxyRequest->request(array('Url' => $FinalURL, 'Log' => false), $RequestParameters, null, $RequestHeaders); } catch (Exception $e) { $Response = false; } if ($Response !== false) { $JsonResponse = json_decode($Response, true); if ($JsonResponse !== false) { if ($ParseResponse) { $AnalyticsJsonResponse = (array) val('Analytics', $JsonResponse, false); // If we received a reply, parse it if ($AnalyticsJsonResponse !== false) { $this->parseAnalyticsResponse($AnalyticsJsonResponse, $Response, $Callback); return $AnalyticsJsonResponse; } } else { return $JsonResponse; } } return $Response; } return false; }
/** * Constructor. */ function __construct() { $this->PhpMailer = new PHPMailer(); $this->PhpMailer->CharSet = c('Garden.Charset', 'utf-8'); $this->PhpMailer->SingleTo = c('Garden.Email.SingleTo', false); $this->PhpMailer->PluginDir = combinePaths(array(PATH_LIBRARY, 'vendors/phpmailer/')); $this->PhpMailer->Hostname = c('Garden.Email.Hostname', ''); $this->PhpMailer->Encoding = 'quoted-printable'; $this->clear(); $this->addHeader('Precedence', 'list'); $this->addHeader('X-Auto-Response-Suppress', 'All'); $this->emailTemplate = new EmailTemplate(); $this->resolveFormat(); if ($this->format === 'html') { $this->setDefaultEmailColors(); $this->setDefaultEmailImage(); } parent::__construct(); }
/** * */ public function renderMaster() { // Build the master view if necessary if (in_array($this->_DeliveryType, array(DELIVERY_TYPE_ALL))) { $this->MasterView = $this->masterView(); // Only get css & ui components if this is NOT a syndication request if ($this->SyndicationMethod == SYNDICATION_NONE && is_object($this->Head)) { $CssAnchors = AssetModel::getAnchors(); $this->EventArguments['CssFiles'] =& $this->_CssFiles; $this->fireEvent('BeforeAddCss'); $ETag = AssetModel::eTag(); $CombineAssets = c('Garden.CombineAssets'); $ThemeType = isMobile() ? 'mobile' : 'desktop'; // And now search for/add all css files. foreach ($this->_CssFiles as $CssInfo) { $CssFile = $CssInfo['FileName']; if (!array_key_exists('Options', $CssInfo) || !is_array($CssInfo['Options'])) { $CssInfo['Options'] = array(); } $Options =& $CssInfo['Options']; // style.css and admin.css deserve some custom processing. if (in_array($CssFile, $CssAnchors)) { if (!$CombineAssets) { // Grab all of the css files from the asset model. $AssetModel = new AssetModel(); $CssFiles = $AssetModel->getCssFiles($ThemeType, ucfirst(substr($CssFile, 0, -4)), $ETag); foreach ($CssFiles as $Info) { $this->Head->addCss($Info[1], 'all', true, $CssInfo); } } else { $Basename = substr($CssFile, 0, -4); $this->Head->addCss(url("/asset/css/{$ThemeType}/{$Basename}-{$ETag}.css", '//'), 'all', false, $CssInfo['Options']); } continue; } $AppFolder = $CssInfo['AppFolder']; $LookupFolder = !empty($AppFolder) ? $AppFolder : $this->ApplicationFolder; $Search = AssetModel::CssPath($CssFile, $LookupFolder, $ThemeType); if (!$Search) { continue; } list($Path, $UrlPath) = $Search; if (isUrl($Path)) { $this->Head->AddCss($Path, 'all', val('AddVersion', $Options, true), $Options); continue; } else { // Check to see if there is a CSS cacher. $CssCacher = Gdn::factory('CssCacher'); if (!is_null($CssCacher)) { $Path = $CssCacher->get($Path, $AppFolder); } if ($Path !== false) { $Path = substr($Path, strlen(PATH_ROOT)); $Path = str_replace(DS, '/', $Path); $this->Head->addCss($Path, 'all', true, $Options); } } } // Add a custom js file. if (arrayHasValue($this->_CssFiles, 'style.css')) { $this->addJsFile('custom.js'); // only to non-admin pages. } $Cdns = array(); if (!c('Garden.Cdns.Disable', false)) { $Cdns = array('jquery.js' => "//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"); } // And now search for/add all JS files. $this->EventArguments['Cdns'] =& $Cdns; $this->fireEvent('AfterJsCdns'); $this->Head->addScript('', 'text/javascript', false, array('content' => $this->definitionList(false))); foreach ($this->_JsFiles as $Index => $JsInfo) { $JsFile = $JsInfo['FileName']; if (!is_array($JsInfo['Options'])) { $JsInfo['Options'] = array(); } $Options =& $JsInfo['Options']; if (isset($Cdns[$JsFile])) { $JsFile = $Cdns[$JsFile]; } $AppFolder = $JsInfo['AppFolder']; $LookupFolder = !empty($AppFolder) ? $AppFolder : $this->ApplicationFolder; $Search = AssetModel::JsPath($JsFile, $LookupFolder, $ThemeType); if (!$Search) { continue; } list($Path, $UrlPath) = $Search; if ($Path !== false) { $AddVersion = true; if (!isUrl($Path)) { $Path = substr($Path, strlen(PATH_ROOT)); $Path = str_replace(DS, '/', $Path); $AddVersion = val('AddVersion', $Options, true); } $this->Head->addScript($Path, 'text/javascript', $AddVersion, $Options); continue; } } } // Add the favicon. $Favicon = C('Garden.FavIcon'); if ($Favicon) { $this->Head->setFavIcon(Gdn_Upload::url($Favicon)); } // Make sure the head module gets passed into the assets collection. $this->addModule('Head'); } // Master views come from one of four places: $MasterViewPaths = array(); if (strpos($this->MasterView, '/') !== false) { $MasterViewPaths[] = combinePaths(array(PATH_ROOT, str_replace('/', DS, $this->MasterView) . '.master*')); } else { if ($this->Theme) { // 1. Application-specific theme view. eg. root/themes/theme_name/app_name/views/ $MasterViewPaths[] = combinePaths(array(PATH_THEMES, $this->Theme, $this->ApplicationFolder, 'views', $this->MasterView . '.master*')); // 2. Garden-wide theme view. eg. /path/to/application/themes/theme_name/views/ $MasterViewPaths[] = combinePaths(array(PATH_THEMES, $this->Theme, 'views', $this->MasterView . '.master*')); } // 3. Plugin default. eg. root/plugin_name/views/ $MasterViewPaths[] = combinePaths(array(PATH_ROOT, $this->ApplicationFolder, 'views', $this->MasterView . '.master*')); // 4. Application default. eg. root/app_name/views/ $MasterViewPaths[] = combinePaths(array(PATH_APPLICATIONS, $this->ApplicationFolder, 'views', $this->MasterView . '.master*')); // 5. Garden default. eg. root/dashboard/views/ $MasterViewPaths[] = combinePaths(array(PATH_APPLICATIONS, 'dashboard', 'views', $this->MasterView . '.master*')); } // Find the first file that matches the path. $MasterViewPath = false; foreach ($MasterViewPaths as $Glob) { $Paths = safeGlob($Glob); if (is_array($Paths) && count($Paths) > 0) { $MasterViewPath = $Paths[0]; break; } } $this->EventArguments['MasterViewPath'] =& $MasterViewPath; $this->fireEvent('BeforeFetchMaster'); if ($MasterViewPath === false) { trigger_error(errorMessage("Could not find master view: {$this->MasterView}.master*", $this->ClassName, '_FetchController'), E_USER_ERROR); } /// A unique identifier that can be used in the body tag of the master view if needed. $ControllerName = $this->ClassName; // Strip "Controller" from the body identifier. if (substr($ControllerName, -10) == 'Controller') { $ControllerName = substr($ControllerName, 0, -10); } // Strip "Gdn_" from the body identifier. if (substr($ControllerName, 0, 4) == 'Gdn_') { $ControllerName = substr($ControllerName, 4); } $this->setData('CssClass', $this->Application . ' ' . $ControllerName . ' ' . $this->RequestMethod . ' ' . $this->CssClass, true); // Check to see if there is a handler for this particular extension. $ViewHandler = Gdn::factory('ViewHandler' . strtolower(strrchr($MasterViewPath, '.'))); if (is_null($ViewHandler)) { $BodyIdentifier = strtolower($this->ApplicationFolder . '_' . $ControllerName . '_' . Gdn_Format::alphaNumeric(strtolower($this->RequestMethod))); include $MasterViewPath; } else { $ViewHandler->render($MasterViewPath, $this); } }
/** * * * @param mixed &$Media * @param mixed $UserID * @return bool */ protected function placeMedia(&$Media, $UserID) { $NewFolder = FileUploadPlugin::findLocalMediaFolder($Media->MediaID, $UserID, true, false); $CurrentPath = array(); foreach ($NewFolder as $FolderPart) { array_push($CurrentPath, $FolderPart); $TestFolder = CombinePaths($CurrentPath); if (!is_dir($TestFolder) && !@mkdir($TestFolder, 0777, true)) { throw new Exception("Failed creating folder '{$TestFolder}' during PlaceMedia verification loop"); } } $FileParts = pathinfo($Media->Name); $SourceFilePath = combinePaths(array($this->pathUploads(), $Media->Path)); $NewFilePath = combinePaths(array($TestFolder, $Media->MediaID . '.' . $FileParts['extension'])); $Success = rename($SourceFilePath, $NewFilePath); if (!$Success) { throw new Exception("Failed renaming '{$SourceFilePath}' -> '{$NewFilePath}'"); } $NewFilePath = FileUploadPlugin::findLocalMedia($Media, false, true); $Media->Path = $NewFilePath; return true; }
/** * Returns the contents of the specified file, or FALSE if it does not * exist. */ public static function getContents() { $File = combinePaths(func_get_args()); if (file_exists($File) && is_file($File)) { return file_get_contents($File); } else { return false; } }
/** * Find the files associated with the theme. * * Please don't use this method. * * @param string $themePath The theme's path. * @return array|false Returns an array of paths or false if the {@link $themePath} is invalid. * @deprecated */ private function findThemeFilesOld($themePath) { if (!is_dir($themePath)) { return false; } $ThemeFiles = scandir($themePath); $TestPatterns = array('about\\.php' => 'about', '.*\\.theme\\.php' => 'about', 'class\\..*themehooks\\.php' => 'hooks', 'screenshot\\.(gif|jpg|jpeg|png)' => 'screenshot', 'mobile\\.(gif|jpg|jpeg|png)' => 'mobilescreenshot'); $MatchedThemeFiles = array(); foreach ($ThemeFiles as $ThemeFile) { foreach ($TestPatterns as $TestPattern => $FileType) { if (preg_match('!' . $TestPattern . '!', $ThemeFile)) { $MatchedThemeFiles[$FileType] = combinePaths(array($themePath, $ThemeFile)); } } } return array_key_exists('about', $MatchedThemeFiles) ? $MatchedThemeFiles : false; }
/** * Export avatars into vanilla-compatibles names */ public function doAvatars() { // Source table $sourceTable = $this->param('source', 'profile_portal'); // Check source folder $sourceFolder = $this->param('avatarpath'); if (!is_dir($sourceFolder)) { trigger_error("Source avatar folder '{$sourceFolder}' does not exist."); } // Set up a target folder $targetFolder = combinePaths(array($sourceFolder, 'ipb')); if (!is_dir($sourceFolder)) { @($made = mkdir($targetFolder, 0777, true)); if (!$made) { trigger_error("Target avatar folder '{$targetFolder}' could not be created."); } } switch ($sourceTable) { case 'profile_portal': $userList = $this->ex->query("select\n pp_member_id as member_id,\n pp_main_photo as main_photo,\n pp_thumb_photo as thumb_photo,\n coalesce(pp_main_photo,pp_thumb_photo,0) as photo\n from :_profile_portal\n where length(coalesce(pp_main_photo,pp_thumb_photo,0)) > 3\n order by pp_member_id asc"); break; case 'member_extra': $userList = $this->ex->query("select\n id as member_id,\n avatar_location as photo\n from :_member_extra\n where\n length(avatar_location) > 3 and\n avatar_location <> 'noavatar'\n order by id asc"); break; } $processed = 0; $skipped = 0; $completed = 0; $errors = array(); while (($row = mysql_fetch_assoc($userList)) !== false) { $processed++; $error = false; $userID = $row['member_id']; // Determine target paths and name $photo = trim($row['photo']); $photo = preg_replace('`^upload:`', '', $photo); if (preg_match('`^https?:`i', $photo)) { $skipped++; continue; } $photoFileName = basename($photo); $photoPath = dirname($photo); $photoFolder = combinePaths(array($targetFolder, $photoPath)); @mkdir($photoFolder, 0777, true); $photoSrc = combinePaths(array($sourceFolder, $photo)); if (!file_exists($photoSrc)) { $errors[] = "Missing file: {$photoSrc}"; continue; } $mainPhoto = trim(getValue('main_photo', $row, null)); $thumbPhoto = trim(getValue('thumb_photo', $row, null)); // Main Photo if (!$mainPhoto) { $mainPhoto = $photo; } $mainSrc = combinePaths(array($sourceFolder, $mainPhoto)); $mainDest = combinePaths(array($photoFolder, "p" . $photoFileName)); $copied = @copy($mainSrc, $mainDest); if (!$copied) { $error |= true; $errors[] = "! failed to copy main photo '{$mainSrc}' for user {$userID} (-> {$mainDest})."; } // Thumb Photo if (!$thumbPhoto) { $thumbPhoto = $photo; } $thumbSrc = combinePaths(array($sourceFolder, $mainPhoto)); $thumbDest = combinePaths(array($photoFolder, "n" . $photoFileName)); $copied = @copy($thumbSrc, $thumbDest); if (!$copied) { $error |= true; $errors[] = "! failed to copy thumbnail '{$thumbSrc}' for user {$userID} (-> {$thumbDest})."; } if (!$error) { $completed++; } if (!($processed % 100)) { echo " - processed {$processed}\n"; } } $nErrors = sizeof($errors); if ($nErrors) { echo "{$nErrors} errors:\n"; foreach ($errors as $error) { echo "{$error}\n"; } } echo "Completed: {$completed}\n"; echo "Skipped: {$skipped}\n"; }
/** * Run the database structure or /utility/structure. * * Note: Keep this method protected! * * @param string $appName Unique app name or 'all' (default). * @param bool $captureOnly Whether to list changes rather than execute (0 or 1). * @throws Exception */ protected function runStructure($appName = 'all', $captureOnly = true) { // This permission is run again to be sure someone doesn't accidentally call this method incorrectly. $this->permission('Garden.Settings.Manage'); $Files = array(); $appName = $appName == '' ? 'all' : $appName; if ($appName == 'all') { // Load all application structure files. $ApplicationManager = new Gdn_ApplicationManager(); $Apps = $ApplicationManager->enabledApplications(); $AppNames = array_column($Apps, 'Folder'); foreach ($AppNames as $appName) { $Files[] = combinePaths(array(PATH_APPLICATIONS, $appName, 'settings', 'structure.php'), DS); } $appName = 'all'; } else { // Load that specific application structure file. $Files[] = combinePaths(array(PATH_APPLICATIONS, $appName, 'settings', 'structure.php'), DS); } $Drop = false; $Explicit = false; $captureOnly = !($captureOnly == '0'); $Structure = Gdn::structure(); $Structure->CaptureOnly = $captureOnly; $SQL = Gdn::sql(); $SQL->CaptureModifications = $captureOnly; $this->setData('CaptureOnly', $Structure->CaptureOnly); $this->setData('Drop', $Drop); $this->setData('Explicit', $Explicit); $this->setData('ApplicationName', $appName); $this->setData('Status', ''); $FoundStructureFile = false; foreach ($Files as $File) { if (file_exists($File)) { $FoundStructureFile = true; try { include $File; } catch (Exception $Ex) { $this->Form->addError($Ex); } } } // Run the structure of all of the plugins. $Plugins = Gdn::pluginManager()->enabledPlugins(); foreach ($Plugins as $PluginKey => $Plugin) { $PluginInstance = Gdn::pluginManager()->getPluginInstance($PluginKey, Gdn_PluginManager::ACCESS_PLUGINNAME); if (method_exists($PluginInstance, 'Structure')) { $PluginInstance->structure(); } } if (property_exists($Structure->Database, 'CapturedSql')) { $this->setData('CapturedSql', (array) $Structure->Database->CapturedSql); } else { $this->setData('CapturedSql', array()); } if ($this->Form->errorCount() == 0 && !$captureOnly && $FoundStructureFile) { $this->setData('Status', 'The structure was successfully executed.'); } }
/** * Update database structure based on current definitions in each app's structure.php file. * * @since 2.0.? * @access public * @param string $AppName Unique app name or 'all' (default). * @param int $CaptureOnly Whether to list changes rather than execture (0 or 1). * @param int $Drop Whether to drop first (0 or 1). * @param int $Explicit Whether to force to only columns currently listed (0 or 1). */ public function structure($AppName = 'all', $CaptureOnly = '1', $Drop = '0', $Explicit = '0') { $this->permission('Garden.Settings.Manage'); $Files = array(); $AppName = $AppName == '' ? 'all' : $AppName; if ($AppName == 'all') { // Load all application structure files. $ApplicationManager = new Gdn_ApplicationManager(); $Apps = $ApplicationManager->enabledApplications(); $AppNames = array_column($Apps, 'Folder'); foreach ($AppNames as $AppName) { $Files[] = combinePaths(array(PATH_APPLICATIONS, $AppName, 'settings', 'structure.php'), DS); } $AppName = 'all'; } else { // Load that specific application structure file. $Files[] = combinePaths(array(PATH_APPLICATIONS, $AppName, 'settings', 'structure.php'), DS); } $Validation = new Gdn_Validation(); $Database = Gdn::database(); $Drop = $Drop == '0' ? false : true; $Explicit = $Explicit == '0' ? false : true; $CaptureOnly = !($CaptureOnly == '0'); $Structure = Gdn::structure(); $Structure->CaptureOnly = $CaptureOnly; $SQL = Gdn::sql(); $SQL->CaptureModifications = $CaptureOnly; $this->setData('CaptureOnly', $Structure->CaptureOnly); $this->setData('Drop', $Drop); $this->setData('Explicit', $Explicit); $this->setData('ApplicationName', $AppName); $this->setData('Status', ''); $FoundStructureFile = false; foreach ($Files as $File) { if (file_exists($File)) { $FoundStructureFile = true; try { include $File; } catch (Exception $Ex) { $this->Form->addError($Ex); } } } // Run the structure of all of the plugins. $Plugins = Gdn::pluginManager()->enabledPlugins(); foreach ($Plugins as $PluginKey => $Plugin) { $PluginInstance = Gdn::pluginManager()->getPluginInstance($PluginKey, Gdn_PluginManager::ACCESS_PLUGINNAME); if (method_exists($PluginInstance, 'Structure')) { $PluginInstance->structure(); } } if (property_exists($Structure->Database, 'CapturedSql')) { $this->setData('CapturedSql', (array) $Structure->Database->CapturedSql); } else { $this->setData('CapturedSql', array()); } if ($this->Form->errorCount() == 0 && !$CaptureOnly && $FoundStructureFile) { $this->setData('Status', 'The structure was successfully executed.'); } $this->addSideMenu('dashboard/settings/configure'); $this->addCssFile('admin.css'); $this->setData('Title', t('Database Structure Upgrades')); $this->render(); }
/** * @param SideMenuModule $Module * @param string $CurrentUrl */ public function buildEditMenu(&$Module, $CurrentUrl = '') { if (!$this->User) { return; } $Module->HtmlId = 'UserOptions'; $Module->AutoLinkGroups = false; $Session = Gdn::session(); $ViewingUserID = $Session->UserID; $Module->addItem('Options', '', false, array('class' => 'SideMenu')); // Check that we have the necessary tools to allow image uploading $AllowImages = c('Garden.Profile.EditPhotos', true) && Gdn_UploadImage::canUploadImages(); // Is the photo hosted remotely? $RemotePhoto = isUrl($this->User->Photo); if ($this->User->UserID != $ViewingUserID) { // Include user js files for people with edit users permissions if (checkPermission('Garden.Users.Edit') || checkPermission('Moderation.Profiles.Edit')) { // $this->addJsFile('jquery.gardenmorepager.js'); $this->addJsFile('user.js'); } $Module->addLink('Options', sprite('SpProfile') . ' ' . t('Edit Profile'), userUrl($this->User, '', 'edit'), array('Garden.Users.Edit', 'Moderation.Profiles.Edit'), array('class' => 'Popup EditAccountLink')); $Module->addLink('Options', sprite('SpProfile') . ' ' . t('Edit Account'), '/user/edit/' . $this->User->UserID, 'Garden.Users.Edit', array('class' => 'Popup EditAccountLink')); $Module->addLink('Options', sprite('SpDelete') . ' ' . t('Delete Account'), '/user/delete/' . $this->User->UserID, 'Garden.Users.Delete', array('class' => 'Popup DeleteAccountLink')); if ($this->User->Photo != '' && $AllowImages) { $Module->addLink('Options', sprite('SpDelete') . ' ' . t('Remove Picture'), combinePaths(array(userUrl($this->User, '', 'removepicture'), $Session->transientKey())), array('Garden.Users.Edit', 'Moderation.Profiles.Edit'), array('class' => 'RemovePictureLink')); } $Module->addLink('Options', sprite('SpPreferences') . ' ' . t('Edit Preferences'), userUrl($this->User, '', 'preferences'), array('Garden.Users.Edit', 'Moderation.Profiles.Edit'), array('class' => 'Popup PreferencesLink')); // Add profile options for everyone $Module->addLink('Options', sprite('SpPicture') . ' ' . t('Change Picture'), userUrl($this->User, '', 'picture'), array('Garden.Users.Edit', 'Moderation.Profiles.Edit'), array('class' => 'PictureLink')); if ($this->User->Photo != '' && $AllowImages && !$RemotePhoto) { $Module->addLink('Options', sprite('SpThumbnail') . ' ' . t('Edit Thumbnail'), userUrl($this->User, '', 'thumbnail'), array('Garden.Users.Edit', 'Moderation.Profiles.Edit'), array('class' => 'ThumbnailLink')); } } else { if (hasEditProfile($this->User->UserID)) { $Module->addLink('Options', sprite('SpEdit') . ' ' . t('Edit Profile'), '/profile/edit', false, array('class' => 'Popup EditAccountLink')); } // Add profile options for the profile owner // Don't allow account editing if it has been turned off. // Don't allow password editing if using SSO Connect ONLY. // This is for security. We encountered the case where a customer charges // for membership using their external application and use SSO to let // their customers into Vanilla. If you allow those people to change their // password in Vanilla, they will then be able to log into Vanilla using // Vanilla's login form regardless of the state of their membership in the // external app. if (c('Garden.UserAccount.AllowEdit') && c('Garden.Registration.Method') != 'Connect') { // No password may have been set if they have only signed in with a connect plugin $PasswordLabel = t('Change My Password'); if ($this->User->HashMethod && $this->User->HashMethod != "Vanilla") { $PasswordLabel = t('Set A Password'); } $Module->addLink('Options', sprite('SpPassword') . ' ' . $PasswordLabel, '/profile/password', false, array('class' => 'Popup PasswordLink')); } $Module->addLink('Options', sprite('SpPreferences') . ' ' . t('Notification Preferences'), userUrl($this->User, '', 'preferences'), false, array('class' => 'Popup PreferencesLink')); if ($AllowImages) { $Module->addLink('Options', sprite('SpPicture') . ' ' . t('Change My Picture'), '/profile/picture', array('Garden.Profiles.Edit', 'Garden.ProfilePicture.Edit'), array('class' => 'PictureLink')); } if ($this->User->Photo != '' && $AllowImages && !$RemotePhoto) { $Module->addLink('Options', sprite('SpThumbnail') . ' ' . t('Edit My Thumbnail'), '/profile/thumbnail', array('Garden.Profiles.Edit', 'Garden.ProfilePicture.Edit'), array('class' => 'ThumbnailLink')); } } if ($this->User->UserID == $ViewingUserID || $Session->checkPermission('Garden.Users.Edit')) { $this->setData('Connections', array()); $this->EventArguments['User'] = $this->User; $this->fireEvent('GetConnections'); if (count($this->data('Connections')) > 0) { $Module->addLink('Options', sprite('SpConnection') . ' ' . t('Social'), '/profile/connections', 'Garden.SignIn.Allow'); } } }
/** * Save the addon data. * * @param array $Stub * @param bool|array $Settings Not used; for signature compatibility. * @return bool|Gdn_DataSet|mixed|object|string */ public function save($Stub, $Settings = false) { trace('AddonModel->Save()'); $Session = Gdn::session(); $this->defineSchema(); // Most of the values come from the file itself. if (isset($Stub['Path'])) { $Path = $Stub['Path']; } elseif (val('Checked', $Stub)) { $Addon = $Stub; } elseif (isset($Stub['File'])) { $Path = combinePaths(array(PATH_UPLOADS, $Stub['File'])); } else { if (!$Session->checkPermission('Addons.Addon.Manage') && isset($Stub['Filename'])) { // Only admins can modify plugin attributes without the file. $this->Validation->addValidationResult('Filename', 'ValidateRequired'); return false; } } // Analyze and fix the file. if (!isset($Addon)) { if (isset($Path)) { try { $Addon = UpdateModel::analyzeAddon($Path, false); } catch (Exception $Ex) { $Addon = false; $this->Validation->addValidationResult('File', '@' . $Ex->getMessage()); } if (!is_array($Addon)) { $this->Validation->addValidationResult('File', 'Could not analyze the addon file.'); return false; } $Addon = array_merge($Stub, $Addon); } else { $Addon = $Stub; if (isset($Path)) { $Addon['MD5'] = md5_file($Path); $Addon['FileSize'] = filesize($Path); } } } // Get an existing addon. if (isset($Addon['AddonID'])) { $CurrentAddon = $this->getID($Addon['AddonID'], false, ['GetVersions' => true]); } elseif (isset($Addon['AddonKey']) && isset($Addon['AddonTypeID'])) { $CurrentAddon = $this->getID(array($Addon['AddonKey'], $Addon['AddonTypeID']), false, ['GetVersions' => true]); } else { $CurrentAddon = false; } trace($CurrentAddon, 'CurrentAddon'); $Insert = !$CurrentAddon; if ($Insert) { $this->addInsertFields($Addon); } $this->addUpdateFields($Addon); // always add update fields if (!$this->validate($Addon, $Insert)) { trace('Addon did not validate'); return false; } // Search for the current version. $MaxVersion = false; $CurrentVersion = false; if ($CurrentAddon && isset($Addon['Version'])) { // Search for a current version. foreach ($CurrentAddon['Versions'] as $Index => $Version) { if (isset($Addon['AddonVersionID'])) { if ($Addon['AddonVersionID'] == $Version['AddonVersionID']) { $CurrentVersion = $Version; } } elseif (version_compare($Addon['Version'], $Version['Version']) == 0) { $CurrentVersion = $Version; } // Only check for a current version if the version has been checked. if (!$Version['Checked']) { continue; } if (!$MaxVersion || version_compare($MaxVersion['Version'], $Version['Version'], '<')) { $MaxVersion = $Version; } } } // Save the addon. $Fields = $this->filterSchema($Addon); if ($Insert) { $AddonID = $this->SQL->insert($this->Name, $Fields); // Add the activity. $ActivityModel = new ActivityModel(); $Activity = array('ActivityType' => 'Addon', 'ActivityUserID' => $Fields['InsertUserID'], 'NotifyUserID' => ActivityModel::NOTIFY_PUBLIC, 'HeadlineFormat' => '{ActivityUserID,user} added the <a href="{Url,html}">{Data.Name}</a> addon.', 'Story' => Gdn_Format::html($Fields['Description']), 'Route' => '/addon/' . rawurlencode(self::slug($Fields, false)), 'Data' => array('Name' => $Fields['Name'])); $ActivityModel->save($Activity); } else { $AddonID = val('AddonID', $CurrentAddon); // Only save the addon if it is the current version. if (!$MaxVersion || version_compare($Addon['Version'], $MaxVersion['Version'], '>=')) { trace('Uploaded version is the most recent version.'); $this->SQL->put($this->Name, $Fields, array('AddonID' => $AddonID)); } else { $this->SQL->reset(); } } // Save the version. if ($AddonID && isset($Path) || isset($Addon['File'])) { trace('Saving addon version'); $Addon['AddonID'] = $AddonID; if (isset($Path)) { if (!stringBeginsWith($Path, PATH_UPLOADS . '/addons/')) { // The addon must be copied into the uploads folder. $NewPath = PATH_UPLOADS . '/addons/' . basename($Path); //rename($Path, $NewPath); $Path = $NewPath; $this->_AddonCache = array(); } $File = substr($Path, strlen(PATH_UPLOADS . '/')); $Addon['File'] = $File; } if ($CurrentVersion) { $Addon['AddonVersionID'] = val('AddonVersionID', $CurrentVersion); } // Insert or update the version. $VersionModel = new Gdn_Model('AddonVersion'); $AddonVersionID = $VersionModel->save($Addon); $this->Validation->addValidationResult($VersionModel->validationResults()); if (!$AddonVersionID) { return false; } // Update the current version in the addon. if (!$MaxVersion || version_compare($CurrentAddon['Version'], $Addon['Version'], '<')) { $this->SQL->put($this->Name, array('CurrentAddonVersionID' => $AddonVersionID), array('AddonID' => $AddonID)); } } $this->_AddonCache = array(); return $AddonID; }
protected function avatarFolder($folder, $type, &$errors) { if (!is_dir($folder)) { trigger_error("Target avatar folder '{$folder}' does not exist."); } $resFolder = opendir($folder); $errors = array(); while (($file = readdir($resFolder)) !== false) { if ($file == '.' || $file == '..') { continue; } $fullPath = combinePaths(array($folder, $file)); // Folder? Recurse if (is_dir($fullPath)) { $this->avatarFolder($fullPath, $type, $errors); continue; } $this->processed++; // Determine target paths and name $photo = trim($file); $photoSrc = combinePaths(array($folder, $photo)); $photoFileName = basename($photoSrc); $photoPath = dirname($photoSrc); $stubFolder = getValue($type, $this->folders); $trimFolder = combinePaths(array($this->sourceFolder, $stubFolder)); $photoPath = str_replace($trimFolder, '', $photoPath); $photoFolder = combinePaths(array($this->targetFolder, $photoPath)); @mkdir($photoFolder, 0777, true); if (!file_exists($photoSrc)) { $errors[] = "Missing file: {$photoSrc}"; continue; } $typePrefix = getValue($type, $this->types); $photoDest = combinePaths(array($photoFolder, "{$typePrefix}{$photoFileName}")); $copied = @copy($photoSrc, $photoDest); if (!$copied) { $errors[] = "! failed to copy photo '{$photoSrc}' (-> {$photoDest})."; } if (!($this->processed % 100)) { echo " - processed {$this->processed}\n"; } } }
/** * * * @param $Path * @param bool $Text * @param null $Format * @param array $Options * @return mixed|null|string */ public static function link($Path, $Text = false, $Format = null, $Options = array()) { $Session = Gdn::session(); $Class = val('class', $Options, ''); $WithDomain = val('WithDomain', $Options); $Target = val('Target', $Options, ''); if ($Target == 'current') { $Target = trim(url('', true), '/ '); } if (is_null($Format)) { $Format = '<a href="%url" class="%class">%text</a>'; } switch ($Path) { case 'activity': touchValue('Permissions', $Options, 'Garden.Activity.View'); break; case 'category': $Breadcrumbs = Gdn::controller()->data('Breadcrumbs'); if (is_array($Breadcrumbs) && count($Breadcrumbs) > 0) { $Last = array_pop($Breadcrumbs); $Path = val('Url', $Last); $DefaultText = val('Name', $Last, T('Back')); } else { $Path = '/'; $DefaultText = c('Garden.Title', T('Back')); } if (!$Text) { $Text = $DefaultText; } break; case 'dashboard': $Path = 'dashboard/settings'; touchValue('Permissions', $Options, array('Garden.Settings.Manage', 'Garden.Settings.View')); if (!$Text) { $Text = t('Dashboard'); } break; case 'home': $Path = '/'; if (!$Text) { $Text = t('Home'); } break; case 'inbox': $Path = 'messages/inbox'; touchValue('Permissions', $Options, 'Garden.SignIn.Allow'); if (!$Text) { $Text = t('Inbox'); } if ($Session->isValid() && $Session->User->CountUnreadConversations) { $Class = trim($Class . ' HasCount'); $Text .= ' <span class="Alert">' . $Session->User->CountUnreadConversations . '</span>'; } if (!$Session->isValid() || !Gdn::applicationManager()->checkApplication('Conversations')) { $Text = false; } break; case 'forumroot': $Route = Gdn::router()->getDestination('DefaultForumRoot'); if (is_null($Route)) { $Path = '/'; } else { $Path = combinePaths(array('/', $Route)); } break; case 'profile': touchValue('Permissions', $Options, 'Garden.SignIn.Allow'); if (!$Text && $Session->isValid()) { $Text = $Session->User->Name; } if ($Session->isValid() && $Session->User->CountNotifications) { $Class = trim($Class . ' HasCount'); $Text .= ' <span class="Alert">' . $Session->User->CountNotifications . '</span>'; } break; case 'user': $Path = 'profile'; touchValue('Permissions', $Options, 'Garden.SignIn.Allow'); if (!$Text && $Session->isValid()) { $Text = $Session->User->Name; } break; case 'photo': $Path = 'profile'; TouchValue('Permissions', $Options, 'Garden.SignIn.Allow'); if (!$Text && $Session->isValid()) { $IsFullPath = strtolower(substr($Session->User->Photo, 0, 7)) == 'http://' || strtolower(substr($Session->User->Photo, 0, 8)) == 'https://'; $PhotoUrl = $IsFullPath ? $Session->User->Photo : Gdn_Upload::url(changeBasename($Session->User->Photo, 'n%s')); $Text = img($PhotoUrl, array('alt' => $Session->User->Name)); } break; case 'drafts': TouchValue('Permissions', $Options, 'Garden.SignIn.Allow'); if (!$Text) { $Text = t('My Drafts'); } if ($Session->isValid() && $Session->User->CountDrafts) { $Class = trim($Class . ' HasCount'); $Text .= ' <span class="Alert">' . $Session->User->CountDrafts . '</span>'; } break; case 'discussions/bookmarked': TouchValue('Permissions', $Options, 'Garden.SignIn.Allow'); if (!$Text) { $Text = t('My Bookmarks'); } if ($Session->isValid() && $Session->User->CountBookmarks) { $Class = trim($Class . ' HasCount'); $Text .= ' <span class="Count">' . $Session->User->CountBookmarks . '</span>'; } break; case 'discussions/mine': TouchValue('Permissions', $Options, 'Garden.SignIn.Allow'); if (!$Text) { $Text = t('My Discussions'); } if ($Session->isValid() && $Session->User->CountDiscussions) { $Class = trim($Class . ' HasCount'); $Text .= ' <span class="Count">' . $Session->User->CountDiscussions . '</span>'; } break; case 'register': if (!$Text) { $Text = t('Register'); } $Path = registerUrl($Target); break; case 'signin': case 'signinout': // The destination is the signin/signout toggle link. if ($Session->isValid()) { if (!$Text) { $Text = T('Sign Out'); } $Path = signOutUrl($Target); $Class = concatSep(' ', $Class, 'SignOut'); } else { if (!$Text) { $Text = t('Sign In'); } $Path = signInUrl($Target); if (signInPopup() && strpos(Gdn::Request()->Url(), 'entry') === false) { $Class = concatSep(' ', $Class, 'SignInPopup'); } } break; } if ($Text == false && strpos($Format, '%text') !== false) { return ''; } if (val('Permissions', $Options) && !$Session->checkPermission($Options['Permissions'], false)) { return ''; } $Url = Gdn::request()->url($Path, $WithDomain); if ($TK = val('TK', $Options)) { if (in_array($TK, array(1, 'true'))) { $TK = 'TransientKey'; } $Url .= (strpos($Url, '?') === false ? '?' : '&') . $TK . '=' . urlencode(Gdn::session()->transientKey()); } if (strcasecmp(trim($Path, '/'), Gdn::request()->path()) == 0) { $Class = concatSep(' ', $Class, 'Selected'); } // Build the final result. $Result = $Format; $Result = str_replace('%url', $Url, $Result); $Result = str_replace('%text', $Text, $Result); $Result = str_replace('%class', $Class, $Result); return $Result; }
/** * Converts addon info into a media item. * * @param $addonName * @param $addonInfo * @param $isEnabled * @param $addonType * @param $filter */ function writeAddonMedia($addonName, $addonInfo, $isEnabled, $addonType, $filter) { $capitalCaseSheme = new \Vanilla\Utility\CapitalCaseScheme(); $addonInfo = $capitalCaseSheme->convertArrayKeys($addonInfo, ['RegisterPermissions']); $screenName = Gdn_Format::display(val('Name', $addonInfo, $addonName)); $description = Gdn_Format::html(t(val('Name', $addonInfo, $addonName) . ' Description', val('Description', $addonInfo, ''))); $id = Gdn_Format::url($addonName) . '-addon'; $media = new MediaItemModule($screenName, '', $description, 'li', ['id' => $id]); $media->setView('media-addon'); // Icon $addon = Gdn::addonManager()->lookupAddon($addonName); $iconPath = ''; if ($addon) { $iconPath = $addon->getIcon(); } if (!$iconPath) { $iconPath = val('IconUrl', $addonInfo, 'applications/dashboard/design/images/addon-placeholder.png'); } $media->setImage($iconPath); // Settings button $settingsUrl = $isEnabled ? val('SettingsUrl', $addonInfo, '') : ''; $settingsPopupClass = val('UsePopupSettings', $addonInfo, true) ? ' js-modal' : ''; if ($settingsUrl != '') { $attr['class'] = 'btn btn-icon-border' . $settingsPopupClass; $attr['aria-label'] = sprintf(t('Settings for %s'), $screenName); $attr['data-reload-page-on-save'] = false; $media->addButton(dashboardSymbol('settings'), $settingsUrl, $attr); } // Toggle if ($addonType === 'locales') { $action = $isEnabled ? 'disable' : 'enable'; } else { $action = $filter; } if ($isEnabled) { $label = sprintf(t('Disable %s'), $screenName); } else { $label = sprintf(t('Enable %s'), $screenName); } $url = '/settings/' . $addonType . '/' . $action . '/' . $addonName; $media->setToggle(slugify($addonName), $isEnabled, $url, $label); // Meta $info = []; // Requirements $requiredApplications = val('RequiredApplications', $addonInfo, false); $requiredPlugins = val('RequiredPlugins', $addonInfo, false); $requirements = []; if (is_array($requiredApplications)) { foreach ($requiredApplications as $requiredApplication => $versionInfo) { $requirements[] = sprintf(t('%1$s Version %2$s'), $requiredApplication, $versionInfo); } } if (is_array($requiredPlugins)) { foreach ($requiredPlugins as $requiredPlugin => $versionInfo) { $requirements[] = sprintf(t('%1$s Version %2$s'), $requiredPlugin, $versionInfo); } } if (!empty($requirements)) { $requirementsMeta = sprintf(t('Requires: %s'), implode(', ', $requirements)); $info[] = $requirementsMeta; } // Authors $author = val('Author', $addonInfo, ''); $authors = []; // Check if singular author is set if ($author) { $authorUrl = val('AuthorUrl', $addonInfo, ''); if ($authorUrl) { $authors[] = anchor($author, $authorUrl); } else { $authors[] = $author; } } // Check for multiple authors foreach (val('Authors', $addonInfo, []) as $author) { if (val('Homepage', $author)) { $authors[] = anchor(val('Name', $author), val('Homepage', $author)); } else { $authors[] = val('Name', $author); } } if ($authors) { $authors = implode(', ', $authors); $info[] = sprintf(t('Created by %s'), $authors); } // Version Info $version = Gdn_Format::display(val('Version', $addonInfo, '')); $newVersion = val('NewVersion', $addonInfo, ''); $upgrade = $newVersion != '' && version_compare($newVersion, $version, '>'); if ($version != '') { $info[] = sprintf(t('Version %s'), $version); } $pluginUrl = val('PluginUrl', $addonInfo, ''); if ($upgrade && $pluginUrl) { $info[] = anchor(printf(t('%1$s version %2$s is available.'), $screenName, $newVersion), combinePaths(array($pluginUrl, 'find', urlencode($screenName)), '/')); } if ($pluginUrl != '') { $info[] = anchor(t('Visit Site'), $pluginUrl); } // Extra meta in addon array if ($meta = val('Meta', $addonInfo)) { foreach ($meta as $key => $value) { if (is_numeric($key)) { $info[] = $value; } else { $info[] = t($key) . ': ' . $value; } } } $media->setMeta($info); echo $media; }
/** * Database & config changes to be done upon enable. * * @since 2.0.0 * @access public */ public function setup() { $Database = Gdn::database(); $Config = Gdn::factory(Gdn::AliasConfig); $Drop = false; //c('Conversations.Version') === FALSE ? TRUE : FALSE; $Validation = new Gdn_Validation(); // This is going to be needed by structure.php to validate permission names include PATH_APPLICATIONS . DS . 'conversations' . DS . 'settings' . DS . 'structure.php'; include PATH_APPLICATIONS . DS . 'conversations' . DS . 'settings' . DS . 'stub.php'; $ApplicationInfo = array(); include combinePaths(array(PATH_APPLICATIONS . DS . 'conversations' . DS . 'settings' . DS . 'about.php')); $Version = val('Version', val('Conversations', $ApplicationInfo, array()), 'Undefined'); saveToConfig('Conversations.Version', $Version); }
/** * Make an application's classes available to the autoloader. * * @param string $Application The name of the application. */ public static function attachApplication($Application) { $ApplicationPath = combinePaths(array(PATH_APPLICATIONS . "/{$Application}")); $AppControllers = combinePaths(array($ApplicationPath . "/controllers")); self::registerMap(self::MAP_CONTROLLER, self::CONTEXT_APPLICATION, $AppControllers, array('SearchSubfolders' => false, 'Extension' => $Application)); $AppModels = combinePaths(array($ApplicationPath . "/models")); self::registerMap(self::MAP_LIBRARY, self::CONTEXT_APPLICATION, $AppModels, array('SearchSubfolders' => false, 'Extension' => $Application, 'ClassFilter' => '*model')); $AppModules = combinePaths(array($ApplicationPath . "/modules")); self::registerMap(self::MAP_LIBRARY, self::CONTEXT_APPLICATION, $AppModules, array('SearchSubfolders' => false, 'Extension' => $Application, 'ClassFilter' => '*module')); $AppLibrary = combinePaths(array($ApplicationPath . "/library")); self::registerMap(self::MAP_LIBRARY, self::CONTEXT_APPLICATION, $AppLibrary, array('SearchSubfolders' => false, 'Extension' => $Application, 'ClassFilter' => '*')); }