/** * Override the default index method of the settings controller in the * dashboard application to render new statistics. */ public function StatsDashboard($Sender) { $StatsUrl = $this->AnalyticsServer; if (!StringBeginsWith($StatsUrl, 'http:') && !StringBeginsWith($StatsUrl, 'https:')) { $StatsUrl = Gdn::Request()->Scheme() . "://{$StatsUrl}"; } // Tell the page where to find the Vanilla Analytics provider $Sender->AddDefinition('VanillaStatsUrl', $StatsUrl); $Sender->SetData('VanillaStatsUrl', $StatsUrl); // Load javascript & css, check permissions, and load side menu for this page. $Sender->AddJsFile('settings.js'); $Sender->Title(T('Dashboard')); $Sender->RequiredAdminPermissions[] = 'Garden.Settings.Manage'; $Sender->RequiredAdminPermissions[] = 'Garden.Users.Add'; $Sender->RequiredAdminPermissions[] = 'Garden.Users.Edit'; $Sender->RequiredAdminPermissions[] = 'Garden.Users.Delete'; $Sender->RequiredAdminPermissions[] = 'Garden.Users.Approve'; $Sender->FireEvent('DefineAdminPermissions'); $Sender->Permission($Sender->RequiredAdminPermissions, '', FALSE); $Sender->AddSideMenu('dashboard/settings'); if (!Gdn_Statistics::CheckIsEnabled() && Gdn_Statistics::CheckIsLocalhost()) { $Sender->Render('dashboardlocalhost', '', 'plugins/VanillaStats'); } else { $Sender->AddJsFile('plugins/VanillaStats/js/vanillastats.js'); $Sender->AddJsFile('plugins/VanillaStats/js/picker.js'); $Sender->AddCSSFile('plugins/VanillaStats/design/picker.css'); $this->ConfigureRange($Sender); $VanillaID = Gdn::InstallationID(); $Sender->SetData('VanillaID', $VanillaID); $Sender->SetData('VanillaVersion', APPLICATION_VERSION); $Sender->SetData('SecurityToken', $this->SecurityToken()); // Render the custom dashboard view $Sender->Render('dashboard', '', 'plugins/VanillaStats'); } }
public function Page($Reference) { $PageModel = new PageModel(); $Page = $PageModel->GetFullID($Reference); if (!$Page) { throw NotFoundException(); } $this->Page = $Page; if ($this->Head) { SetMetaTags($Page, $this); if ($Page->CustomCss) { $CustomCss = "\n" . $Page->CustomCss; if (!StringBeginsWith(trim($CustomCss), '<style', True)) { $CustomCss = Wrap($CustomCss, 'style', array('type' => 'text/css')); } $this->Head->AddString($CustomCss); } if ($Page->CustomJs) { $CustomJs = $Page->CustomJs; if (!StringBeginsWith(trim($CustomJs), '<script', True)) { $CustomJs = Wrap($CustomJs, 'script', array('type' => 'text/javascript')); } $this->Head->AddString($CustomJs); } } if ($Page->SectionID) { $this->Section = BuildNode($Page, 'Section'); $this->SectionID = $Page->SectionID; CandyHooks::AddModules($this, $this->Section); } $this->FireEvent('ContentPage'); if ($Page->View) { $this->View = $this->FetchViewLocation($this->View, False, False, False); } if (!$this->View) { $this->View = $this->FetchViewLocation('view', 'page', '', False); if (!$this->View) { $this->View = 'default'; } } $this->Title($Page->Title); $this->SetData('Content', $Page, True); $this->EventArguments['Format'] =& $Page->Format; $this->EventArguments['Body'] =& $Page->Body; $this->FireEvent('BeforeBodyFormat'); $this->ContentBodyHtml = Gdn_Format::To($Page->Body, $Page->Format); $Doc = PqDocument($this->ContentBodyHtml); $Header = $Doc->Find('h1'); $CountH1 = count($Header); if ($CountH1 == 0) { $this->SetData('Headline', Gdn_Format::Text($Page->Title)); } elseif ($CountH1 == 1) { $this->SetData('Headline', $Header->Text()); $Header->Remove(); $this->ContentBodyHtml = $Doc->Html(); } // $this->AddModule('PageInfoModule'); $this->Render(); }
/** * Manage the current ranks and add new ones */ public function Settings() { $this->Permission('Yaga.Ranks.Manage'); $this->AddSideMenu('rank/settings'); $this->Title(T('Yaga.Ranks.Manage')); // Get list of ranks from the model and pass to the view $this->SetData('Ranks', $this->RankModel->Get()); if ($this->Form->IsPostBack() == TRUE) { // Handle the photo upload $Upload = new Gdn_Upload(); $TmpImage = $Upload->ValidateUpload('PhotoUpload', FALSE); if ($TmpImage) { // Generate the target image name $TargetImage = $Upload->GenerateTargetName(PATH_UPLOADS); $ImageBaseName = pathinfo($TargetImage, PATHINFO_BASENAME); // Save the uploaded image $Parts = $Upload->SaveAs($TmpImage, 'yaga' . DS . $ImageBaseName); $RelativeUrl = StringBeginsWith($Parts['Url'], Gdn_Url::WebRoot(TRUE), TRUE, TRUE); SaveToConfig('Yaga.Ranks.Photo', $RelativeUrl); if (C('Yaga.Ranks.Photo') == $Parts['SaveName']) { $this->InformMessage(T('Yaga.Rank.PhotoUploaded')); } } } include_once $this->FetchViewLocation('helper_functions', 'rank'); $this->Render(); }
/** * * @param array $Links An array of arrays with the following keys: * - Text: The text of the link. * - Url: The url of the link. * @param string|array $CssClass The css class of the link. This can be a two-item array where the second element will be added to the buttons. * @param string|false $Default The url of the default link. * @since 2.1 */ function ButtonGroup($Links, $CssClass = 'Button', $Default = FALSE) { if (!is_array($Links) || count($Links) < 1) { return; } $Text = $Links[0]['Text']; $Url = $Links[0]['Url']; $ButtonClass = ''; if (is_array($CssClass)) { list($CssClass, $ButtonClass) = $CssClass; } if ($Default) { // Find the default button. $Default = ltrim($Default, '/'); foreach ($Links as $Link) { if (StringBeginsWith(ltrim($Link['Url'], '/'), $Default)) { $Text = $Link['Text']; $Url = $Link['Url']; break; } } } if (count($Links) < 2) { echo Anchor($Text, $Url, $CssClass); } else { // NavButton or Button? $ButtonClass = ConcatSep(' ', $ButtonClass, strpos($CssClass, 'NavButton') !== FALSE ? 'NavButton' : 'Button'); if (strpos($CssClass, 'Primary') !== FALSE) { $ButtonClass .= ' Primary'; } // Strip "Button" or "NavButton" off the group class. echo '<div class="ButtonGroup ' . str_replace(array('NavButton', 'Button'), array('', ''), $CssClass) . '">'; echo Anchor($Text, $Url, $ButtonClass); echo Anchor(Sprite('SpDropdownHandle'), '#', $ButtonClass . ' Handle'); echo '<ul class="Dropdown MenuItems">'; foreach ($Links as $Link) { echo Wrap(Anchor($Link['Text'], $Link['Url'], GetValue('CssClass', $Link, '')), 'li'); } echo '</ul>'; echo '</div>'; } }
/** * Save mask information. * * @param array $PostValues * @param mixed $Validation. */ public static function SaveMaskInfo($PostValues, $Validation = False) { $MaskValues = array(); foreach ($PostValues as $Key => $Value) { if (StringBeginsWith($Key, 'Mask_')) { $MaskValues[$Value] = GetValue('Description_' . $Value, $PostValues); } } $NewMaskValues = array_combine($PostValues['Mask'], $PostValues['Description']); $MaskValues = $MaskValues + $NewMaskValues; $Data = array(); foreach ($MaskValues as $Int => $Description) { $Int = sprintf('%u', $Int); if ($Int > 0 && !($Int & $Int - 1)) { $Data[$Int] = $Description; } } K('Candy.Mask.Info', $Data); return True; }
public function CalculateRow(&$Row) { $ActivityType = self::GetActivityType($Row['ActivityTypeID']); $Row['ActivityType'] = GetValue('Name', $ActivityType); if (is_string($Row['Data'])) { $Row['Data'] = @unserialize($Row['Data']); } $Row['PhotoUrl'] = Url($Row['Route'], TRUE); if (!$Row['Photo']) { if (isset($Row['ActivityPhoto'])) { $Row['Photo'] = $Row['ActivityPhoto']; $Row['PhotoUrl'] = UserUrl($Row, 'Activity'); } else { $User = Gdn::UserModel()->GetID($Row['ActivityUserID'], DATASET_TYPE_ARRAY); if ($User) { $Photo = $User['Photo']; $Row['PhotoUrl'] = UserUrl($User); if (!$Photo || StringBeginsWith($Photo, 'http')) { $Row['Photo'] = $Photo; } else { $Row['Photo'] = Gdn_Upload::Url(ChangeBasename($Photo, 'n%s')); } } } } $Data = $Row['Data']; if (isset($Data['ActivityUserIDs'])) { $Row['ActivityUserID'] = array_merge(array($Row['ActivityUserID']), $Data['ActivityUserIDs']); } if (isset($Data['RegardingUserIDs'])) { $Row['RegardingUserID'] = array_merge(array($Row['RegardingUserID']), $Data['RegardingUserIDs']); } $Row['Url'] = ExternalUrl($Row['Route']); if ($Row['HeadlineFormat']) { $Row['Headline'] = FormatString($Row['HeadlineFormat'], $Row); } else { $Row['Headline'] = Gdn_Format::ActivityHeadline($Row); } }
public static function Parse($Name) { $Result = FALSE; $Name = str_replace('\\', '/', $Name); if (preg_match('`^https?://`', $Name)) { $Result = array('Name' => $Name, 'Type' => 'external', 'SaveName' => $Name, 'SaveFormat' => '%s', 'Url' => $Name); return $Result; } elseif (StringBeginsWith($Name, PATH_UPLOADS)) { $Name = ltrim(substr($Name, strlen(PATH_UPLOADS)), '/'); // This is an upload. $Result = array('Name' => $Name, 'Type' => '', 'SaveName' => $Name, 'SaveFormat' => '%s'); } elseif (preg_match('`^~([^/]*)/(.*)$`', $Name, $Matches)) { // The first part of the name tells us the type. $Type = $Matches[1]; $Name = $Matches[2]; $Result = array('Name' => $Name, 'Type' => $Type, 'SaveName' => "~{$Type}/{$Name}", 'SaveFormat' => "~{$Type}/%s"); } else { $Name = ltrim($Name, '/'); // This is an upload in the uploads folder. $Result = array('Name' => $Name, 'Type' => '', 'SaveName' => $Name, 'SaveFormat' => '%s'); } $UrlPrefix = self::Urls($Result['Type']); if ($UrlPrefix === FALSE) { $Result['Url'] = FALSE; } else { $Result['Url'] = $UrlPrefix . '/' . $Result['Name']; } return $Result; }
/** * Main import page. * * @since 2.0.0 * @access public */ public function Index() { $this->Permission('Garden.Import'); // This permission doesn't exist, so only users with Admin == '1' will succeed. $Timer = new Gdn_Timer(); // Determine the current step. $this->Form = new Gdn_Form(); $Imp = new ImportModel(); $Imp->LoadState(); // Search for the list of acceptable imports. $ImportPaths = array(); $ExistingPaths = SafeGlob(PATH_ROOT . '/uploads/export*', array('gz', 'txt')); foreach ($ExistingPaths as $Path) { $ImportPaths[$Path] = basename($Path); } // Add the database as a path. $ImportPaths = array_merge(array('db:' => T('This Database')), $ImportPaths); if ($Imp->CurrentStep < 1) { // Check to see if there is a file. $ImportPath = C('Garden.Import.ImportPath'); $Validation = new Gdn_Validation(); if (strcasecmp(Gdn::Request()->RequestMethod(), 'post') == 0) { $Upload = new Gdn_Upload(); $Validation = new Gdn_Validation(); if (count($ImportPaths) > 0) { $Validation->ApplyRule('PathSelect', 'Required', T('You must select a file to import.')); } if (count($ImportPaths) == 0 || $this->Form->GetFormValue('PathSelect') == 'NEW') { $TmpFile = $Upload->ValidateUpload('ImportFile', FALSE); } else { $TmpFile = ''; } if ($TmpFile) { $Filename = $_FILES['ImportFile']['name']; $Extension = pathinfo($Filename, PATHINFO_EXTENSION); $TargetFolder = PATH_ROOT . DS . 'uploads' . DS . 'import'; if (!file_exists($TargetFolder)) { mkdir($TargetFolder, 0777, TRUE); } $ImportPath = $Upload->GenerateTargetName(PATH_ROOT . DS . 'uploads' . DS . 'import', $Extension); $Upload->SaveAs($TmpFile, $ImportPath); $Imp->ImportPath = $ImportPath; $this->Form->SetFormValue('PathSelect', $ImportPath); $UploadedFiles = GetValue('UploadedFiles', $Imp->Data); $UploadedFiles[$ImportPath] = basename($Filename); $Imp->Data['UploadedFiles'] = $UploadedFiles; } elseif ($PathSelect = $this->Form->GetFormValue('PathSelect')) { if ($PathSelect == 'NEW') { $Validation->AddValidationResult('ImportFile', 'ValidateRequired'); } else { $Imp->ImportPath = $PathSelect; } } elseif (!$Imp->ImportPath && count($ImportPaths) == 0) { // There was no file uploaded this request or before. $Validation->AddValidationResult('ImportFile', $Upload->Exception); } // Validate the overwrite. if (TRUE || strcasecmp($this->Form->GetFormValue('Overwrite'), 'Overwrite') == 0) { if (!StringBeginsWith($this->Form->GetFormValue('PathSelect'), 'Db:', TRUE)) { $Validation->ApplyRule('Email', 'Required'); if (!$this->Form->GetFormValue('UseCurrentPassword')) { $Validation->ApplyRule('Password', 'Required'); } } } if ($Validation->Validate($this->Form->FormValues())) { $this->Form->SetFormValue('Overwrite', 'overwrite'); $Imp->FromPost($this->Form->FormValues()); $this->View = 'Info'; } else { $this->Form->SetValidationResults($Validation->Results()); } } else { $this->Form->SetFormValue('PathSelect', $Imp->ImportPath); } $Imp->SaveState(); } else { $this->SetData('Steps', $Imp->Steps()); $this->View = 'Info'; } if (!StringBeginsWith($Imp->ImportPath, 'db:') && !file_exists($Imp->ImportPath)) { $Imp->DeleteState(); } try { $UploadedFiles = GetValue('UploadedFiles', $Imp->Data, array()); $ImportPaths = array_merge($ImportPaths, $UploadedFiles); $this->SetData('ImportPaths', $ImportPaths); $this->SetData('Header', $Imp->GetImportHeader()); $this->SetData('Stats', GetValue('Stats', $Imp->Data, array())); $this->SetData('GenerateSQL', GetValue('GenerateSQL', $Imp->Data)); $this->SetData('ImportPath', $Imp->ImportPath); $this->SetData('OriginalFilename', GetValue('OriginalFilename', $Imp->Data)); $this->SetData('CurrentStep', $Imp->CurrentStep); $this->SetData('LoadSpeedWarning', $Imp->LoadTableType(FALSE) == 'LoadTableWithInsert'); } catch (Gdn_UserException $Ex) { $this->Form->AddError($Ex); $Imp->SaveState(); $this->View = 'Index'; } $this->Render(); }
/** * Get the path of a view. * * @param string $View The name of the view. * @param string $Controller The name of the controller invoking the view or blank. * @param string $Folder The application folder or plugins/plugin folder. * @return string|false The path to the view or false if it wasn't found. * @deprecated */ function viewLocation($View, $Controller, $Folder) { deprecated('viewLocation()'); $Paths = array(); if (strpos($View, '/') !== false) { // This is a path to the view from the root. $Paths[] = $View; } else { $View = strtolower($View); $Controller = strtolower(StringEndsWith($Controller, 'Controller', true, true)); if ($Controller) { $Controller = '/' . $Controller; } $Extensions = array('tpl', 'php'); // 1. First we check the theme. if (Gdn::Controller() && ($Theme = Gdn::Controller()->Theme)) { foreach ($Extensions as $Ext) { $Paths[] = PATH_THEMES . "/{$Theme}/views{$Controller}/{$View}.{$Ext}"; } } // 2. Then we check the application/plugin. if (StringBeginsWith($Folder, 'plugins/')) { // This is a plugin view. foreach ($Extensions as $Ext) { $Paths[] = PATH_ROOT . "/{$Folder}/views{$Controller}/{$View}.{$Ext}"; } } else { // This is an application view. $Folder = strtolower($Folder); foreach ($Extensions as $Ext) { $Paths[] = PATH_APPLICATIONS . "/{$Folder}/views{$Controller}/{$View}.{$Ext}"; } if ($Folder != 'dashboard' && StringEndsWith($View, '.master')) { // This is a master view that can always fall back to the dashboard. foreach ($Extensions as $Ext) { $Paths[] = PATH_APPLICATIONS . "/dashboard/views{$Controller}/{$View}.{$Ext}"; } } } } // Now let's search the paths for the view. foreach ($Paths as $Path) { if (file_exists($Path)) { return $Path; } } Trace(array('view' => $View, 'controller' => $Controller, 'folder' => $Folder), 'View'); Trace($Paths, 'ViewLocation()'); return false; }
/** * Set user preference for sorting discussions. */ public function Sort($Target = '') { if (!Gdn::Session()->IsValid()) { throw PermissionException(); } if (!$this->Request->IsAuthenticatedPostBack()) { throw ForbiddenException('GET'); } // Get param $SortField = Gdn::Request()->Post('DiscussionSort'); $SortField = 'd.' . StringBeginsWith($SortField, 'd.', TRUE, TRUE); // Use whitelist here too to keep database clean if (!in_array($SortField, DiscussionModel::AllowedSortFields())) { throw new Gdn_UserException("Unknown sort {$SortField}."); } // Set user pref Gdn::UserModel()->SavePreference(Gdn::Session()->UserID, 'Discussions.SortField', $SortField); if ($Target) { Redirect($Target); } // Send sorted discussions. $this->DeliveryMethod(DELIVERY_METHOD_JSON); $this->Render(); }
/** * Run a query, replacing database prefixes. * @param string $Sql The sql to execute. * - :_z will be replaced by the import prefix. * - :_ will be replaced by the database prefix. * @param array $Parameters PDO parameters to pass to the query. * @return Gdn_DataSet */ public function Query($Sql, $Parameters = NULL) { $Db = Gdn::Database(); // Replace db prefixes. $Sql = str_replace(array(':_z', ':_'), array($Db->DatabasePrefix . self::TABLE_PREFIX, $Db->DatabasePrefix), $Sql); // Figure out the type of the type of the query. if (StringBeginsWith($Sql, 'select')) { $Type = 'select'; } elseif (StringBeginsWith($Sql, 'truncate')) { $Type = 'truncate'; } elseif (StringBeginsWith($Sql, 'insert')) { $Type = 'insert'; } elseif (StringBeginsWith($Sql, 'update')) { $Type = 'update'; } elseif (StringBeginsWith($Sql, 'delete')) { $Type = 'delete'; } else { $Type = 'select'; } // Execute the query. if (is_array($Parameters)) { $this->SQL->NamedParameters($Parameters); } $Result = $this->SQL->Query($Sql, $Type); //$this->Timer->Split('Sql: '. str_replace("\n", "\n ", $Sql)); return $Result; }
/** * Banner management screen. * * @since 2.0.0 * @access public */ public function Banner() { $this->Permission('Garden.Settings.Manage'); $this->AddSideMenu('dashboard/settings/banner'); $this->Title(T('Banner')); $Validation = new Gdn_Validation(); $ConfigurationModel = new Gdn_ConfigurationModel($Validation); $ConfigurationModel->SetField(array('Garden.HomepageTitle' => C('Garden.Title'), 'Garden.Title', 'Garden.Description')); // Set the model on the form. $this->Form->SetModel($ConfigurationModel); // Get the current logo. $Logo = C('Garden.Logo'); if ($Logo) { $Logo = ltrim($Logo, '/'); // Fix the logo path. if (StringBeginsWith($Logo, 'uploads/')) { $Logo = substr($Logo, strlen('uploads/')); } $this->SetData('Logo', $Logo); } // Get the current favicon. $Favicon = C('Garden.FavIcon'); $this->SetData('Favicon', $Favicon); $ShareImage = C('Garden.ShareImage'); $this->SetData('ShareImage', $ShareImage); // If seeing the form for the first time... if (!$this->Form->AuthenticatedPostBack()) { // Apply the config settings to the form. $this->Form->SetData($ConfigurationModel->Data); } else { // Define some validation rules for the fields being saved $ConfigurationModel->Validation->ApplyRule('Garden.Title', 'Required'); $SaveData = array(); if ($this->Form->Save() !== FALSE) { $Upload = new Gdn_Upload(); try { // Validate the upload $TmpImage = $Upload->ValidateUpload('Logo', FALSE); if ($TmpImage) { // Generate the target image name $TargetImage = $Upload->GenerateTargetName(PATH_UPLOADS); $ImageBaseName = pathinfo($TargetImage, PATHINFO_BASENAME); // Delete any previously uploaded images. if ($Logo) { $Upload->Delete($Logo); } // Save the uploaded image $Parts = $Upload->SaveAs($TmpImage, $ImageBaseName); $ImageBaseName = $Parts['SaveName']; $SaveData['Garden.Logo'] = $ImageBaseName; $this->SetData('Logo', $ImageBaseName); } $ImgUpload = new Gdn_UploadImage(); $TmpFavicon = $ImgUpload->ValidateUpload('Favicon', FALSE); if ($TmpFavicon) { $ICOName = 'favicon_' . substr(md5(microtime()), 16) . '.ico'; if ($Favicon) { $Upload->Delete($Favicon); } // Resize the to a png. $Parts = $ImgUpload->SaveImageAs($TmpFavicon, $ICOName, 16, 16, array('OutputType' => 'ico', 'Crop' => TRUE)); $SaveData['Garden.FavIcon'] = $Parts['SaveName']; $this->SetData('Favicon', $Parts['SaveName']); } $TmpShareImage = $Upload->ValidateUpload('ShareImage', FALSE); if ($TmpShareImage) { $TargetImage = $Upload->GenerateTargetName(PATH_UPLOADS, FALSE); $ImageBaseName = pathinfo($TargetImage, PATHINFO_BASENAME); if ($ShareImage) { $Upload->Delete($ShareImage); } $Parts = $Upload->SaveAs($TmpShareImage, $ImageBaseName); $SaveData['Garden.ShareImage'] = $Parts['SaveName']; $this->SetData('ShareImage', $Parts['SaveName']); } } catch (Exception $ex) { $this->Form->AddError($ex); } // If there were no errors, save the path to the logo in the config if ($this->Form->ErrorCount() == 0) { SaveToConfig($SaveData); } $this->InformMessage(T("Your settings have been saved.")); } } $this->Render(); }
public function _SetBreadcrumbs($Name = NULL, $Url = NULL) { // Add the root link. if (GetValue('UserID', $this->User) == Gdn::Session()->UserID) { $Root = array('Name' => T('Profile'), 'Url' => '/profile'); $Breadcrumb = array('Name' => $Name, 'Url' => $Url); } else { $NameUnique = C('Garden.Registration.NameUnique'); $Root = array('Name' => GetValue('Name', $this->User), 'Url' => UserUrl($this->User)); $Breadcrumb = array('Name' => $Name, 'Url' => $Url . '/' . ($NameUnique ? '' : GetValue('UserID', $this->User) . '/') . rawurlencode(GetValue('Name', $this->User))); } $this->Data['Breadcrumbs'][] = $Root; if ($Name && !StringBeginsWith($Root['Url'], $Url)) { $this->Data['Breadcrumbs'][] = array('Name' => $Name, 'Url' => $Url); } }
/** * Connect the user with an external source. * * This controller method is meant to be used with plugins that set its data array to work. * Events: ConnectData * * @since 2.0.0 * @access public * * @param string $Method Used to register multiple providers on ConnectData event. */ public function Connect($Method) { $this->AddJsFile('entry.js'); $this->View = 'connect'; $IsPostBack = $this->Form->IsPostBack() && $this->Form->GetFormValue('Connect', NULL) !== NULL; if (!$IsPostBack) { // Here are the initial data array values. that can be set by a plugin. $Data = array('Provider' => '', 'ProviderName' => '', 'UniqueID' => '', 'FullName' => '', 'Name' => '', 'Email' => '', 'Photo' => '', 'Target' => $this->Target()); $this->Form->SetData($Data); $this->Form->AddHidden('Target', $this->Request->Get('Target', '/')); } // The different providers can check to see if they are being used and modify the data array accordingly. $this->EventArguments = array($Method); // Fire ConnectData event & error handling. $CurrentData = $this->Form->FormValues(); try { $this->FireEvent('ConnectData'); } catch (Gdn_UserException $Ex) { $this->Form->AddError($Ex); return $this->Render('ConnectError'); } catch (Exception $Ex) { if (Debug()) { $this->Form->AddError($Ex); } else { $this->Form->AddError('There was an error fetching the connection data.'); } return $this->Render('ConnectError'); } if (!UserModel::NoEmail()) { if (!$this->Form->GetFormValue('Email') || $this->Form->GetFormValue('EmailVisible')) { $this->Form->SetFormValue('EmailVisible', TRUE); $this->Form->AddHidden('EmailVisible', TRUE); if ($IsPostBack) { $this->Form->SetFormValue('Email', GetValue('Email', $CurrentData)); } } } $FormData = $this->Form->FormValues(); // debug // Make sure the minimum required data has been provided to the connect. if (!$this->Form->GetFormValue('Provider')) { $this->Form->AddError('ValidateRequired', T('Provider')); } if (!$this->Form->GetFormValue('UniqueID')) { $this->Form->AddError('ValidateRequired', T('UniqueID')); } if (!$this->Data('Verified')) { // Whatever event handler catches this must Set the data 'Verified' to true to prevent a random site from connecting without credentials. // This must be done EVERY postback and is VERY important. $this->Form->AddError('The connection data has not been verified.'); } if ($this->Form->ErrorCount() > 0) { return $this->Render(); } $UserModel = Gdn::UserModel(); // Check to see if there is an existing user associated with the information above. $Auth = $UserModel->GetAuthentication($this->Form->GetFormValue('UniqueID'), $this->Form->GetFormValue('Provider')); $UserID = GetValue('UserID', $Auth); // Check to synchronise roles upon connecting. if (($this->Data('Trusted') || C('Garden.SSO.SynchRoles')) && $this->Form->GetFormValue('Roles', NULL) !== NULL) { $SaveRoles = TRUE; // Translate the role names to IDs. $Roles = $this->Form->GetFormValue('Roles', NULL); $Roles = RoleModel::GetByName($Roles); $RoleIDs = array_keys($Roles); if (empty($RoleIDs)) { // The user must have at least one role. This protects that. $RoleIDs = $this->UserModel->NewUserRoleIDs(); } $this->Form->SetFormValue('RoleID', $RoleIDs); } else { $SaveRoles = FALSE; } if ($UserID) { // The user is already connected. $this->Form->SetFormValue('UserID', $UserID); if (C('Garden.Registration.ConnectSynchronize', TRUE)) { $User = Gdn::UserModel()->GetID($UserID, DATASET_TYPE_ARRAY); $Data = $this->Form->FormValues(); // Don't overwrite the user photo if the user uploaded a new one. $Photo = GetValue('Photo', $User); if (!GetValue('Photo', $Data) || $Photo && !StringBeginsWith($Photo, 'http')) { unset($Data['Photo']); } // Synchronize the user's data. $UserModel->Save($Data, array('NoConfirmEmail' => TRUE, 'FixUnique' => TRUE, 'SaveRoles' => $SaveRoles)); } // Always save the attributes because they may contain authorization information. if ($Attributes = $this->Form->GetFormValue('Attributes')) { $UserModel->SaveAttribute($UserID, $Attributes); } // Sign the user in. Gdn::Session()->Start($UserID, TRUE, TRUE); Gdn::UserModel()->FireEvent('AfterSignIn'); // $this->_SetRedirect(TRUE); $this->_SetRedirect($this->Request->Get('display') == 'popup'); } elseif ($this->Form->GetFormValue('Name') || $this->Form->GetFormValue('Email')) { $NameUnique = C('Garden.Registration.NameUnique', TRUE); $EmailUnique = C('Garden.Registration.EmailUnique', TRUE); $AutoConnect = C('Garden.Registration.AutoConnect'); // Get the existing users that match the name or email of the connection. $Search = FALSE; if ($this->Form->GetFormValue('Name') && $NameUnique) { $UserModel->SQL->OrWhere('Name', $this->Form->GetFormValue('Name')); $Search = TRUE; } if ($this->Form->GetFormValue('Email') && ($EmailUnique || $AutoConnect)) { $UserModel->SQL->OrWhere('Email', $this->Form->GetFormValue('Email')); $Search = TRUE; } if ($Search) { $ExistingUsers = $UserModel->GetWhere()->ResultArray(); } else { $ExistingUsers = array(); } // Check to automatically link the user. if ($AutoConnect && count($ExistingUsers) > 0) { foreach ($ExistingUsers as $Row) { if ($this->Form->GetFormValue('Email') == $Row['Email']) { $UserID = $Row['UserID']; $this->Form->SetFormValue('UserID', $UserID); $Data = $this->Form->FormValues(); if (C('Garden.Registration.ConnectSynchronize', TRUE)) { // Don't overwrite a photo if the user has already uploaded one. $Photo = GetValue('Photo', $Row); if (!GetValue('Photo', $Data) || $Photo && !StringBeginsWith($Photo, 'http')) { unset($Data['Photo']); } $UserModel->Save($Data, array('NoConfirmEmail' => TRUE, 'FixUnique' => TRUE, 'SaveRoles' => $SaveRoles)); } if ($Attributes = $this->Form->GetFormValue('Attributes')) { $UserModel->SaveAttribute($UserID, $Attributes); } // Save the userauthentication link. $UserModel->SaveAuthentication(array('UserID' => $UserID, 'Provider' => $this->Form->GetFormValue('Provider'), 'UniqueID' => $this->Form->GetFormValue('UniqueID'))); // Sign the user in. Gdn::Session()->Start($UserID, TRUE, TRUE); Gdn::UserModel()->FireEvent('AfterSignIn'); // $this->_SetRedirect(TRUE); $this->_SetRedirect($this->Request->Get('display') == 'popup'); $this->Render(); return; } } } $CurrentUserID = Gdn::Session()->UserID; // Massage the existing users. foreach ($ExistingUsers as $Index => $UserRow) { if ($EmailUnique && $UserRow['Email'] == $this->Form->GetFormValue('Email')) { $EmailFound = $UserRow; break; } if ($UserRow['Name'] == $this->Form->GetFormValue('Name')) { $NameFound = $UserRow; } if ($CurrentUserID > 0 && $UserRow['UserID'] == $CurrentUserID) { unset($ExistingUsers[$Index]); $CurrentUserFound = TRUE; } } if (isset($EmailFound)) { // The email address was found and can be the only user option. $ExistingUsers = array($UserRow); $this->SetData('NoConnectName', TRUE); } elseif (isset($CurrentUserFound)) { $ExistingUsers = array_merge(array('UserID' => 'current', 'Name' => sprintf(T('%s (Current)'), Gdn::Session()->User->Name)), $ExistingUsers); } if (!isset($NameFound) && !$IsPostBack) { $this->Form->SetFormValue('ConnectName', $this->Form->GetFormValue('Name')); } $this->SetData('ExistingUsers', $ExistingUsers); if (UserModel::NoEmail()) { $EmailValid = TRUE; } else { $EmailValid = ValidateRequired($this->Form->GetFormValue('Email')); } if ($this->Form->GetFormValue('Name') && $EmailValid && (!is_array($ExistingUsers) || count($ExistingUsers) == 0)) { // There is no existing user with the suggested name so we can just create the user. $User = $this->Form->FormValues(); $User['Password'] = RandomString(50); // some password is required $User['HashMethod'] = 'Random'; $User['Source'] = $this->Form->GetFormValue('Provider'); $User['SourceID'] = $this->Form->GetFormValue('UniqueID'); $User['Attributes'] = $this->Form->GetFormValue('Attributes', NULL); $User['Email'] = $this->Form->GetFormValue('ConnectEmail', $this->Form->GetFormValue('Email', NULL)); // $UserID = $UserModel->InsertForBasic($User, FALSE, array('ValidateEmail' => FALSE, 'NoConfirmEmail' => TRUE, 'SaveRoles' => $SaveRoles)); $UserID = $UserModel->Register($User, array('CheckCaptcha' => FALSE, 'ValidateEmail' => FALSE, 'NoConfirmEmail' => TRUE, 'SaveRoles' => $SaveRoles)); $User['UserID'] = $UserID; $this->Form->SetValidationResults($UserModel->ValidationResults()); if ($UserID) { $UserModel->SaveAuthentication(array('UserID' => $UserID, 'Provider' => $this->Form->GetFormValue('Provider'), 'UniqueID' => $this->Form->GetFormValue('UniqueID'))); $this->Form->SetFormValue('UserID', $UserID); Gdn::Session()->Start($UserID, TRUE, TRUE); Gdn::UserModel()->FireEvent('AfterSignIn'); // Send the welcome email. if (C('Garden.Registration.SendConnectEmail', FALSE)) { try { $UserModel->SendWelcomeEmail($UserID, '', 'Connect', array('ProviderName' => $this->Form->GetFormValue('ProviderName', $this->Form->GetFormValue('Provider', 'Unknown')))); } catch (Exception $Ex) { // Do nothing if emailing doesn't work. } } $this->_SetRedirect(TRUE); } } } // Save the user's choice. if ($IsPostBack) { // The user has made their decision. $PasswordHash = new Gdn_PasswordHash(); $UserSelect = $this->Form->GetFormValue('UserSelect'); if (!$UserSelect || $UserSelect == 'other') { // The user entered a username. $ConnectNameEntered = TRUE; if ($this->Form->ValidateRule('ConnectName', 'ValidateRequired')) { $ConnectName = $this->Form->GetFormValue('ConnectName'); $User = FALSE; if (C('Garden.Registration.NameUnique')) { // Check to see if there is already a user with the given name. $User = $UserModel->GetWhere(array('Name' => $ConnectName))->FirstRow(DATASET_TYPE_ARRAY); } if (!$User) { $this->Form->ValidateRule('ConnectName', 'ValidateUsername'); } } } else { // The user selected an existing user. $ConnectNameEntered = FALSE; if ($UserSelect == 'current') { if (Gdn::Session()->UserID == 0) { // This shouldn't happen, but a use could sign out in another browser and click submit on this form. $this->Form->AddError('@You were uexpectidly signed out.'); } else { $UserSelect = Gdn::Session()->UserID; } } $User = $UserModel->GetID($UserSelect, DATASET_TYPE_ARRAY); } if (isset($User) && $User) { // Make sure the user authenticates. if (!$User['UserID'] == Gdn::Session()->UserID) { if ($this->Form->ValidateRule('ConnectPassword', 'ValidateRequired', sprintf(T('ValidateRequired'), T('Password')))) { try { if (!$PasswordHash->CheckPassword($this->Form->GetFormValue('ConnectPassword'), $User['Password'], $User['HashMethod'], $this->Form->GetFormValue('ConnectName'))) { if ($ConnectNameEntered) { $this->Form->AddError('The username you entered has already been taken.'); } else { $this->Form->AddError('The password you entered is incorrect.'); } } } catch (Gdn_UserException $Ex) { $this->Form->AddError($Ex); } } } } elseif ($this->Form->ErrorCount() == 0) { // The user doesn't exist so we need to add another user. $User = $this->Form->FormValues(); $User['Name'] = $User['ConnectName']; $User['Password'] = RandomString(50); // some password is required $User['HashMethod'] = 'Random'; $UserID = $UserModel->Register($User, array('CheckCaptcha' => FALSE, 'NoConfirmEmail' => TRUE, 'SaveRoles' => $SaveRoles)); $User['UserID'] = $UserID; $this->Form->SetValidationResults($UserModel->ValidationResults()); if ($UserID) { // // Add the user to the default roles. // $UserModel->SaveRoles($UserID, C('Garden.Registration.DefaultRoles')); // Send the welcome email. $UserModel->SendWelcomeEmail($UserID, '', 'Connect', array('ProviderName' => $this->Form->GetFormValue('ProviderName', $this->Form->GetFormValue('Provider', 'Unknown')))); } } if ($this->Form->ErrorCount() == 0) { // Save the authentication. if (isset($User) && GetValue('UserID', $User)) { $UserModel->SaveAuthentication(array('UserID' => $User['UserID'], 'Provider' => $this->Form->GetFormValue('Provider'), 'UniqueID' => $this->Form->GetFormValue('UniqueID'))); $this->Form->SetFormValue('UserID', $User['UserID']); } // Sign the appropriate user in. Gdn::Session()->Start($this->Form->GetFormValue('UserID', TRUE, TRUE)); Gdn::UserModel()->FireEvent('AfterSignIn'); $this->_SetRedirect(TRUE); } } $this->Render(); }
/** * Write a button group control. * * @param array $Links An array of arrays with the following keys: * - Text: The text of the link. * - Url: The url of the link. * @param string|array $CssClass The css class of the link. This can be a two-item array where the second element will be added to the buttons. * @param string|false $Default The url of the default link. * @since 2.1 */ function buttonGroup($Links, $CssClass = 'Button', $Default = false) { if (!is_array($Links) || count($Links) < 1) { return; } $Text = $Links[0]['Text']; $Url = $Links[0]['Url']; $ButtonClass = ''; if (is_array($CssClass)) { list($CssClass, $ButtonClass) = $CssClass; } if ($Default && count($Links) > 1) { if (is_array($Default)) { $DefaultText = $Default['Text']; $Default = $Default['Url']; } // Find the default button. $Default = ltrim($Default, '/'); foreach ($Links as $Link) { if (StringBeginsWith(ltrim($Link['Url'], '/'), $Default)) { $Text = $Link['Text']; $Url = $Link['Url']; break; } } if (isset($DefaultText)) { $Text = $DefaultText; } } if (count($Links) < 2) { echo anchor($Text, $Url, $CssClass); } else { // NavButton or Button? $ButtonClass = concatSep(' ', $ButtonClass, strpos($CssClass, 'NavButton') !== false ? 'NavButton' : 'Button'); if (strpos($CssClass, 'Primary') !== false) { $ButtonClass .= ' Primary'; } // Strip "Button" or "NavButton" off the group class. echo '<div class="ButtonGroup Multi ' . str_replace(array('NavButton', 'Button'), array('', ''), $CssClass) . '">'; echo anchor($Text, $Url, $ButtonClass); echo '<ul class="Dropdown MenuItems">'; foreach ($Links as $Link) { echo wrap(anchor($Link['Text'], $Link['Url'], val('CssClass', $Link, '')), 'li'); } echo '</ul>'; echo anchor(sprite('SpDropdownHandle', 'Sprite', t('Expand for more options.')), '#', $ButtonClass . ' Handle'); echo '</div>'; } }
/** * Undocumented method. * * @todo Method RenderMaster() needs a description. */ 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)) { // if (ArrayHasValue($this->_CssFiles, 'style.css')) { // $this->AddCssFile('custom.css'); // // // Add the theme option's css file. // if ($this->Theme && $this->ThemeOptions) { // $Filenames = GetValueR('Styles.Value', $this->ThemeOptions); // if (is_string($Filenames) && $Filenames != '%s') // $this->_CssFiles[] = array('FileName' => ChangeBasename('custom.css', $Filenames), 'AppFolder' => FALSE, 'Options' => FALSE); // } // } elseif (ArrayHasValue($this->_CssFiles, 'admin.css')) { // $this->AddCssFile('customadmin.css'); // } $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']; // style.css and admin.css deserve some custom processing. if (in_array($CssFile, array('style.css', 'admin.css'))) { 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("/utility/css/{$ThemeType}/{$Basename}-{$ETag}.css", '//'), 'all', FALSE, $CssInfo['Options']); } continue; } if (StringBeginsWith($CssFile, 'http')) { $this->Head->AddCss($CssFile, 'all', GetValue('AddVersion', $CssInfo, TRUE), $CssInfo['Options']); continue; } elseif (strpos($CssFile, '/') !== FALSE) { // A direct path to the file was given. $CssPaths = array(CombinePaths(array(PATH_ROOT, str_replace('/', DS, $CssFile)))); } else { // $CssGlob = preg_replace('/(.*)(\.css)/', '\1*\2', $CssFile); $AppFolder = $CssInfo['AppFolder']; if ($AppFolder == '') { $AppFolder = $this->ApplicationFolder; } // CSS comes from one of four places: $CssPaths = array(); if ($this->Theme) { // Use the default filename. $CssPaths[] = PATH_THEMES . DS . $this->Theme . DS . 'design' . DS . $CssFile; } // 3. Application or plugin. if (StringBeginsWith($AppFolder, 'plugins/')) { // The css is coming from a plugin. $AppFolder = substr($AppFolder, strlen('plugins/')); $CssPaths[] = PATH_PLUGINS . "/{$AppFolder}/design/{$CssFile}"; $CssPaths[] = PATH_PLUGINS . "/{$AppFolder}/{$CssFile}"; } elseif (in_array($AppFolder, array('static', 'resources'))) { // This is a static css file. $CssPaths[] = PATH_ROOT . "/resources/css/{$CssFile}"; } else { // Application default. eg. root/applications/app_name/design/ $CssPaths[] = PATH_APPLICATIONS . DS . $AppFolder . DS . 'design' . DS . $CssFile; } // 4. Garden default. eg. root/applications/dashboard/design/ $CssPaths[] = PATH_APPLICATIONS . DS . 'dashboard' . DS . 'design' . DS . $CssFile; } // Find the first file that matches the path. $CssPath = FALSE; foreach ($CssPaths as $Glob) { $Paths = SafeGlob($Glob); if (is_array($Paths) && count($Paths) > 0) { $CssPath = $Paths[0]; break; } } // Check to see if there is a CSS cacher. $CssCacher = Gdn::Factory('CssCacher'); if (!is_null($CssCacher)) { $CssPath = $CssCacher->Get($CssPath, $AppFolder); } if ($CssPath !== FALSE) { $CssPath = substr($CssPath, strlen(PATH_ROOT)); $CssPath = str_replace(DS, '/', $CssPath); $this->Head->AddCss($CssPath, 'all', TRUE, $CssInfo['Options']); } } // Add a custom js file. if (ArrayHasValue($this->_CssFiles, 'style.css')) { $this->AddJsFile('custom.js'); } // only to non-admin pages. // And now search for/add all JS files. $Cdns = array(); if (Gdn::Request()->Scheme() != 'https' && !C('Garden.Cdns.Disable', FALSE)) { $Cdns = array('jquery.js' => 'http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js'); } $this->EventArguments['Cdns'] =& $Cdns; $this->FireEvent('AfterJsCdns'); foreach ($this->_JsFiles as $Index => $JsInfo) { $JsFile = $JsInfo['FileName']; if (isset($Cdns[$JsFile])) { $JsFile = $Cdns[$JsFile]; } if (strpos($JsFile, '//') !== FALSE) { // This is a link to an external file. $this->Head->AddScript($JsFile, 'text/javascript', GetValue('Options', $JsInfo, array())); continue; } elseif (strpos($JsFile, '/') !== FALSE) { // A direct path to the file was given. $JsPaths = array(CombinePaths(array(PATH_ROOT, str_replace('/', DS, $JsFile)), DS)); } else { $AppFolder = $JsInfo['AppFolder']; if ($AppFolder == '') { $AppFolder = $this->ApplicationFolder; } // JS can come from a theme, an any of the application folder, or it can come from the global js folder: $JsPaths = array(); if ($this->Theme) { // 1. Application-specific js. eg. root/themes/theme_name/app_name/design/ $JsPaths[] = PATH_THEMES . DS . $this->Theme . DS . $AppFolder . DS . 'js' . DS . $JsFile; // 2. Garden-wide theme view. eg. root/themes/theme_name/design/ $JsPaths[] = PATH_THEMES . DS . $this->Theme . DS . 'js' . DS . $JsFile; } // 3. The application or plugin folder. if (StringBeginsWith(trim($AppFolder, '/'), 'plugins/')) { $JsPaths[] = PATH_PLUGINS . strstr($AppFolder, '/') . "/js/{$JsFile}"; $JsPaths[] = PATH_PLUGINS . strstr($AppFolder, '/') . "/{$JsFile}"; } else { $JsPaths[] = PATH_APPLICATIONS . "/{$AppFolder}/js/{$JsFile}"; } // 4. Global JS folder. eg. root/js/ $JsPaths[] = PATH_ROOT . DS . 'js' . DS . $JsFile; // 5. Global JS library folder. eg. root/js/library/ $JsPaths[] = PATH_ROOT . DS . 'js' . DS . 'library' . DS . $JsFile; } // Find the first file that matches the path. $JsPath = FALSE; foreach ($JsPaths as $Glob) { $Paths = SafeGlob($Glob); if (is_array($Paths) && count($Paths) > 0) { $JsPath = $Paths[0]; break; } } if ($JsPath !== FALSE) { $JsSrc = str_replace(array(PATH_ROOT, DS), array('', '/'), $JsPath); $Options = (array) $JsInfo['Options']; $Options['path'] = $JsPath; $Version = GetValue('Version', $JsInfo); if ($Version) { TouchValue('version', $Options, $Version); } $this->Head->AddScript($JsSrc, 'text/javascript', $Options); } } } // 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(); $MasterViewPath2 = ViewLocation($this->MasterView() . '.master', '', $this->ApplicationFolder); 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. Application default. eg. root/app_name/views/ $MasterViewPaths[] = CombinePaths(array(PATH_APPLICATIONS, $this->ApplicationFolder, 'views', $this->MasterView . '.master*')); // 4. 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; } } if ($MasterViewPath != $MasterViewPath2) { Trace("Master views differ. Controller: {$MasterViewPath}, ViewLocation(): {$MasterViewPath2}", TRACE_WARNING); } $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); } }
/** * Banner management screen. */ public function Banner() { $this->Permission('Garden.Settings.Manage'); $this->AddSideMenu('dashboard/settings/banner'); $this->Title(T('Banner')); $Validation = new Gdn_Validation(); $ConfigurationModel = new Gdn_ConfigurationModel($Validation); $ConfigurationModel->SetField(array('Garden.Title')); // Set the model on the form. $this->Form->SetModel($ConfigurationModel); // Get the current logo. $Logo = C('Garden.Logo'); if ($Logo) { $Logo = ltrim($Logo, '/'); // Fix the logo path. if (StringBeginsWith($Logo, 'uploads/')) $Logo = substr($Logo, strlen('uploads/')); $this->SetData('Logo', $Logo); } // If seeing the form for the first time... if ($this->Form->AuthenticatedPostBack() === FALSE) { // Apply the config settings to the form. $this->Form->SetData($ConfigurationModel->Data); } else { // Define some validation rules for the fields being saved $ConfigurationModel->Validation->ApplyRule('Garden.Title', 'Required'); if ($this->Form->Save() !== FALSE) { $Upload = new Gdn_Upload(); try { // Validate the upload $TmpImage = $Upload->ValidateUpload('Logo', FALSE); if ($TmpImage) { // Generate the target image name $TargetImage = $Upload->GenerateTargetName(PATH_ROOT . DS . 'uploads'); $ImageBaseName = pathinfo($TargetImage, PATHINFO_BASENAME); // Delete any previously uploaded images. if ($Logo) $Upload->Delete($Logo); // Save the uploaded image $Parts = $Upload->SaveAs( $TmpImage, $ImageBaseName ); $ImageBaseName = $Parts['SaveName']; } } catch (Exception $ex) { $this->Form->AddError($ex->getMessage()); } // If there were no errors, save the path to the logo in the config if ($this->Form->ErrorCount() == 0 && $Upload->GetUploadedFileName() != '') { SaveToConfig('Garden.Logo', $ImageBaseName); $this->SetData('Logo', $ImageBaseName); } $this->InformMessage(T("Your settings have been saved.")); } } $this->Render(); }
/** * Alternate version of Index that uses the embed master view. * * @param int $DiscussionID Unique identifier, if discussion has been created. * @param string $DiscussionStub Deprecated. * @param int $Offset * @param int $Limit */ public function Embed($DiscussionID = '', $DiscussionStub = '', $Offset = '', $Limit = '') { $this->Title(T('Comments')); // Add theme data $this->Theme = C('Garden.CommentsTheme', $this->Theme); Gdn_Theme::Section('Comments'); // Force view options $this->MasterView = 'empty'; $this->CanEditComments = FALSE; // Don't show the comment checkboxes on the embed comments page // Add some css to help with the transparent bg on embedded comments if ($this->Head) { $this->Head->AddString('<style type="text/css"> body { background: transparent !important; } </style>'); } // Javascript files & options $this->AddJsFile('jquery.gardenmorepager.js'); $this->AddJsFile('jquery.autogrow.js'); $this->RemoveJsFile('autosave.js'); $this->AddJsFile('discussion.js'); $this->AddDefinition('DoInform', '0'); // Suppress inform messages on embedded page. $this->AddDefinition('SelfUrl', Gdn::Request()->PathAndQuery()); $this->AddDefinition('Embedded', TRUE); // Define incoming variables (prefer querystring parameters over method parameters) $DiscussionID = is_numeric($DiscussionID) && $DiscussionID > 0 ? $DiscussionID : 0; $DiscussionID = GetIncomingValue('vanilla_discussion_id', $DiscussionID); $Offset = GetIncomingValue('Offset', $Offset); $Limit = GetIncomingValue('Limit', $Limit); $vanilla_identifier = GetIncomingValue('vanilla_identifier', ''); // Only allow vanilla identifiers of 32 chars or less - md5 if larger if (strlen($vanilla_identifier) > 32) { $vanilla_identifier = md5($vanilla_identifier); } $vanilla_type = GetIncomingValue('vanilla_type', 'page'); $vanilla_url = GetIncomingValue('vanilla_url', ''); $vanilla_category_id = GetIncomingValue('vanilla_category_id', ''); $ForeignSource = array('vanilla_identifier' => $vanilla_identifier, 'vanilla_type' => $vanilla_type, 'vanilla_url' => $vanilla_url, 'vanilla_category_id' => $vanilla_category_id); $this->SetData('ForeignSource', $ForeignSource); // Set comment sorting $SortComments = C('Garden.Embed.SortComments') == 'desc' ? 'desc' : 'asc'; $this->SetData('SortComments', $SortComments); // Retrieve the discussion record $Discussion = FALSE; if ($DiscussionID > 0) { $Discussion = $this->DiscussionModel->GetID($DiscussionID); } else { if ($vanilla_identifier != '' && $vanilla_type != '') { $Discussion = $this->DiscussionModel->GetForeignID($vanilla_identifier, $vanilla_type); } } // Set discussion data if we have one for this page if ($Discussion) { $this->Permission('Vanilla.Discussions.View', TRUE, 'Category', $Discussion->PermissionCategoryID); $this->SetData('Discussion', $Discussion, TRUE); $this->SetData('DiscussionID', $Discussion->DiscussionID, TRUE); $this->Title($Discussion->Name); // Actual number of comments, excluding the discussion itself $ActualResponses = $Discussion->CountComments; // Define the query offset & limit if (!is_numeric($Limit) || $Limit < 0) { $Limit = C('Garden.Embed.CommentsPerPage', 30); } $OffsetProvided = $Offset != ''; list($Offset, $Limit) = OffsetLimit($Offset, $Limit); $this->Offset = $Offset; if (C('Vanilla.Comments.AutoOffset')) { if ($ActualResponses <= $Limit) { $this->Offset = 0; } if ($this->Offset == $ActualResponses) { $this->Offset -= $Limit; } } else { if ($this->Offset == '') { $this->Offset = 0; } } if ($this->Offset < 0) { $this->Offset = 0; } // Set the canonical url to have the proper page title. $this->CanonicalUrl(DiscussionUrl($Discussion, PageNumber($this->Offset, $Limit))); // Load the comments. $CurrentOrderBy = $this->CommentModel->OrderBy(); if (StringBeginsWith(GetValueR('0.0', $CurrentOrderBy), 'c.DateInserted')) { $this->CommentModel->OrderBy('c.DateInserted ' . $SortComments); } // allow custom sort $this->SetData('Comments', $this->CommentModel->Get($Discussion->DiscussionID, $Limit, $this->Offset), TRUE); if (count($this->CommentModel->Where()) > 0) { $ActualResponses = FALSE; } $this->SetData('_Count', $ActualResponses); // Build a pager $PagerFactory = new Gdn_PagerFactory(); $this->EventArguments['PagerType'] = 'MorePager'; $this->FireEvent('BeforeBuildPager'); $this->Pager = $PagerFactory->GetPager($this->EventArguments['PagerType'], $this); $this->Pager->ClientID = 'Pager'; $this->Pager->MoreCode = 'More Comments'; $this->Pager->Configure($this->Offset, $Limit, $ActualResponses, 'discussion/embed/' . $Discussion->DiscussionID . '/' . Gdn_Format::Url($Discussion->Name) . '/%1$s'); $this->Pager->CurrentRecords = $this->Comments->NumRows(); $this->FireEvent('AfterBuildPager'); } // Define the form for the comment input $this->Form = Gdn::Factory('Form', 'Comment'); $this->Form->Action = Url('/vanilla/post/comment/'); $this->Form->AddHidden('CommentID', ''); $this->Form->AddHidden('Embedded', 'true'); // Tell the post controller that this is an embedded page (in case there are custom views it needs to pick up from a theme). $this->Form->AddHidden('DisplayNewCommentOnly', 'true'); // Only load/display the new comment after posting (don't load all new comments since the page last loaded). // Grab the page title if ($this->Request->Get('title')) { $this->Form->SetValue('Name', $this->Request->Get('title')); } // Set existing DiscussionID for comment form if ($Discussion) { $this->Form->AddHidden('DiscussionID', $Discussion->DiscussionID); } foreach ($ForeignSource as $Key => $Val) { // Drop the foreign source information into the form so it can be used if creating a discussion $this->Form->AddHidden($Key, $Val); // Also drop it into the definitions so it can be picked up for stashing comments $this->AddDefinition($Key, $Val); } // Retrieve & apply the draft if there is one: $Draft = FALSE; if (Gdn::Session()->UserID && $Discussion) { $DraftModel = new DraftModel(); $Draft = $DraftModel->Get(Gdn::Session()->UserID, 0, 1, $Discussion->DiscussionID)->FirstRow(); $this->Form->AddHidden('DraftID', $Draft ? $Draft->DraftID : ''); } if ($Draft) { $this->Form->SetFormValue('Body', $Draft->Body); } else { // Look in the session stash for a comment $StashComment = Gdn::Session()->Stash('CommentForForeignID_' . $ForeignSource['vanilla_identifier'], '', FALSE); if ($StashComment) { $this->Form->SetValue('Body', $StashComment); $this->Form->SetFormValue('Body', $StashComment); } } // Deliver JSON data if necessary if ($this->_DeliveryType != DELIVERY_TYPE_ALL) { if ($this->Discussion) { $this->SetJson('LessRow', $this->Pager->ToString('less')); $this->SetJson('MoreRow', $this->Pager->ToString('more')); } $this->View = 'comments'; } // Ordering note for JS if ($SortComments == 'desc') { $this->AddDefinition('PrependNewComments', '1'); } // Report the discussion id so js can use it. if ($Discussion) { $this->AddDefinition('DiscussionID', $Discussion->DiscussionID); } $this->FireEvent('BeforeDiscussionRender'); $this->Render(); }
/** * Call a method on the given model. */ public function Model() { $this->Permission('Garden.Settings.Manage'); $this->DeliveryMethod(DELIVERY_METHOD_JSON); $this->DeliveryType(DELIVERY_TYPE_DATA); $Args = func_get_args(); // Check to see if we have a model. $ModelName = StringEndsWith(array_shift($Args), 'Model', TRUE, TRUE); $ModelName = ucfirst($ModelName) . 'Model'; if (!class_exists($ModelName)) { throw NotFoundException($ModelName); } // Check for json/xml style extension. if (count($Args)) { $LastArg = $Args[count($Args) - 1]; $Extension = strrchr($LastArg, '.'); if ($Extension) { $Args[count($Args) - 1] = substr($LastArg, 0, -strlen($Extension)); $Extension = strtolower($Extension); if ($Extension == '.xml') { $this->DeliveryMethod(DELIVERY_METHOD_XML); } } } // Instantiate the model. $Model = new $ModelName(); $MethodName = array_shift($Args); // Reflect the arguments. $Callback = array($Model, $MethodName); if ($this->Request->Get('help')) { $this->SetData('Model', get_class($Model)); if ($MethodName) { if (!method_exists($Model, $MethodName)) { throw NotFoundException($ModelName . '->' . $MethodName . '()'); } $this->SetData('Method', $MethodName); $Meth = new ReflectionMethod($Callback[0], $Callback[1]); $MethArgs = $Meth->getParameters(); $Args = array(); foreach ($MethArgs as $Index => $MethArg) { $ParamName = $MethArg->getName(); if ($MethArg->isDefaultValueAvailable()) { $Args[$ParamName] = $MethArg->getDefaultValue(); } else { $Args[$ParamName] = 'REQUIRED'; } } $this->SetData('Args', $Args); } else { $Class = new ReflectionClass($Model); $Meths = $Class->getMethods(); $Methods = array(); foreach ($Meths as $Meth) { $MethodName = $Meth->getName(); if (StringBeginsWith($MethodName, '_')) { continue; } $MethArgs = $Meth->getParameters(); $Args = array(); foreach ($MethArgs as $Index => $MethArg) { $ParamName = $MethArg->getName(); if ($MethArg->isDefaultValueAvailable()) { $Args[$ParamName] = $MethArg->getDefaultValue(); } else { $Args[$ParamName] = 'REQUIRED'; } } $Methods[$MethodName] = array('Method' => $MethodName, 'Args' => $Args); } $this->SetData('Methods', $Methods); } } else { if (!method_exists($Model, $MethodName)) { throw NotFoundException($ModelName . '->' . $MethodName . '()'); } $MethodArgs = ReflectArgs($Callback, $this->Request->Get(), $Args); $Result = call_user_func_array($Callback, $MethodArgs); if (is_array($Result)) { $this->Data = $Result; } elseif (is_a($Result, 'Gdn_DataSet')) { $Result = $Result->ResultArray(); $this->Data = $Result; } elseif (is_a($Result, 'stdClass')) { $this->Data = (array) $Result; } else { $this->SetData('Result', $Result); } } $this->Render(); }
public static function CssPath($ThemeType, $Filename, $Folder) { if (!$ThemeType) { $ThemeType = IsMobile() ? 'mobile' : 'desktop'; } // 1. Check for a url. if (IsUrl($Filename)) { return array($Filename, $Filename); } // 2. Check for a full path. if (strpos($Filename, '/') !== FALSE) { $Filename = '/' . ltrim($Filename, '/'); $Path = PATH_ROOT . $Filename; if (file_exists($Path)) { return array($Path, $Filename); } else { return FALSE; } } // 3. Check the theme. if ($Theme = Gdn::ThemeManager()->ThemeFromType($ThemeType)) { $Paths[] = array(PATH_THEMES . "/{$Theme}/design/{$Filename}", "/themes/{$Theme}/design/{$Filename}"); } if ($Folder) { // 4. Check static, a plugin or application. if (in_array($Folder, array('resources', 'static'))) { $path = "/resources/css/{$Filename}"; $Paths[] = array(PATH_ROOT . $path, $path); } elseif (StringBeginsWith($Folder, 'plugins/')) { $Folder = substr($Folder, strlen('plugins/')); $Paths[] = array(PATH_PLUGINS . "/{$Folder}/design/{$Filename}", "/plugins/{$Folder}/design/{$Filename}"); $Paths[] = array(PATH_PLUGINS . "/{$Folder}/{$Filename}", "/plugins/{$Folder}/{$Filename}"); } else { $Paths[] = array(PATH_APPLICATIONS . "/{$Folder}/design/{$Filename}", "/applications/{$Folder}/design/{$Filename}"); } } // 5. Check the default. if ($Folder != 'dashboard') { $Paths[] = array(PATH_APPLICATIONS . '/dashboard/design/$Filename', "/applications/dashboard/design/{$Filename}"); } foreach ($Paths as $Info) { if (file_exists($Info[0])) { return $Info; } } return FALSE; }
/** * Adds a JS file to search for in the application or global js folder(s). * * @param string $FileName The js file to search for. * @param string $AppFolder The application folder that should contain the JS file. Default is to use the application folder that this controller belongs to. */ public function addJsFile($FileName, $AppFolder = '', $Options = null) { $JsInfo = array('FileName' => $FileName, 'AppFolder' => $AppFolder, 'Options' => $Options); if (StringBeginsWith($AppFolder, 'plugins/')) { $Name = stringBeginsWith($AppFolder, 'plugins/', true, true); $Info = Gdn::pluginManager()->getPluginInfo($Name, Gdn_PluginManager::ACCESS_PLUGINNAME); if ($Info) { $JsInfo['Version'] = val('Version', $Info); } } else { $JsInfo['Version'] = APPLICATION_VERSION; } $this->_JsFiles[] = $JsInfo; }
} $Photo = $User->Photo; if ($User->Banned) { $BannedPhoto = C('Garden.BannedPhoto', 'http://cdn.vanillaforums.com/images/banned_large.png'); if ($BannedPhoto) { $Photo = Gdn_Upload::Url($BannedPhoto); } } if ($Photo) { ?> <div class="Photo PhotoWrap PhotoWrapLarge <?php echo GetValue('_CssClass', $User); ?> "> <?php if (StringBeginsWith($Photo, 'http')) { $Img = Img($Photo, array('class' => 'ProfilePhotoLarge')); } else { $Img = Img(Gdn_Upload::Url(ChangeBasename($Photo, 'p%s')), array('class' => 'ProfilePhotoLarge')); } if (!$User->Banned && (Gdn::Session()->UserID == $User->UserID || Gdn::Session()->CheckPermission('Garden.Users.Edit'))) { echo Anchor(Wrap(T('Change Picture')), '/profile/picture?userid=' . $User->UserID, 'ChangePicture'); } echo $Img; ?> </div> <?php } else { if ($User->UserID == Gdn::Session()->UserID || Gdn::Session()->CheckPermission('Garden.Users.Edit')) { ?> <div class="Photo"><?php
/** * Offers a quick and dirty way of parsing an addon's info array without using eval(). * @param string $Path The path to the info array. * @param string $Variable The name of variable containing the information. * @return array|false The info array or false if the file could not be parsed. */ public static function ParseInfoArray($Path, $Variable = FALSE) { $fp = fopen($Path, 'rb'); $Lines = array(); $InArray = FALSE; // Get all of the lines in the info array. while (($Line = fgets($fp)) !== FALSE) { // Remove comments from the line. $Line = preg_replace('`\\s//.*$`', '', $Line); if (!$Line) { continue; } if (!$InArray && preg_match('`\\$([A-Za-z]+Info)\\s*\\[`', trim($Line), $Matches)) { $Variable = $Matches[1]; if (preg_match('`\\[\\s*[\'"](.+?)[\'"]\\s*\\]`', $Line, $Matches)) { $GlobalKey = $Matches[1]; $InArray = TRUE; } } elseif ($InArray && StringEndsWith(trim($Line), ';')) { break; } elseif ($InArray) { $Lines[] = trim($Line); } } fclose($fp); if (count($Lines) == 0) { return FALSE; } // Parse the name/value information in the arrays. $Result = array(); foreach ($Lines as $Line) { // Get the name from the line. if (!preg_match('`[\'"](.+?)[\'"]\\s*=>`', $Line, $Matches) || !substr($Line, -1) == ',') { continue; } $Key = $Matches[1]; // Strip the key from the line. $Line = trim(trim(substr(strstr($Line, '=>'), 2)), ','); if (strlen($Line) == 0) { continue; } $Value = NULL; if (is_numeric($Line)) { $Value = $Line; } elseif (strcasecmp($Line, 'TRUE') == 0 || strcasecmp($Line, 'FALSE') == 0) { $Value = $Line; } elseif (in_array($Line[0], array('"', "'")) && substr($Line, -1) == $Line[0]) { $Quote = $Line[0]; $Value = trim($Line, $Quote); $Value = str_replace('\\' . $Quote, $Quote, $Value); } elseif (StringBeginsWith($Line, 'array(') && substr($Line, -1) == ')') { // Parse the line's array. $Line = substr($Line, 6, strlen($Line) - 7); $Items = explode(',', $Line); $Array = array(); foreach ($Items as $Item) { $SubItems = explode('=>', $Item); if (count($SubItems) == 1) { $Array[] = trim(trim($SubItems[0]), '"\''); } elseif (count($SubItems) == 2) { $SubKey = trim(trim($SubItems[0]), '"\''); $SubValue = trim(trim($SubItems[1]), '"\''); $Array[$SubKey] = $SubValue; } } $Value = $Array; } if ($Value != NULL) { $Result[$Key] = $Value; } } $Result = array($GlobalKey => $Result, 'Variable' => $Variable); return $Result; }
/** * Returns a platform-specific query to fetch column data from $Table. * * @param string $Table The name of the table to fetch column data from. */ public function FetchColumnSql($Table) { if ($Table[0] != '`' && !StringBeginsWith($Table, $this->Database->DatabasePrefix)) $Table = $this->Database->DatabasePrefix.$Table; return "show columns from ".$this->FormatTableName($Table); }
/** * Undocumented method. * * @todo Method RenderMaster() needs a description. */ 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)) { if (ArrayHasValue($this->_CssFiles, 'style.css')) { $this->AddCssFile('custom.css'); } if (ArrayHasValue($this->_CssFiles, 'admin.css')) { $this->AddCssFile('customadmin.css'); } $this->EventArguments['CssFiles'] =& $this->_CssFiles; $this->FireEvent('BeforeAddCss'); // And now search for/add all css files foreach ($this->_CssFiles as $CssInfo) { $CssFile = $CssInfo['FileName']; if (strpos($CssFile, '/') !== FALSE) { // A direct path to the file was given. $CssPaths = array(CombinePaths(array(PATH_ROOT, str_replace('/', DS, $CssFile)))); } else { $CssGlob = preg_replace('/(.*)(\\.css)/', '\\1*\\2', $CssFile); $AppFolder = $CssInfo['AppFolder']; if ($AppFolder == '') { $AppFolder = $this->ApplicationFolder; } // CSS comes from one of four places: $CssPaths = array(); if ($this->Theme) { // 1. Application-specific css. eg. root/themes/theme_name/app_name/design/ // $CssPaths[] = PATH_THEMES . DS . $this->Theme . DS . $AppFolder . DS . 'design' . DS . $CssGlob; // 2. Theme-wide theme view. eg. root/themes/theme_name/design/ // a) Check to see if a customized version of the css is there. if ($this->ThemeOptions) { $Filenames = GetValueR('Styles.Value', $this->ThemeOptions); if (is_string($Filenames) && $Filenames != '%s') { $CssPaths[] = PATH_THEMES . DS . $this->Theme . DS . 'design' . DS . ChangeBasename($CssFile, $Filenames); } } // b) Use the default filename. $CssPaths[] = PATH_THEMES . DS . $this->Theme . DS . 'design' . DS . $CssFile; } // 3. Application or plugin. if (StringBeginsWith($AppFolder, 'plugins/')) { // The css is coming from a plugin. $AppFolder = substr($AppFolder, strlen('plugins/')); $CssPaths[] = PATH_PLUGINS . "/{$AppFolder}/design/{$CssFile}"; $CssPaths[] = PATH_PLUGINS . "/{$AppFolder}/{$CssFile}"; } else { // Application default. eg. root/applications/app_name/design/ $CssPaths[] = PATH_APPLICATIONS . DS . $AppFolder . DS . 'design' . DS . $CssFile; } // 4. Garden default. eg. root/applications/dashboard/design/ $CssPaths[] = PATH_APPLICATIONS . DS . 'dashboard' . DS . 'design' . DS . $CssFile; } // Find the first file that matches the path. $CssPath = FALSE; foreach ($CssPaths as $Glob) { $Paths = SafeGlob($Glob); if (is_array($Paths) && count($Paths) > 0) { $CssPath = $Paths[0]; break; } } // Check to see if there is a CSS cacher. $CssCacher = Gdn::Factory('CssCacher'); if (!is_null($CssCacher)) { $CssPath = $CssCacher->Get($CssPath, $AppFolder); } if ($CssPath !== FALSE) { $CssPath = substr($CssPath, strlen(PATH_ROOT)); $CssPath = str_replace(DS, '/', $CssPath); $this->Head->AddCss($CssPath, 'all', TRUE, $CssInfo['Options']); } } // Add a custom js file. if (ArrayHasValue($this->_CssFiles, 'style.css')) { $this->AddJsFile('custom.js'); } // only to non-admin pages. // And now search for/add all JS files foreach ($this->_JsFiles as $Index => $JsInfo) { $JsFile = $JsInfo['FileName']; if (strpos($JsFile, '//') !== FALSE) { // This is a link to an external file. $this->Head->AddScript($JsFile); continue; } if (strpos($JsFile, '/') !== FALSE) { // A direct path to the file was given. $JsPaths = array(CombinePaths(array(PATH_ROOT, str_replace('/', DS, $JsFile)), DS)); } else { $AppFolder = $JsInfo['AppFolder']; if ($AppFolder == '') { $AppFolder = $this->ApplicationFolder; } // JS can come from a theme, an any of the application folder, or it can come from the global js folder: $JsPaths = array(); if ($this->Theme) { // 1. Application-specific js. eg. root/themes/theme_name/app_name/design/ $JsPaths[] = PATH_THEMES . DS . $this->Theme . DS . $AppFolder . DS . 'js' . DS . $JsFile; // 2. Garden-wide theme view. eg. root/themes/theme_name/design/ $JsPaths[] = PATH_THEMES . DS . $this->Theme . DS . 'js' . DS . $JsFile; } // 3. The application or plugin folder. if (StringBeginsWith(trim($AppFolder, '/'), 'plugins/')) { $JsPaths[] = PATH_PLUGINS . strstr($AppFolder, '/') . "/js/{$JsFile}"; $JsPaths[] = PATH_PLUGINS . strstr($AppFolder, '/') . "/{$JsFile}"; } else { $JsPaths[] = PATH_APPLICATIONS . "/{$AppFolder}/js/{$JsFile}"; } // 4. Global JS folder. eg. root/js/ $JsPaths[] = PATH_ROOT . DS . 'js' . DS . $JsFile; // 5. Global JS library folder. eg. root/js/library/ $JsPaths[] = PATH_ROOT . DS . 'js' . DS . 'library' . DS . $JsFile; } // Find the first file that matches the path. $JsPath = FALSE; foreach ($JsPaths as $Glob) { $Paths = SafeGlob($Glob); if (is_array($Paths) && count($Paths) > 0) { $JsPath = $Paths[0]; break; } } if ($JsPath !== FALSE) { $JsSrc = str_replace(array(PATH_ROOT, DS), array('', '/'), $JsPath); $Options = (array) $JsInfo['Options']; $Options['path'] = $JsPath; $Version = GetValue('Version', $JsInfo); if ($Version) { TouchValue('version', $Options, $Version); } $this->Head->AddScript($JsSrc, 'text/javascript', $Options); } } } // Add the favicon $this->Head->SetFavIcon(C('Garden.FavIcon', Asset('themes/' . $this->Theme . '/design/favicon.png'))); // 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. Application default. eg. root/app_name/views/ $MasterViewPaths[] = CombinePaths(array(PATH_APPLICATIONS, $this->ApplicationFolder, 'views', $this->MasterView . '.master*')); // 4. 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); } }
public function FetchPageInfo($Url, $ThrowError = FALSE) { $PageInfo = FetchPageInfo($Url, 3, $ThrowError); $Title = GetValue('Title', $PageInfo, ''); if ($Title == '') { if ($ThrowError) { throw new Gdn_UserException(T("The page didn't contain any information.")); } $Title = FormatString(T('Undefined discussion subject.'), array('Url' => $Url)); } else { if ($Strip = C('Vanilla.Embed.StripPrefix')) { $Title = StringBeginsWith($Title, $Strip, TRUE, TRUE); } if ($Strip = C('Vanilla.Embed.StripSuffix')) { $Title = StringEndsWith($Title, $Strip, TRUE, TRUE); } } $Title = trim($Title); $Description = GetValue('Description', $PageInfo, ''); $Images = GetValue('Images', $PageInfo, array()); $Body = FormatString(T('EmbeddedDiscussionFormat'), array('Title' => $Title, 'Excerpt' => $Description, 'Image' => count($Images) > 0 ? Img(GetValue(0, $Images), array('class' => 'LeftAlign')) : '', 'Url' => $Url)); if ($Body == '') { $Body = $ForeignUrl; } if ($Body == '') { $Body = FormatString(T('EmbeddedNoBodyFormat.'), array('Url' => $Url)); } $Result = array('Name' => $Title, 'Body' => $Body, 'Format' => 'Html'); return $Result; }
public function ScanPluginFile($PluginFile, $VariableName = NULL) { // Find the $PluginInfo array if (!file_exists($PluginFile)) { return; } $Lines = file($PluginFile); $InfoBuffer = FALSE; $ClassBuffer = FALSE; $ClassName = ''; $PluginInfoString = ''; if (!$VariableName) { $VariableName = 'PluginInfo'; } $ParseVariableName = '$' . $VariableName; ${$VariableName} = array(); foreach ($Lines as $Line) { if ($InfoBuffer && substr(trim($Line), -2) == ');') { $PluginInfoString .= $Line; $ClassBuffer = TRUE; $InfoBuffer = FALSE; } if (StringBeginsWith(trim($Line), $ParseVariableName)) { $InfoBuffer = TRUE; } if ($InfoBuffer) { $PluginInfoString .= $Line; } if ($ClassBuffer && strtolower(substr(trim($Line), 0, 6)) == 'class ') { $Parts = explode(' ', $Line); if (count($Parts) > 2) { $ClassName = $Parts[1]; } break; } } unset($Lines); if ($PluginInfoString != '') { eval($PluginInfoString); } // Define the folder name and assign the class name for the newly added item if (isset(${$VariableName}) && is_array(${$VariableName})) { $Item = array_pop($Trash = array_keys(${$VariableName})); ${$VariableName}[$Item]['Index'] = $Item; ${$VariableName}[$Item]['ClassName'] = $ClassName; ${$VariableName}[$Item]['PluginFilePath'] = $PluginFile; ${$VariableName}[$Item]['PluginRoot'] = dirname($PluginFile); if (!array_key_exists('Name', ${$VariableName}[$Item])) { ${$VariableName}[$Item]['Name'] = $Item; } if (!array_key_exists('Folder', ${$VariableName}[$Item])) { ${$VariableName}[$Item]['Folder'] = $Item; } return ${$VariableName}[$Item]; } elseif ($VariableName !== NULL) { if (isset(${$VariableName})) { return ${$VariableName}; } } return NULL; }
/** * Execute a single validation rule and return its result. * * @param mixed $Value The value to validate. * @param string $FieldName The name of the field to put into the error result. * @param string|array $Rule The rule to validate which can be one of the following. * - string: The name of a function used to validate the value. * - 'regex:<regex>': The regular expression used to validate the value. * - array: An array with the following keys: * - Name: The name of the function used to validate. * - Args: An argument to pass to the function after the value. * @param string $CustomError A custom error message. * @return bool|string One of the following * - TRUE: The value passed validation. * - string: The error message associated with the error. */ public static function ValidateRule($Value, $FieldName, $Rule, $CustomError = FALSE) { // Figure out the type of rule. if (is_string($Rule)) { if (StringBeginsWith($Rule, 'regex:', TRUE)) { $RuleName = 'regex'; $Args = substr($Rule, 6); } elseif (StringBeginsWith($Rule, 'function:', TRUE)) { $RuleName = substr($Rule, 9); } else { $RuleName = $Rule; } } elseif (is_array($Rule)) { $RuleName = GetValue('Name', $Rule); $Args = GetValue('Args', $Rule); } if (!isset($Args)) { $Args = NULL; } if (function_exists($RuleName)) { $Result = $RuleName($Value, $Args); if ($Result === TRUE) { return TRUE; } elseif ($CustomError) { return $CustomError; } elseif (is_string($Result)) { return $Result; } else { return sprintf(T($RuleName), T($FieldName)); } } else { return sprintf('Validation does not exist: %s.', $RuleName); } }
function ExternalUrl($Path) { $Format = C('Garden.ExternalUrlFormat'); if ($Format && !StringBeginsWith($Path, 'http')) { $Result = sprintf($Format, ltrim($Path, '/')); } else { $Result = Url($Path, TRUE); } return $Result; }
/** * Modifies $this->Table() with the columns specified with $this->Column(). * * @param boolean $Explicit If TRUE, this method will remove any columns from the table that were not * defined with $this->Column(). */ protected function _Modify($Explicit = FALSE) { $Px = $this->_DatabasePrefix; $AdditionalSql = array(); // statements executed at the end // Returns an array of schema data objects for each field in the specified // table. The returned array of objects contains the following properties: // Name, PrimaryKey, Type, AllowNull, Default, Length, Enum. $ExistingColumns = $this->ExistingColumns(); $AlterSql = array(); // 1. Remove any unnecessary columns if this is an explicit modification if ($Explicit) { // array_diff returns values from the first array that aren't present // in the second array. In this example, all columns currently in the // table that are NOT in $this->_Columns. $RemoveColumns = array_diff(array_keys($ExistingColumns), array_keys($this->_Columns)); foreach ($RemoveColumns as $Column) { $AlterSql[] = "drop column `{$Column}`"; } } // Prepare the alter query $AlterSqlPrefix = 'alter table `' . $this->_DatabasePrefix . $this->_TableName . "`\n"; // 2. Alter the table storage engine. $ForceDatabaseEngine = C('Database.ForceStorageEngine'); if ($ForceDatabaseEngine && !$this->_TableStorageEngine) { $this->_TableStorageEngine = $ForceDatabaseEngine; } $Indexes = $this->_IndexSql($this->_Columns); $IndexesDb = $this->_IndexSqlDb(); if ($this->_TableStorageEngine) { $CurrentEngine = $this->Database->Query("show table status where name = '" . $this->_DatabasePrefix . $this->_TableName . "'")->Value('Engine'); if (strcasecmp($CurrentEngine, $this->_TableStorageEngine)) { // Check to drop a fulltext index if we don't support it. if (!$this->_SupportsFulltext()) { foreach ($IndexesDb as $IndexName => $IndexSql) { if (StringBeginsWith($IndexSql, 'fulltext', TRUE)) { $DropIndexQuery = "{$AlterSqlPrefix} drop index {$IndexName};\n"; if (!$this->Query($DropIndexQuery)) { throw new Exception(sprintf(T('Failed to drop the index `%1$s` on table `%2$s`.'), $IndexName, $this->_TableName)); } } } } $EngineQuery = $AlterSqlPrefix . ' engine = ' . $this->_TableStorageEngine; if (!$this->Query($EngineQuery)) { throw new Exception(sprintf(T('Failed to alter the storage engine of table `%1$s` to `%2$s`.'), $this->_DatabasePrefix . $this->_TableName, $this->_TableStorageEngine)); } } } // 3. Add new columns & modify existing ones // array_diff returns values from the first array that aren't present in // the second array. In this example, all columns in $this->_Columns that // are NOT in the table. $PrevColumnName = FALSE; foreach ($this->_Columns as $ColumnName => $Column) { if (!array_key_exists($ColumnName, $ExistingColumns)) { // This column name is not in the existing column collection, so add the column $AddColumnSql = 'add ' . $this->_DefineColumn(GetValue($ColumnName, $this->_Columns)); if ($PrevColumnName !== FALSE) { $AddColumnSql .= " after `{$PrevColumnName}`"; } $AlterSql[] = $AddColumnSql; // if (!$this->Query($AlterSqlPrefix.$AddColumnSql)) // throw new Exception(sprintf(T('Failed to add the `%1$s` column to the `%1$s` table.'), $Column, $this->_DatabasePrefix.$this->_TableName)); } else { $ExistingColumn = $ExistingColumns[$ColumnName]; $ExistingColumnDef = $this->_DefineColumn($ExistingColumn); $ColumnDef = $this->_DefineColumn($Column); $Comment = "/* Existing: {$ExistingColumnDef}, New: {$ColumnDef} */\n"; if ($ExistingColumnDef != $ColumnDef) { //$Column->Type != $ExistingColumn->Type || $Column->AllowNull != $ExistingColumn->AllowNull || ($Column->Length != $ExistingColumn->Length && !in_array($Column->Type, array('tinyint', 'smallint', 'int', 'bigint', 'float', 'double')))) { // The existing & new column types do not match, so modify the column. $ChangeSql = $Comment . 'change `' . $ColumnName . '` ' . $this->_DefineColumn(GetValue($ColumnName, $this->_Columns)); $AlterSql[] = $ChangeSql; // if (!$this->Query($AlterSqlPrefix.$ChangeSql)) // throw new Exception(sprintf(T('Failed to modify the data type of the `%1$s` column on the `%2$s` table.'), // $ColumnName, // $this->_DatabasePrefix.$this->_TableName)); // Check for a modification from an enum to an int. if (strcasecmp($ExistingColumn->Type, 'enum') == 0 && in_array(strtolower($Column->Type), $this->Types('int'))) { $Sql = "update `{$Px}{$this->_TableName}` set `{$ColumnName}` = case `{$ColumnName}`"; foreach ($ExistingColumn->Enum as $Index => $NewValue) { $OldValue = $Index + 1; if (!is_numeric($NewValue)) { continue; } $NewValue = (int) $NewValue; $Sql .= " when {$OldValue} then {$NewValue}"; } $Sql .= " else `{$ColumnName}` end"; $Description = "Update {$this->_TableName}.{$ColumnName} enum values to {$Column->Type}"; $AdditionalSql[$Description] = $Sql; } } } $PrevColumnName = $ColumnName; } if (count($AlterSql) > 0) { if (!$this->Query($AlterSqlPrefix . implode(",\n", $AlterSql))) { throw new Exception(sprintf(T('Failed to alter the `%s` table.'), $this->_DatabasePrefix . $this->_TableName)); } } // 4. Update Indexes. $IndexSql = array(); // Go through the indexes to add or modify. foreach ($Indexes as $Name => $Sql) { if (array_key_exists($Name, $IndexesDb)) { if ($Indexes[$Name] != $IndexesDb[$Name]) { if ($Name == 'PRIMARY') { $IndexSql[$Name] = $AlterSqlPrefix . "drop primary key;\n"; } else { $IndexSql[$Name] = $AlterSqlPrefix . 'drop index ' . $Name . ";\n"; } $IndexSql[$Name] .= $AlterSqlPrefix . "add {$Sql};\n"; } unset($IndexesDb[$Name]); } else { $IndexSql[$Name] = $AlterSqlPrefix . "add {$Sql};\n"; } } // Go through the indexes to drop. if ($Explicit) { foreach ($IndexesDb as $Name => $Sql) { if ($Name == 'PRIMARY') { $IndexSql[$Name] = $AlterSqlPrefix . "drop primary key;\n"; } else { $IndexSql[$Name] = $AlterSqlPrefix . 'drop index ' . $Name . ";\n"; } } } // Modify all of the indexes. foreach ($IndexSql as $Name => $Sql) { if (!$this->Query($Sql)) { throw new Exception(sprintf(T('Error.ModifyIndex', 'Failed to add or modify the `%1$s` index in the `%2$s` table.'), $Name, $this->_TableName)); } } // Run any additional Sql. foreach ($AdditionalSql as $Description => $Sql) { if (!$this->Query($Sql)) { throw new Exception("Error modifying table: {$Description}."); } } $this->Reset(); return TRUE; }