/** * @return LightOpenID */ public function GetOpenID() { if (get_magic_quotes_gpc()) { foreach ($_GET as $Name => $Value) { $_GET[$Name] = stripslashes($Value); } } $OpenID = new LightOpenID(); if (isset($_GET['url'])) $OpenID->identity = $_GET['url']; $Url = Url('/entry/connect/openid', TRUE); $UrlParts = explode('?', $Url); parse_str(GetValue(1, $UrlParts, ''), $Query); $Query = array_merge($Query, ArrayTranslate($_GET, array('display', 'Target'))); $OpenID->returnUrl = $UrlParts[0].'?'.http_build_query($Query); $OpenID->required = array('contact/email', 'namePerson/first', 'namePerson/last', 'pref/language'); $this->EventArguments['OpenID'] = $OpenID; $this->FireEvent('GetOpenID'); return $OpenID; }
/** * Render a breadcrumb trail for the user based on the page they are on. */ function smarty_function_breadcrumbs($Params, &$Smarty) { $Breadcrumbs = $Smarty->Controller->Data('Breadcrumbs'); if (!is_array($Breadcrumbs)) { $Breadcrumbs = array(); } $Options = ArrayTranslate($Params, array('homeurl' => 'HomeUrl', 'hidelast' => 'HideLast')); return Gdn_Theme::Breadcrumbs($Breadcrumbs, GetValue('homelink', $Params, TRUE), $Options); }
/** * * * @param Gdn_Controller $Sender * @param array $Args */ public function profileController_jsConnect_create($Sender, $Args = array()) { include_once dirname(__FILE__) . '/functions.jsconnect.php'; $client_id = $Sender->Request->get('client_id', 0); $Provider = self::getProvider($client_id); $client_id = val('AuthenticationKey', $Provider); $Secret = val('AssociationSecret', $Provider); if (Gdn::session()->isValid()) { $User = ArrayTranslate((array) Gdn::session()->User, array('UserID' => 'UniqueID', 'Name', 'Email', 'PhotoUrl', 'DateOfBirth', 'Gender')); // Grab the user's roles. $Roles = Gdn::userModel()->getRoles(Gdn::session()->UserID); $Roles = array_column($Roles, 'Name'); $User['Roles'] = ''; if (is_array($Roles) && sizeof($Roles)) { $User['Roles'] = implode(',', $Roles); } if (!$User['PhotoUrl'] && function_exists('UserPhotoDefaultUrl')) { $User['PhotoUrl'] = Url(UserPhotoDefaultUrl(Gdn::session()->User), true); } } else { $User = []; } ob_clean(); writeJsConnect($User, $Sender->Request->get(), $client_id, $Secret, val('HashType', $Provider, true)); exit; }
/** * Modifies category data before it is returned. * * Adds CountAllDiscussions column to each category representing the sum of * discussions within this category as well as all subcategories. * * @since 2.0.17 * @access public * * @param object $Data SQL result. */ public static function AddCategoryColumns($Data) { $Result =& $Data->Result(); $Result2 = $Result; foreach ($Result as &$Category) { if (!property_exists($Category, 'CountAllDiscussions')) { $Category->CountAllDiscussions = $Category->CountDiscussions; } if (!property_exists($Category, 'CountAllComments')) { $Category->CountAllComments = $Category->CountComments; } // Calculate the following field. $Following = !((bool) GetValue('Archived', $Category) || (bool) GetValue('Unfollow', $Category)); $Category->Following = $Following; $DateMarkedRead = GetValue('DateMarkedRead', $Category); $UserDateMarkedRead = GetValue('UserDateMarkedRead', $Category); if (!$DateMarkedRead) { $DateMarkedRead = $UserDateMarkedRead; } elseif ($UserDateMarkedRead && Gdn_Format::ToTimestamp($UserDateMarkedRead) > Gdn_Format::ToTimeStamp($DateMarkedRead)) { $DateMarkedRead = $UserDateMarkedRead; } // Set appropriate Last* columns. SetValue('LastTitle', $Category, GetValue('LastDiscussionTitle', $Category, NULL)); $LastDateInserted = GetValue('LastDateInserted', $Category, NULL); if (GetValue('LastCommentUserID', $Category) == NULL) { SetValue('LastCommentUserID', $Category, GetValue('LastDiscussionUserID', $Category, NULL)); SetValue('DateLastComment', $Category, GetValue('DateLastDiscussion', $Category, NULL)); SetValue('LastUserID', $Category, GetValue('LastDiscussionUserID', $Category, NULL)); $LastDiscussion = ArrayTranslate($Category, array('LastDiscussionID' => 'DiscussionID', 'CategoryID' => 'CategoryID', 'LastTitle' => 'Name')); SetValue('LastUrl', $Category, DiscussionUrl($LastDiscussion, FALSE, '//') . '#latest'); if (is_null($LastDateInserted)) { SetValue('LastDateInserted', $Category, GetValue('DateLastDiscussion', $Category, NULL)); } } else { $LastDiscussion = ArrayTranslate($Category, array('LastDiscussionID' => 'DiscussionID', 'CategoryID' => 'CategoryID', 'LastTitle' => 'Name')); SetValue('LastUserID', $Category, GetValue('LastCommentUserID', $Category, NULL)); SetValue('LastUrl', $Category, DiscussionUrl($LastDiscussion, FALSE, '//') . '#latest'); if (is_null($LastDateInserted)) { SetValue('LastDateInserted', $Category, GetValue('DateLastComment', $Category, NULL)); } } $LastDateInserted = GetValue('LastDateInserted', $Category, NULL); if ($DateMarkedRead) { if ($LastDateInserted) { $Category->Read = Gdn_Format::ToTimestamp($DateMarkedRead) >= Gdn_Format::ToTimestamp($LastDateInserted); } else { $Category->Read = TRUE; } } else { $Category->Read = FALSE; } foreach ($Result2 as $Category2) { if ($Category2->TreeLeft > $Category->TreeLeft && $Category2->TreeRight < $Category->TreeRight) { $Category->CountAllDiscussions += $Category2->CountDiscussions; $Category->CountAllComments += $Category2->CountComments; } } } }
/** * Get meta data of a single conversation. * * @since 2.0.0 * @access public * * @param int $ConversationID Unique ID of conversation. * @param int $ViewingUserID Unique ID of current user. * @return Gdn_DataSet SQL result (single row). */ public function GetID($ConversationID, $ViewingUserID = FALSE) { // Get the conversation. $Conversation = $this->GetWhere(array('ConversationID' => $ConversationID))->FirstRow(DATASET_TYPE_ARRAY); if ($ViewingUserID) { $Data = $this->SQL->GetWhere('UserConversation', array('ConversationID' => $ConversationID, 'UserID' => $ViewingUserID))->FirstRow(DATASET_TYPE_ARRAY); // Convert the array. $UserConversation = ArrayTranslate($Data, array('LastMessageID', 'CountReadMessages', 'DateLastViewed', 'Bookmarked')); $UserConversation['CountNewMessages'] = $Conversation['CountMessages'] - $Data['CountReadMessages']; } else { $UserConversation = array('CountNewMessages' => 0, 'CountReadMessages' => $Conversation['CountMessages'], 'DateLastViewed' => $Conversation['DateUpdated']); } $Conversation = array_merge($Conversation, $UserConversation); return (object) $Conversation; }
/** * Check an addon's file to extract the addon information out of it. * * @param string $Path The path to the file. * @param bool $Fix Whether or not to fix files that have been zipped incorrectly. * @return array An array of addon information. */ public static function AnalyzeAddon($Path, $ThrowError = TRUE) { if (!file_exists($Path)) { if ($ThrowError) { throw new Exception("{$Path} not found.", 404); } return FALSE; } $Result = array(); $InfoPaths = array('/settings/about.php', '/default.php', '/class.*.plugin.php', '/about.php', '/definitions.php', '/index.php', 'vanilla2export.php'); // Get the list of potential files to analyze. if (is_dir($Path)) { $Entries = self::_GetInfoFiles($Path, $InfoPaths); } else { $Entries = self::_GetInfoZip($Path, $InfoPaths, FALSE, $ThrowError); $DeleteEntries = TRUE; } foreach ($Entries as $Entry) { if ($Entry['Name'] == '/index.php') { // This could be the core vanilla package. $Version = self::ParseCoreVersion($Entry['Path']); if (!$Version) { continue; } // The application was confirmed. $Addon = array('AddonKey' => 'vanilla', 'AddonTypeID' => ADDON_TYPE_CORE, 'Name' => 'Vanilla', 'Description' => 'Vanilla is an open-source, standards-compliant, multi-lingual, fully extensible discussion forum for the web. Anyone who has web-space that meets the requirements can download and use Vanilla for free!', 'Version' => $Version, 'Path' => $Entry['Path']); break; } elseif ($Entry['Name'] == 'vanilla2export.php') { // This could be the vanilla porter. $Version = self::ParseCoreVersion($Entry['Path']); if (!$Version) { continue; } $Addon = array('AddonKey' => 'porter', 'AddonTypeID' => ADDON_TYPE_CORE, 'Name' => 'Vanilla Porter', 'Description' => 'Drop this script in your existing site and navigate to it in your web browser to export your existing forum data to the Vanilla 2 import format.', 'Version' => $Version, 'Path' => $Entry['Path']); break; } else { // This could be an addon. $Info = self::ParseInfoArray($Entry['Path']); if (!is_array($Info) && count($Info)) { continue; } $Key = key($Info); $Variable = $Info['Variable']; $Info = $Info[$Key]; // Validate the addon. $Name = $Entry['Name']; $Valid = TRUE; if (!GetValue('Name', $Info)) { $Info['Name'] = $Key; } if (!GetValue('Description', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Description')); $Valid = FALSE; } if (!GetValue('Version', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Version')); $Valid = FALSE; } if (isset($Entry['Base']) && strcasecmp($Entry['Base'], $Key) != 0 && $Variable != 'ThemeInfo') { $Result[] = "{$Name}: The addon's key is not the same as its folder name."; $Valid = FALSE; } if (!$Valid) { continue; } // The addon is valid. $Addon = array_merge(array('AddonKey' => $Key, 'AddonTypeID' => ''), $Info); switch ($Variable) { case 'ApplicationInfo': $Addon['AddonTypeID'] = ADDON_TYPE_APPLICATION; break; case 'LocaleInfo': $Addon['AddonTypeID'] = ADDON_TYPE_LOCALE; break; case 'PluginInfo': $Addon['AddonTypeID'] = ADDON_TYPE_PLUGIN; break; case 'ThemeInfo': $Addon['AddonTypeID'] = ADDON_TYPE_THEME; break; } } } if ($DeleteEntries) { $FolderPath = substr($Path, 0, -4); Gdn_FileSystem::RemoveFolder($FolderPath); } // Add the addon requirements. if ($Addon) { $Requirements = ArrayTranslate($Addon, array('RequiredApplications' => 'Applications', 'RequiredPlugins' => 'Plugins', 'RequiredThemes' => 'Themes')); foreach ($Requirements as $Type => $Items) { if (!is_array($Items)) { unset($Requirements[$Type]); } } $Addon['Requirements'] = serialize($Requirements); $Addon['Checked'] = TRUE; $Addon['Path'] = $Path; $UploadsPath = PATH_UPLOADS . '/'; if (StringBeginsWith($Addon['Path'], $UploadsPath)) { $Addon['File'] = substr($Addon['Path'], strlen($UploadsPath)); } if (is_file($Path)) { $Addon['MD5'] = md5_file($Path); $Addon['FileSize'] = filesize($Path); } } elseif ($ThrowError) { $Msg = implode("\n", $Result); throw new Gdn_UserException($Msg, 400); } else { return FALSE; } return $Addon; // Figure out what kind of addon this is. $Root = ''; $NewRoot = ''; $Addon = FALSE; foreach ($Entries as $Entry) { $Name = '/' . ltrim($Entry['name'], '/'); $Filename = basename($Name); $Folder = substr($Name, 0, -strlen($Filename)); $NewRoot = ''; // Check to see if the entry is a plugin file. if ($Filename == 'default.php' || StringEndsWith($Filename, '.plugin.php')) { if (count(explode('/', $Folder)) > 3) { // The file is too deep to be a plugin file. continue; } // This could be a plugin file, but we have to examine its info array. $Zip->extractTo($FolderPath, $Entry['name']); $FilePath = CombinePaths(array($FolderPath, $Name)); $Info = self::ParseInfoArray($FilePath, 'PluginInfo'); Gdn_FileSystem::RemoveFolder(dirname($FilePath)); if (!is_array($Info) || !count($Info)) { continue; } // Check to see if the info array conforms to a plugin spec. $Key = key($Info); $Info = $Info[$Key]; $Root = trim($Folder, '/'); $Valid = TRUE; // Make sure the key matches the folder name. if ($Root && strcasecmp($Root, $Key) != 0) { $Result[] = "{$Name}: The plugin's key is not the same as its folder name."; $Valid = FALSE; } else { $NewRoot = $Root; } if (!GetValue('Description', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Description')); $Valid = FALSE; } if (!GetValue('Version', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Version')); $Valid = FALSE; } if ($Valid) { // The plugin was confirmed. $Addon = array('AddonKey' => $Key, 'AddonTypeID' => ADDON_TYPE_PLUGIN, 'Name' => GetValue('Name', $Info) ? $Info['Name'] : $Key, 'Description' => $Info['Description'], 'Version' => $Info['Version'], 'Path' => $Path); break; } continue; } // Check to see if the entry is an application file. if (StringEndsWith($Name, '/settings/about.php')) { if (count(explode('/', $Folder)) > 4) { $Result[] = "{$Name}: The application's info array was not in the correct location."; // The file is too deep to be a plugin file. continue; } // This could be a plugin file, but we have to examine its info array. $Zip->extractTo($FolderPath, $Entry['name']); $FilePath = CombinePaths(array($FolderPath, $Name)); $Info = self::ParseInfoArray($FilePath, 'ApplicationInfo'); Gdn_FileSystem::RemoveFolder(dirname($FilePath)); if (!is_array($Info) || !count($Info)) { $Result[] = "{$Name}: The application's info array could not be parsed."; continue; } $Key = key($Info); $Info = $Info[$Key]; $Root = trim(substr($Name, 0, -strlen('/settings/about.php')), '/'); $Valid = TRUE; // Make sure the key matches the folder name. if ($Root && strcasecmp($Root, $Key) != 0) { $Result[] = "{$Name}: The application's key is not the same as its folder name."; $Valid = FALSE; } else { $NewRoot = $Root; } if (!GetValue('Description', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Description')); $Valid = FALSE; } if (!GetValue('Version', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Version')); $Valid = FALSE; } if ($Valid) { // The application was confirmed. $Addon = array('AddonKey' => $Key, 'AddonTypeID' => ADDON_TYPE_APPLICATION, 'Name' => GetValue('Name', $Info) ? $Info['Name'] : $Key, 'Description' => $Info['Description'], 'Version' => $Info['Version'], 'Path' => $Path); break; } continue; } // Check to see if the entry is a theme file. if (StringEndsWith($Name, '/about.php')) { if (count(explode('/', $Folder)) > 3) { // The file is too deep to be a plugin file. continue; } // This could be a theme file, but we have to examine its info array. $Zip->extractTo($FolderPath, $Entry['name']); $FilePath = CombinePaths(array($FolderPath, $Name)); $Info = self::ParseInfoArray($FilePath, 'ThemeInfo'); Gdn_FileSystem::RemoveFolder(dirname($FilePath)); if (!is_array($Info) || !count($Info)) { continue; } $Key = key($Info); $Info = $Info[$Key]; $Valid = TRUE; $Root = trim(substr($Name, 0, -strlen('/about.php')), '/'); // Make sure the theme is at least one folder deep. if (strlen($Root) == 0) { $Result[] = $Name . ': The theme must be in a folder.'; $Valid = FALSE; } if (!GetValue('Description', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Description')); $Valid = FALSE; } if (!GetValue('Version', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Version')); $Valid = FALSE; } if ($Valid) { // The application was confirmed. $Addon = array('AddonKey' => $Key, 'AddonTypeID' => ADDON_TYPE_THEME, 'Name' => GetValue('Name', $Info) ? $Info['Name'] : $Key, 'Description' => $Info['Description'], 'Version' => $Info['Version'], 'Path' => $Path); break; } } if (StringEndsWith($Name, '/definitions.php')) { if (count(explode('/', $Folder)) > 3) { // The file is too deep to be a plugin file. continue; } // This could be a locale pack, but we have to examine its info array. $Zip->extractTo($FolderPath, $Entry['name']); $FilePath = CombinePaths(array($FolderPath, $Name)); $Info = self::ParseInfoArray($FilePath, 'LocaleInfo'); Gdn_FileSystem::RemoveFolder(dirname($FilePath)); if (!is_array($Info) || !count($Info)) { continue; } $Key = key($Info); $Info = $Info[$Key]; $Valid = TRUE; $Root = trim(substr($Name, 0, -strlen('/definitions.php')), '/'); // Make sure the locale is at least one folder deep. if ($Root != $Key) { $Result[] = $Name . ': The locale pack\'s key must be the same as its folder name.'; $Valid = FALSE; } if (!GetValue('Locale', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Locale')); $Valud = FALSE; } elseif (strcasecmp($Info['Locale'], $Key) == 0) { $Result[] = $Name . ': ' . T('The locale\'s key cannot be the same as the name of the locale.'); $Valid = FALSE; } if (!GetValue('Description', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Description')); $Valid = FALSE; } if (!GetValue('Version', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Version')); $Valid = FALSE; } if ($Valid) { // The locale pack was confirmed. $Addon = array('AddonKey' => $Key, 'AddonTypeID' => ADDON_TYPE_LOCALE, 'Name' => GetValue('Name', $Info) ? $Info['Name'] : $Key, 'Description' => $Info['Description'], 'Version' => $Info['Version'], 'Path' => $Path); break; } } // Check to see if the entry is a core file. if (StringEndsWith($Name, '/index.php')) { if (count(explode('/', $Folder)) != 3) { // The file is too deep to be the core's index.php continue; } // This could be a theme file, but we have to examine its info array. $Zip->extractTo($FolderPath, $Entry['name']); $FilePath = CombinePaths(array($FolderPath, $Name)); // Get the version number from the core. $Version = self::ParseCoreVersion($FilePath); if (!$Version) { continue; } // The application was confirmed. $Addon = array('AddonKey' => 'vanilla', 'AddonTypeID' => ADDON_TYPE_CORE, 'Name' => 'Vanilla', 'Description' => 'Vanilla is an open-source, standards-compliant, multi-lingual, fully extensible discussion forum for the web. Anyone who has web-space that meets the requirements can download and use Vanilla for free!', 'Version' => $Version, 'Path' => $Path); $Info = array(); break; } } if ($Addon) { // Add the requirements. $Requirements = ArrayTranslate($Info, array('RequiredApplications' => 'Applications', 'RequiredPlugins' => 'Plugins', 'RequiredThemes' => 'Themes')); foreach ($Requirements as $Type => $Items) { if (!is_array($Items)) { unset($Requirements[$Type]); } } $Addon['Requirements'] = serialize($Requirements); $Addon['Checked'] = TRUE; $UploadsPath = PATH_ROOT . '/uploads/'; if (StringBeginsWith($Addon['Path'], $UploadsPath)) { $Addon['File'] = substr($Addon['Path'], strlen($UploadsPath)); } if ($Fix) { // Delete extraneous files. foreach ($Deletes as $Delete) { $Zip->deleteName($Delete['name']); } } } $Zip->close(); if (file_exists($FolderPath)) { Gdn_FileSystem::RemoveFolder($FolderPath); } if ($Addon) { $Addon['MD5'] = md5_file($Path); $Addon['FileSize'] = filesize($Path); return $Addon; } else { if ($ThrowError) { $Msg = implode("\n", $Result); throw new Exception($Msg, 400); } else { return FALSE; } } }
/** * Add a method to the ModerationController to handle merging discussions. * @param Gdn_Controller $Sender */ public function ModerationController_MergeDiscussions_Create($Sender) { $Session = Gdn::Session(); $Sender->Form = new Gdn_Form(); $Sender->Title(T('Merge Discussions')); $DiscussionModel = new DiscussionModel(); $CheckedDiscussions = Gdn::UserModel()->GetAttribute($Session->User->UserID, 'CheckedDiscussions', array()); if (!is_array($CheckedDiscussions)) { $CheckedDiscussions = array(); } $DiscussionIDs = $CheckedDiscussions; $Sender->SetData('DiscussionIDs', $DiscussionIDs); $CountCheckedDiscussions = count($DiscussionIDs); $Sender->SetData('CountCheckedDiscussions', $CountCheckedDiscussions); $Discussions = $DiscussionModel->SQL->WhereIn('DiscussionID', $DiscussionIDs)->Get('Discussion')->ResultArray(); $Sender->SetData('Discussions', $Discussions); // Perform the merge if ($Sender->Form->AuthenticatedPostBack()) { // Create a new discussion record $MergeDiscussion = FALSE; $MergeDiscussionID = $Sender->Form->GetFormValue('MergeDiscussionID'); foreach ($Discussions as $Discussion) { if ($Discussion['DiscussionID'] == $MergeDiscussionID) { $MergeDiscussion = $Discussion; break; } } $RedirectLink = $Sender->Form->GetFormValue('RedirectLink'); if ($MergeDiscussion) { $ErrorCount = 0; // Verify that the user has permission to perform the merge. $Category = CategoryModel::Categories($MergeDiscussion['CategoryID']); if ($Category && !$Category['PermsDiscussionsEdit']) { throw PermissionException('Vanilla.Discussions.Edit'); } $DiscussionModel->DefineSchema(); $MaxNameLength = GetValue('Length', $DiscussionModel->Schema->GetField('Name')); // Assign the comments to the new discussion record $DiscussionModel->SQL->Update('Comment')->Set('DiscussionID', $MergeDiscussionID)->WhereIn('DiscussionID', $DiscussionIDs)->Put(); $CommentModel = new CommentModel(); foreach ($Discussions as $Discussion) { if ($Discussion['DiscussionID'] == $MergeDiscussionID) { continue; } // Create a comment out of the discussion. $Comment = ArrayTranslate($Discussion, array('Body', 'Format', 'DateInserted', 'InsertUserID', 'InsertIPAddress', 'DateUpdated', 'UpdateUserID', 'UpdateIPAddress', 'Attributes', 'Spam', 'Likes', 'Abuse')); $Comment['DiscussionID'] = $MergeDiscussionID; $CommentModel->Validation->Results(TRUE); $CommentID = $CommentModel->Save($Comment); if ($CommentID) { // Move any attachments (FileUpload plugin awareness) if (class_exists('MediaModel')) { $MediaModel = new MediaModel(); $MediaModel->Reassign($Discussion['DiscussionID'], 'discussion', $CommentID, 'comment'); } if ($RedirectLink) { // The discussion needs to be changed to a moved link. $RedirectDiscussion = array('Name' => SliceString(sprintf(T('Merged: %s'), $Discussion['Name']), $MaxNameLength), 'Type' => 'redirect', 'Body' => FormatString(T('This discussion has been <a href="{url,html}">merged</a>.'), array('url' => DiscussionUrl($MergeDiscussion))), 'Format' => 'Html'); $DiscussionModel->SetField($Discussion['DiscussionID'], $RedirectDiscussion); $CommentModel->UpdateCommentCount($Discussion['DiscussionID']); $CommentModel->RemovePageCache($Discussion['DiscussionID']); } else { // Delete discussion that was merged. $DiscussionModel->Delete($Discussion['DiscussionID']); } } else { $Sender->InformMessage($CommentModel->Validation->ResultsText()); $ErrorCount++; } } // Update counts on all affected discussions. $CommentModel->UpdateCommentCount($MergeDiscussionID); $CommentModel->RemovePageCache($MergeDiscussionID); // Clear selections Gdn::UserModel()->SaveAttribute($Session->UserID, 'CheckedDiscussions', FALSE); ModerationController::InformCheckedDiscussions($Sender); if ($ErrorCount == 0) { $Sender->JsonTarget('', '', 'Refresh'); } } } $Sender->Render('MergeDiscussions', '', 'plugins/SplitMerge'); }
/** * Change ban data on a user (ban or unban them). * * @since 2.0.18 * @access public * * @param array $User * @param bool $BannedValue Whether user is banned. */ public function SaveUser($User, $BannedValue, $Ban = FALSE) { $Banned = $User['Banned']; if ($Banned == $BannedValue) { return; } Gdn::UserModel()->SetField($User['UserID'], 'Banned', $BannedValue); // Add the activity. $ActivityModel = new ActivityModel(); $Activity = array('ActivityType' => 'Ban', 'ActivityUserID' => $User['UserID'], 'RegardingUserID' => Gdn::Session()->UserID, 'NotifyUserID' => ActivityModel::NOTIFY_MODS); $BannedString = $BannedValue ? 'banned' : 'unbanned'; if ($Ban) { $Activity['HeadlineFormat'] = '{ActivityUserID,user} was ' . $BannedString . ' (based on {Data.BanType}: {Data.BanValue}).'; $Activity['Data'] = ArrayTranslate($Ban, array('BanType', 'BanValue')); $Activity['Story'] = $Ban['Notes']; $Activity['RecordType'] = 'Ban'; if (isset($Ban['BanID'])) { $Activity['BanID'] = $Ban['BanID']; } } else { $Activity['HeadlineFormat'] = '{ActivityUserID,user} was ' . $BannedString . '.'; } $ActivityModel->Save($Activity); }
public function EntryController_Twauthorize_Create($Sender, $Dir = '') { $Query = ArrayTranslate($Sender->Request->Get(), array('display', 'Target')); $Query = http_build_query($Query); if ($Dir == 'profile') { // This is a profile connection. $this->RedirectUri(self::ProfileConnecUrl()); } $this->Authorize($Query); }
/** * Get the high-level table information for a given table. * * @param string $tableName The name of the table to get the information for. * @return array? Returns an array of table information. */ protected function getTableInfo($tableName) { $pxName = $this->_DatabasePrefix . $tableName; $status = $this->Database->query("show table status where name = '{$pxName}'")->firstRow(DATASET_TYPE_ARRAY); if (!$status) { return null; } $result = ArrayTranslate($status, array('Engine' => 'engine', 'Rows' => 'rows', 'Collation' => 'collation')); // Look up the encoding for the collation. $result['charset'] = $this->getCharsetFromCollation($result['collation']); return $result; }
/** * @param Gdn_Controller $Sender * @param array $Args */ protected function Settings_AddEdit($Sender, $Args) { $client_id = $Sender->Request->Get('client_id'); Gdn::Locale()->SetTranslation('AuthenticationKey', 'Client ID'); Gdn::Locale()->SetTranslation('AssociationSecret', 'Secret'); Gdn::Locale()->SetTranslation('AuthenticateUrl', 'Authentication Url'); $Form = new Gdn_Form(); $Sender->Form = $Form; $Model = new Gdn_AuthenticationProviderModel(); if ($Form->AuthenticatedPostBack()) { if ($Form->GetFormValue('Generate') || $Sender->Request->Post('Generate')) { $Form->SetFormValue('AuthenticationKey', mt_rand()); $Form->SetFormValue('AssociationSecret', md5(mt_rand())); $Sender->SetFormSaved(FALSE); } else { $Form->ValidateRule('AuthenticationKey', 'ValidateRequired'); $Form->ValidateRule('AuthenticationKey', 'regex:`^[a-z0-9_-]+$`i', T('The client id must contain only letters, numbers and dashes.')); $Form->ValidateRule('AssociationSecret', 'ValidateRequired'); $Form->ValidateRule('AuthenticateUrl', 'ValidateRequired'); $Values = $Form->FormValues(); $Values = ArrayTranslate($Values, array('Name', 'AuthenticationKey', 'URL', 'AssociationSecret', 'AuthenticateUrl', 'SignInUrl', 'RegisterUrl', 'SignOutUrl', 'IsDefault')); $Values['AuthenticationSchemeAlias'] = 'jsconnect'; $Values['AssociationHashMethod'] = 'md5'; $Values['Attributes'] = serialize(array('HashType' => $Form->GetFormValue('HashType'), 'TestMode' => $Form->GetFormValue('TestMode'), 'Trusted' => $Form->GetFormValue('Trusted', 0))); if ($Form->ErrorCount() == 0) { $IsDefault = GetValue('IsDefault', $Values); if ($IsDefault) { Gdn::SQL()->Put('UserAuthenticationProvider', array('IsDefault' => 0), array('AuthenticationKey <>' => val('AuthenticationKey', $Values))); } if ($client_id) { Gdn::SQL()->Put('UserAuthenticationProvider', $Values, array('AuthenticationKey' => $client_id)); } else { Gdn::SQL()->Options('Ignore', TRUE)->Insert('UserAuthenticationProvider', $Values); } $Sender->RedirectUrl = Url('/settings/jsconnect'); } } } else { if ($client_id) { $Provider = self::GetProvider($client_id); TouchValue('Trusted', $Provider, 1); } else { $Provider = array(); } $Form->SetData($Provider); } $Sender->SetData('Title', sprintf(T($client_id ? 'Edit %s' : 'Add %s'), T('Connection'))); $Sender->Render('Settings_AddEdit', '', 'plugins/jsconnect'); }
/** * Check an addon's file to extract the addon information out of it. * * @param string $Path The path to the file. * @param bool $Fix Whether or not to fix files that have been zipped incorrectly. * @return array An array of addon information. */ public static function AnalyzeAddon($Path, $Fix = FALSE, $ThrowError = TRUE) { $Result = array(); // Extract the zip file so we can make sure it has appropriate information. $Zip = NULL; if (class_exists('ZipArchive', FALSE)) { $Zip = new ZipArchive(); $ZipOpened = $Zip->open($Path); if ($ZipOpened !== TRUE) { $Zip = NULL; } } if (!$Zip) { require_once PATH_LIBRARY . "/vendors/pclzip/class.pclzipadapter.php"; $Zip = new PclZipAdapter(); $ZipOpened = $Zip->open($Path); } if ($ZipOpened !== TRUE) { if ($ThrowError) { $Errors = array(ZIPARCHIVE::ER_EXISTS => 'ER_EXISTS', ZIPARCHIVE::ER_INCONS => 'ER_INCONS', ZIPARCHIVE::ER_INVAL => 'ER_INVAL', ZIPARCHIVE::ER_MEMORY => 'ER_MEMORY', ZIPARCHIVE::ER_NOENT => 'ER_NOENT', ZIPARCHIVE::ER_NOZIP => 'ER_NOZIP', ZIPARCHIVE::ER_OPEN => 'ER_OPEN', ZIPARCHIVE::ER_READ => 'ER_READ', ZIPARCHIVE::ER_SEEK => 'ER_SEEK'); throw new Exception(T('Could not open addon file. Addons must be zip files.') . ' (' . $Path . ' ' . GetValue($ZipOpened, $Errors, 'Unknown Error') . ')' . $Worked, 400); } return FALSE; } $Entries = array(); for ($i = 0; $i < $Zip->numFiles; $i++) { $Entries[] = $Zip->statIndex($i); } // Figure out which system files to delete. $Deletes = array(); foreach ($Entries as $Index => $Entry) { $Name = $Entry['name']; $Delete = strpos($Name, '__MACOSX') !== FALSE | strpos($Name, '.DS_Store') !== FALSE | strpos($Name, 'thumbs.db') !== FALSE | strpos($Name, '.gitignore') !== FALSE; if ($Delete) { $Deletes[] = $Entry; unset($Entries[$Index]); } } // Get a folder ready for checking the addon. $FolderPath = dirname($Path) . '/' . basename($Path, '.zip') . '/'; if (file_exists($FolderPath)) { Gdn_FileSystem::RemoveFolder($FolderPath); } // Figure out what kind of addon this is. $Root = ''; $NewRoot = ''; $Addon = FALSE; foreach ($Entries as $Entry) { $Name = '/' . ltrim($Entry['name'], '/'); $Filename = basename($Name); $Folder = substr($Name, 0, -strlen($Filename)); $NewRoot = ''; // Check to see if the entry is a plugin file. if ($Filename == 'default.php' || StringEndsWith($Filename, '.plugin.php')) { if (count(explode('/', $Folder)) > 3) { // The file is too deep to be a plugin file. continue; } // This could be a plugin file, but we have to examine its info array. $Zip->extractTo($FolderPath, $Entry['name']); $FilePath = CombinePaths(array($FolderPath, $Name)); $Info = self::ParseInfoArray($FilePath, 'PluginInfo'); Gdn_FileSystem::RemoveFolder(dirname($FilePath)); if (!is_array($Info) || !count($Info)) { continue; } // Check to see if the info array conforms to a plugin spec. $Key = key($Info); $Info = $Info[$Key]; $Root = trim($Folder, '/'); $Valid = TRUE; // Make sure the key matches the folder name. if ($Root && strcasecmp($Root, $Key) != 0) { $Result[] = "{$Name}: The plugin's key is not the same as its folder name."; $Valid = FALSE; } else { $NewRoot = $Root; } if (!GetValue('Description', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Description')); $Valid = FALSE; } if (!GetValue('Version', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Version')); $Valid = FALSE; } if ($Valid) { // The plugin was confirmed. $Addon = array('AddonKey' => $Key, 'AddonTypeID' => ADDON_TYPE_PLUGIN, 'Name' => GetValue('Name', $Info) ? $Info['Name'] : $Key, 'Description' => $Info['Description'], 'Version' => $Info['Version'], 'Path' => $Path); break; } continue; } // Check to see if the entry is an application file. if (StringEndsWith($Name, '/settings/about.php')) { if (count(explode('/', $Folder)) > 4) { $Result[] = "{$Name}: The application's info array was not in the correct location."; // The file is too deep to be a plugin file. continue; } // This could be a plugin file, but we have to examine its info array. $Zip->extractTo($FolderPath, $Entry['name']); $FilePath = CombinePaths(array($FolderPath, $Name)); $Info = self::ParseInfoArray($FilePath, 'ApplicationInfo'); Gdn_FileSystem::RemoveFolder(dirname($FilePath)); if (!is_array($Info) || !count($Info)) { $Result[] = "{$Name}: The application's info array could not be parsed."; continue; } $Key = key($Info); $Info = $Info[$Key]; $Root = trim(substr($Name, 0, -strlen('/settings/about.php')), '/'); $Valid = TRUE; // Make sure the key matches the folder name. if ($Root && strcasecmp($Root, $Key) != 0) { $Result[] = "{$Name}: The application's key is not the same as its folder name."; $Valid = FALSE; } else { $NewRoot = $Root; } if (!GetValue('Description', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Description')); $Valid = FALSE; } if (!GetValue('Version', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Version')); $Valid = FALSE; } if ($Valid) { // The application was confirmed. $Addon = array('AddonKey' => $Key, 'AddonTypeID' => ADDON_TYPE_APPLICATION, 'Name' => GetValue('Name', $Info) ? $Info['Name'] : $Key, 'Description' => $Info['Description'], 'Version' => $Info['Version'], 'Path' => $Path); break; } continue; } // Check to see if the entry is a theme file. if (StringEndsWith($Name, '/about.php')) { if (count(explode('/', $Folder)) > 3) { // The file is too deep to be a plugin file. continue; } // This could be a theme file, but we have to examine its info array. $Zip->extractTo($FolderPath, $Entry['name']); $FilePath = CombinePaths(array($FolderPath, $Name)); $Info = self::ParseInfoArray($FilePath, 'ThemeInfo'); Gdn_FileSystem::RemoveFolder(dirname($FilePath)); if (!is_array($Info) || !count($Info)) { continue; } $Key = key($Info); $Info = $Info[$Key]; $Valid = TRUE; $Root = trim(substr($Name, 0, -strlen('/about.php')), '/'); // Make sure the theme is at least one folder deep. if (strlen($Root) == 0) { $Result[] = $Name . ': The theme must be in a folder.'; $Valid = FALSE; } if (!GetValue('Description', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Description')); $Valid = FALSE; } if (!GetValue('Version', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Version')); $Valid = FALSE; } if ($Valid) { // The application was confirmed. $Addon = array('AddonKey' => $Key, 'AddonTypeID' => ADDON_TYPE_THEME, 'Name' => GetValue('Name', $Info) ? $Info['Name'] : $Key, 'Description' => $Info['Description'], 'Version' => $Info['Version'], 'Path' => $Path); break; } } if (StringEndsWith($Name, '/definitions.php')) { if (count(explode('/', $Folder)) > 3) { // The file is too deep to be a plugin file. continue; } // This could be a locale pack, but we have to examine its info array. $Zip->extractTo($FolderPath, $Entry['name']); $FilePath = CombinePaths(array($FolderPath, $Name)); $Info = self::ParseInfoArray($FilePath, 'LocaleInfo'); Gdn_FileSystem::RemoveFolder(dirname($FilePath)); if (!is_array($Info) || !count($Info)) { continue; } $Key = key($Info); $Info = $Info[$Key]; $Valid = TRUE; $Root = trim(substr($Name, 0, -strlen('/definitions.php')), '/'); // Make sure the locale is at least one folder deep. if ($Root != $Key) { $Result[] = $Name . ': The locale pack\'s key must be the same as its folder name.'; $Valid = FALSE; } if (!GetValue('Locale', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Locale')); $Valud = FALSE; } elseif (strcasecmp($Info['Locale'], $Key) == 0) { $Result[] = $Name . ': ' . T('The locale\'s key cannot be the same as the name of the locale.'); $Valid = FALSE; } if (!GetValue('Description', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Description')); $Valid = FALSE; } if (!GetValue('Version', $Info)) { $Result[] = $Name . ': ' . sprintf(T('ValidateRequired'), T('Version')); $Valid = FALSE; } if ($Valid) { // The locale pack was confirmed. $Addon = array('AddonKey' => $Key, 'AddonTypeID' => ADDON_TYPE_LOCALE, 'Name' => GetValue('Name', $Info) ? $Info['Name'] : $Key, 'Description' => $Info['Description'], 'Version' => $Info['Version'], 'Path' => $Path); break; } } // Check to see if the entry is a core file. if (StringEndsWith($Name, '/index.php')) { if (count(explode('/', $Folder)) != 3) { // The file is too deep to be the core's index.php continue; } // This could be a theme file, but we have to examine its info array. $Zip->extractTo($FolderPath, $Entry['name']); $FilePath = CombinePaths(array($FolderPath, $Name)); // Get the version number from the core. $Version = self::ParseCoreVersion($FilePath); if (!$Version) { continue; } // The application was confirmed. $Addon = array('AddonKey' => 'vanilla', 'AddonTypeID' => ADDON_TYPE_CORE, 'Name' => 'Vanilla', 'Description' => 'Vanilla is an open-source, standards-compliant, multi-lingual, fully extensible discussion forum for the web. Anyone who has web-space that meets the requirements can download and use Vanilla for free!', 'Version' => $Version, 'Path' => $Path); $Info = array(); break; } } if ($Addon) { // Add the requirements. $Requirements = ArrayTranslate($Info, array('RequiredApplications' => 'Applications', 'RequiredPlugins' => 'Plugins', 'RequiredThemes' => 'Themes')); foreach ($Requirements as $Type => $Items) { if (!is_array($Items)) { unset($Requirements[$Type]); } } $Addon['Requirements'] = serialize($Requirements); $Addon['Checked'] = TRUE; $UploadsPath = PATH_ROOT . '/uploads/'; if (StringBeginsWith($Addon['Path'], $UploadsPath)) { $Addon['File'] = substr($Addon['Path'], strlen($UploadsPath)); } if ($Fix) { // Delete extraneous files. foreach ($Deletes as $Delete) { $Zip->deleteName($Delete['name']); } } } $Zip->close(); if (file_exists($FolderPath)) { Gdn_FileSystem::RemoveFolder($FolderPath); } if ($Addon) { $Addon['MD5'] = md5_file($Path); return $Addon; } else { if ($ThrowError) { $Msg = implode("\n", $Result); throw new Exception($Msg, 400); } else { return FALSE; } } }
/** * Inserts or updates the discussion via form values. * * Events: BeforeSaveDiscussion, AfterSaveDiscussion. * * @since 2.0.0 * @access public * * @param array $FormPostValues Data sent from the form model. * @return int $DiscussionID Unique ID of the discussion. */ public function Save($FormPostValues) { $Session = Gdn::Session(); // Define the primary key in this model's table. $this->DefineSchema(); // Add & apply any extra validation rules: $this->Validation->ApplyRule('Body', 'Required'); $MaxCommentLength = Gdn::Config('Vanilla.Comment.MaxLength'); if (is_numeric($MaxCommentLength) && $MaxCommentLength > 0) { $this->Validation->SetSchemaProperty('Body', 'Length', $MaxCommentLength); $this->Validation->ApplyRule('Body', 'Length'); } // Get the DiscussionID from the form so we know if we are inserting or updating. $DiscussionID = ArrayValue('DiscussionID', $FormPostValues, ''); // See if there is a source ID. if (array_key_exists('SourceID', $FormPostValues)) { $DiscussionID = $this->SQL->GetWhere('Discussion', ArrayTranslate($FormPostValues, array('Source', 'SourceID')))->Value('DiscussionID'); if ($DiscussionID) { $FormPostValues['DiscussionID'] = $DiscussionID; } } $Insert = $DiscussionID == '' ? TRUE : FALSE; $this->EventArguments['Insert'] = $Insert; if ($Insert) { unset($FormPostValues['DiscussionID']); // If no categoryid is defined, grab the first available. if (ArrayValue('CategoryID', $FormPostValues) === FALSE) { $FormPostValues['CategoryID'] = $this->SQL->Get('Category', 'CategoryID', '', 1)->FirstRow()->CategoryID; } $this->AddInsertFields($FormPostValues); // $FormPostValues['LastCommentUserID'] = $Session->UserID; $FormPostValues['DateLastComment'] = Gdn_Format::ToDateTime(); } // Add the update fields because this table's default sort is by DateUpdated (see $this->Get()). $this->AddUpdateFields($FormPostValues); // Set checkbox values to zero if they were unchecked if (ArrayValue('Announce', $FormPostValues, '') === FALSE) { $FormPostValues['Announce'] = 0; } if (ArrayValue('Closed', $FormPostValues, '') === FALSE) { $FormPostValues['Closed'] = 0; } if (ArrayValue('Sink', $FormPostValues, '') === FALSE) { $FormPostValues['Sink'] = 0; } // Prep and fire event $this->EventArguments['FormPostValues'] =& $FormPostValues; $this->EventArguments['DiscussionID'] = $DiscussionID; $this->FireEvent('BeforeSaveDiscussion'); // Validate the form posted values if ($this->Validate($FormPostValues, $Insert)) { // If the post is new and it validates, make sure the user isn't spamming if (!$Insert || !$this->CheckForSpam('Discussion')) { // Get all fields on the form that relate to the schema $Fields = $this->Validation->SchemaValidationFields(); // Get DiscussionID if one was sent $DiscussionID = intval(ArrayValue('DiscussionID', $Fields, 0)); // Remove the primary key from the fields for saving $Fields = RemoveKeyFromArray($Fields, 'DiscussionID'); $Discussion = FALSE; $StoredCategoryID = FALSE; if ($DiscussionID > 0) { // Updating $Stored = $this->GetID($DiscussionID); // Clear the cache if necessary. if (GetValue('Announce', $Stored) != GetValue('Announce', $Fields)) { $CacheKeys = array('Announcements', 'Announcements_' . GetValue('CategoryID', $Fields)); $Announce = GetValue('Announce', $Discussion); $this->SQL->Cache($CacheKeys); } $this->SQL->Put($this->Name, $Fields, array($this->PrimaryKey => $DiscussionID)); $Fields['DiscussionID'] = $DiscussionID; LogModel::LogChange('Edit', 'Discussion', (array) $Fields, (array) $Stored); if ($Stored->CategoryID != $Fields['CategoryID']) { $StoredCategoryID = $Stored->CategoryID; } } else { // Inserting. if (!GetValue('Format', $Fields)) { $Fields['Format'] = Gdn::Config('Garden.InputFormatter', ''); } // Check for spam. $Spam = SpamModel::IsSpam('Discussion', $Fields); // Clear the cache if necessary. if (GetValue('Announce', $Fields)) { $CacheKeys = array('Announcements', 'Announcements_' . GetValue('CategoryID', $Fields)); $Announce = GetValue('Announce', $Discussion); $this->SQL->Cache($CacheKeys); } if (!$Spam) { $DiscussionID = $this->SQL->Insert($this->Name, $Fields); } else { return SPAM; } // Assign the new DiscussionID to the comment before saving $FormPostValues['IsNewDiscussion'] = TRUE; $FormPostValues['DiscussionID'] = $DiscussionID; // Notify users of mentions $DiscussionName = ArrayValue('Name', $Fields, ''); $Usernames = GetMentions($DiscussionName); $UserModel = Gdn::UserModel(); foreach ($Usernames as $Username) { $User = $UserModel->GetByUsername($Username); if ($User && $User->UserID != $Session->UserID) { AddActivity($Session->UserID, 'DiscussionMention', '', $User->UserID, '/discussion/' . $DiscussionID . '/' . Gdn_Format::Url($DiscussionName)); } } // Notify any users who were mentioned in the comment $DiscussionName = ArrayValue('Name', $Fields, ''); $Story = ArrayValue('Body', $Fields, ''); $Usernames = GetMentions($Story); $NotifiedUsers = array(); foreach ($Usernames as $Username) { $User = $UserModel->GetByUsername($Username); if ($User && $User->UserID != $Session->UserID) { $NotifiedUsers[] = $User->UserID; $ActivityModel = new ActivityModel(); $ActivityID = $ActivityModel->Add($Session->UserID, 'CommentMention', Anchor(Gdn_Format::Text($DiscussionName), '/discussion/' . $DiscussionID . '/' . Gdn_Format::Url($DiscussionName), FALSE), $User->UserID, '', '/discussion/' . $DiscussionID . '/' . Gdn_Format::Url($DiscussionName), FALSE); $ActivityModel->SendNotification($ActivityID, $Story); } } $this->RecordActivity($Session->UserID, $DiscussionID, $DiscussionName); try { $Fields['DiscussionID'] = $DiscussionID; $this->NotifyNewDiscussion($Fields); } catch (Exception $Ex) { throw $Ex; } } // Get CategoryID of this discussion $Data = $this->SQL->Select('CategoryID')->From('Discussion')->Where('DiscussionID', $DiscussionID)->Get(); $CategoryID = FALSE; if ($Data->NumRows() > 0) { $CategoryID = $Data->FirstRow()->CategoryID; } // Update discussion counter for affected categories $this->UpdateDiscussionCount($CategoryID, $Insert ? $DiscussionID : FALSE); if ($StoredCategoryID) { $this->UpdateDiscussionCount($StoredCategoryID); } // Fire an event that the discussion was saved. $this->EventArguments['FormPostValues'] = $FormPostValues; $this->EventArguments['Fields'] = $Fields; $this->EventArguments['DiscussionID'] = $DiscussionID; $this->FireEvent('AfterSaveDiscussion'); } } return $DiscussionID; }
public function Initialize($Schema = NULL) { if ($Schema !== NULL) { $this->Schema($Schema); } $Form = $this->Form(); if ($Form->AuthenticatedPostBack()) { // Grab the data from the form. $Data = array(); foreach ($this->_Schema as $Row) { $Name = $Row['Name']; if (strtolower(GetValue('Control', $Row)) == 'imageupload') { $Form->SaveImage($Name, ArrayTranslate($Row, array('Prefix', 'Size'))); } $Value = $Form->GetFormValue($Name); if ($Value == GetValue('Default', $Value, '')) { $Value = ''; } $Data[$Name] = $Value; } // Save it to the config. SaveToConfig($Data, array('RemoveEmpty' => TRUE)); $this->_Sender->InformMessage(T('Saved')); } else { // Load the form data from the config. $Data = array(); foreach ($this->_Schema as $Row) { $Data[$Row['Name']] = C($Row['Name'], GetValue('Default', $Row, '')); } $Form->SetData($Data); } }
/** * Log an operation into the log table. * * @param string $Operation The operation being performed. This is usually one of: * - Delete: The record has been deleted. * - Edit: The record has been edited. * - Spam: The record has been marked spam. * - Moderate: The record requires moderation. * @param string $RecordType The type of record being logged. This usually correspond to the tablename of the record. * @param array $Data The record data. * - If you are logging just one row then pass the row as an array. * - You can pass an additional _New element to tell the logger what the new data is. * @return int The log id. */ public static function Insert($Operation, $RecordType, $Data, $Options = array()) { // Check to see if we are storing two versions of the data. if (($InsertUserID = self::_LogValue($Data, 'Log_InsertUserID')) === NULL) { $InsertUserID = Gdn::Session()->UserID; } if (($InsertIPAddress = self::_LogValue($Data, 'Log_InsertIPAddress')) == NULL) { $InsertIPAddress = Gdn::Request()->IPAddress(); } // Do some known translations for the parent record ID. if (($ParentRecordID = self::_LogValue($Data, 'ParentRecordID')) === NULL) { switch ($RecordType) { case 'Activity': $ParentRecordID = self::_LogValue($Data, 'CommentActivityID', 'CommentActivityID'); break; case 'Comment': $ParentRecordID = self::_LogValue($Data, 'DiscussionID', 'DiscussionID'); break; } } // Get the row information from the data or determine it based on the type. $LogRow = array('Operation' => $Operation, 'RecordType' => $RecordType, 'RecordID' => self::_LogValue($Data, 'RecordID', $RecordType . 'ID'), 'RecordUserID' => self::_LogValue($Data, 'RecordUserID', 'UpdateUserID', 'InsertUserID'), 'RecordIPAddress' => self::_LogValue($Data, 'RecordIPAddress', 'LastIPAddress', 'InsertIPAddress'), 'RecordDate' => self::_LogValue($Data, 'RecordDate', 'DateUpdated', 'DateInserted'), 'InsertUserID' => $InsertUserID, 'InsertIPAddress' => $InsertIPAddress, 'DateInserted' => Gdn_Format::ToDateTime(), 'ParentRecordID' => $ParentRecordID, 'Data' => serialize($Data)); if ($LogRow['RecordDate'] == NULL) { $LogRow['RecordDate'] = Gdn_Format::ToDateTime(); } $GroupBy = GetValue('GroupBy', $Options); // Make sure we aren't grouping by null values. if (is_array($GroupBy)) { foreach ($GroupBy as $Name) { if (GetValue($Name, $LogRow) === NULL) { $GroupBy = FALSE; break; } } } if ($GroupBy) { $GroupBy[] = 'Operation'; $GroupBy[] = 'RecordType'; // Check to see if there is a record already logged here. $Where = array_combine($GroupBy, ArrayTranslate($LogRow, $GroupBy)); $LogRow2 = Gdn::SQL()->GetWhere('Log', $Where)->FirstRow(DATASET_TYPE_ARRAY); if ($LogRow2) { $LogID = $LogRow2['LogID']; $OtherUserIDs = explode(',', $LogRow2['OtherUserIDs']); if (!is_array($OtherUserIDs)) { $OtherUserIDs = array(); } if ($InsertUserID != $LogRow2['InsertUserID'] && !in_array($InsertUserID, $OtherUserIDs)) { $OtherUserIDs[] = $InsertUserID; } if (array_key_exists('OtherUserIDs', $Options)) { $OtherUserIDs = array_merge($OtherUserIDs, $Options['OtherUserIDs']); $OtherUserIDs = array_unique($OtherUserIDs); $OtherUserIDs = array_diff($OtherUserIDs, array($InsertUserID)); $Count = count($OtherUserIDs) + 1; } else { $Count = (int) $LogRow2['CountGroup'] + 1; } Gdn::SQL()->Put('Log', array('OtherUserIDs' => implode(',', $OtherUserIDs), 'CountGroup' => $Count, 'DateUpdated' => Gdn_Format::ToDateTime()), array('LogID' => $LogID)); } else { $LogID = Gdn::SQL()->Insert('Log', $LogRow); } } else { // Insert the log entry. $LogID = Gdn::SQL()->Insert('Log', $LogRow); } return $LogID; }
public function Search($Search, $Offset = 0, $Limit = 20) { // If there are no searches then return an empty array. if (trim($Search) == '') { return array(); } // Figure out the exact search mode. if ($this->ForceSearchMode) { $SearchMode = $this->ForceSearchMode; } else { $SearchMode = strtolower(C('Garden.Search.Mode', 'matchboolean')); } if ($SearchMode == 'matchboolean') { if (strpos($Search, '+') !== FALSE || strpos($Search, '-') !== FALSE) { $SearchMode = 'boolean'; } else { $SearchMode = 'match'; } } else { $this->_SearchMode = $SearchMode; } if ($ForceDatabaseEngine = C('Database.ForceStorageEngine')) { if (strcasecmp($ForceDatabaseEngine, 'myisam') != 0) { $SearchMode = 'like'; } } if (strlen($Search) <= 4) { $SearchMode = 'like'; } $this->_SearchMode = $SearchMode; $this->FireEvent('Search'); if (count($this->_SearchSql) == 0) { return array(); } // Perform the search by unioning all of the sql together. $Sql = $this->SQL->Select()->From('_TBL_ s')->OrderBy('s.DateInserted', 'desc')->Limit($Limit, $Offset)->GetSelect(); $Sql = str_replace($this->Database->DatabasePrefix . '_TBL_', "(\n" . implode("\nunion all\n", $this->_SearchSql) . "\n)", $Sql); $this->EventArguments['Search'] = $Search; $this->FireEvent('AfterBuildSearchQuery'); if ($this->_SearchMode == 'like') { $Search = '%' . $Search . '%'; } foreach ($this->_Parameters as $Key => $Value) { $this->_Parameters[$Key] = $Search; } $Parameters = $this->_Parameters; $this->Reset(); $this->SQL->Reset(); $Result = $this->Database->Query($Sql, $Parameters)->ResultArray(); foreach ($Result as $Key => $Value) { if (isset($Value['Summary'])) { $Value['Summary'] = Condense(Gdn_Format::To($Value['Summary'], $Value['Format'])); $Result[$Key] = $Value; } switch ($Value['RecordType']) { case 'Discussion': $Discussion = ArrayTranslate($Value, array('PrimaryID' => 'DiscussionID', 'Title' => 'Name', 'CategoryID')); $Result[$Key]['Url'] = DiscussionUrl($Discussion, 1); break; } } return $Result; }
/** * Inserts or updates the discussion via form values. * * Events: BeforeSaveDiscussion, AfterSaveDiscussion. * * @since 2.0.0 * @access public * * @param array $FormPostValues Data sent from the form model. * @return int $DiscussionID Unique ID of the discussion. */ public function Save($FormPostValues) { $Session = Gdn::Session(); // Define the primary key in this model's table. $this->DefineSchema(); // Add & apply any extra validation rules: $this->Validation->ApplyRule('Body', 'Required'); $this->Validation->AddRule('MeAction', 'function:ValidateMeAction'); $this->Validation->ApplyRule('Body', 'MeAction'); $MaxCommentLength = Gdn::Config('Vanilla.Comment.MaxLength'); if (is_numeric($MaxCommentLength) && $MaxCommentLength > 0) { $this->Validation->SetSchemaProperty('Body', 'Length', $MaxCommentLength); $this->Validation->ApplyRule('Body', 'Length'); } // Validate category permissions. $CategoryID = GetValue('CategoryID', $FormPostValues); if ($CategoryID > 0) { $Category = CategoryModel::Categories($CategoryID); if ($Category && !$Session->CheckPermission('Vanilla.Discussions.Add', TRUE, 'Category', GetValue('PermissionCategoryID', $Category))) { $this->Validation->AddValidationResult('CategoryID', 'You do not have permission to post in this category'); } } // Get the DiscussionID from the form so we know if we are inserting or updating. $DiscussionID = ArrayValue('DiscussionID', $FormPostValues, ''); // See if there is a source ID. if (GetValue('SourceID', $FormPostValues)) { $DiscussionID = $this->SQL->GetWhere('Discussion', ArrayTranslate($FormPostValues, array('Source', 'SourceID')))->Value('DiscussionID'); if ($DiscussionID) { $FormPostValues['DiscussionID'] = $DiscussionID; } } elseif (GetValue('ForeignID', $FormPostValues)) { $DiscussionID = $this->SQL->GetWhere('Discussion', array('ForeignID' => $FormPostValues['ForeignID']))->Value('DiscussionID'); if ($DiscussionID) { $FormPostValues['DiscussionID'] = $DiscussionID; } } $Insert = $DiscussionID == '' ? TRUE : FALSE; $this->EventArguments['Insert'] = $Insert; if ($Insert) { unset($FormPostValues['DiscussionID']); // If no categoryid is defined, grab the first available. if (!GetValue('CategoryID', $FormPostValues) && !C('Vanilla.Categories.Use')) { $FormPostValues['CategoryID'] = GetValue('CategoryID', CategoryModel::DefaultCategory(), -1); } $this->AddInsertFields($FormPostValues); // The UpdateUserID used to be required. Just add it if it still is. if (!$this->Schema->GetProperty('UpdateUserID', 'AllowNull', TRUE)) { $FormPostValues['UpdateUserID'] = $FormPostValues['InsertUserID']; } // $FormPostValues['LastCommentUserID'] = $Session->UserID; $FormPostValues['DateLastComment'] = $FormPostValues['DateInserted']; } else { // Add the update fields. $this->AddUpdateFields($FormPostValues); } // Set checkbox values to zero if they were unchecked if (ArrayValue('Announce', $FormPostValues, '') === FALSE) { $FormPostValues['Announce'] = 0; } if (ArrayValue('Closed', $FormPostValues, '') === FALSE) { $FormPostValues['Closed'] = 0; } if (ArrayValue('Sink', $FormPostValues, '') === FALSE) { $FormPostValues['Sink'] = 0; } // Prep and fire event $this->EventArguments['FormPostValues'] =& $FormPostValues; $this->EventArguments['DiscussionID'] = $DiscussionID; $this->FireEvent('BeforeSaveDiscussion'); // Validate the form posted values $this->Validate($FormPostValues, $Insert); $ValidationResults = $this->ValidationResults(); // If the body is not required, remove it's validation errors. $BodyRequired = C('Vanilla.DiscussionBody.Required', TRUE); if (!$BodyRequired && array_key_exists('Body', $ValidationResults)) { unset($ValidationResults['Body']); } if (count($ValidationResults) == 0) { // If the post is new and it validates, make sure the user isn't spamming if (!$Insert || !$this->CheckForSpam('Discussion')) { // Get all fields on the form that relate to the schema $Fields = $this->Validation->SchemaValidationFields(); // Get DiscussionID if one was sent $DiscussionID = intval(ArrayValue('DiscussionID', $Fields, 0)); // Remove the primary key from the fields for saving $Fields = RemoveKeyFromArray($Fields, 'DiscussionID'); $StoredCategoryID = FALSE; if ($DiscussionID > 0) { // Updating $Stored = $this->GetID($DiscussionID, DATASET_TYPE_ARRAY); // Clear the cache if necessary. if (GetValue('Announce', $Stored) != GetValue('Announce', $Fields)) { $CacheKeys = array('Announcements'); $this->SQL->Cache($CacheKeys); } self::SerializeRow($Fields); $this->SQL->Put($this->Name, $Fields, array($this->PrimaryKey => $DiscussionID)); SetValue('DiscussionID', $Fields, $DiscussionID); LogModel::LogChange('Edit', 'Discussion', (array) $Fields, $Stored); if (GetValue('CategoryID', $Stored) != GetValue('CategoryID', $Fields)) { $StoredCategoryID = GetValue('CategoryID', $Stored); } } else { // Inserting. if (!GetValue('Format', $Fields) || C('Garden.ForceInputFormatter')) { $Fields['Format'] = C('Garden.InputFormatter', ''); } if (C('Vanilla.QueueNotifications')) { $Fields['Notified'] = ActivityModel::SENT_PENDING; } // Check for spam. $Spam = SpamModel::IsSpam('Discussion', $Fields); if ($Spam) { return SPAM; } // Check for approval $ApprovalRequired = CheckRestriction('Vanilla.Approval.Require'); if ($ApprovalRequired && !GetValue('Verified', Gdn::Session()->User)) { LogModel::Insert('Pending', 'Discussion', $Fields); return UNAPPROVED; } // Create discussion $DiscussionID = $this->SQL->Insert($this->Name, $Fields); $Fields['DiscussionID'] = $DiscussionID; // Update the cache. if ($DiscussionID && Gdn::Cache()->ActiveEnabled()) { $CategoryCache = array('LastDiscussionID' => $DiscussionID, 'LastCommentID' => NULL, 'LastTitle' => Gdn_Format::Text($Fields['Name']), 'LastUserID' => $Fields['InsertUserID'], 'LastDateInserted' => $Fields['DateInserted'], 'LastUrl' => DiscussionUrl($Fields)); CategoryModel::SetCache($Fields['CategoryID'], $CategoryCache); // Clear the cache if necessary. if (GetValue('Announce', $Fields)) { Gdn::Cache()->Remove('Announcements'); } } // Update the user's discussion count. $this->UpdateUserDiscussionCount(Gdn::Session()->UserID); // Assign the new DiscussionID to the comment before saving. $FormPostValues['IsNewDiscussion'] = TRUE; $FormPostValues['DiscussionID'] = $DiscussionID; // Do data prep. $DiscussionName = ArrayValue('Name', $Fields, ''); $Story = ArrayValue('Body', $Fields, ''); $NotifiedUsers = array(); $UserModel = Gdn::UserModel(); $ActivityModel = new ActivityModel(); if (GetValue('Type', $FormPostValues)) { $Code = 'HeadlineFormat.Discussion.' . $FormPostValues['Type']; } else { $Code = 'HeadlineFormat.Discussion'; } $HeadlineFormat = T($Code, '{ActivityUserID,user} started a new discussion: <a href="{Url,html}">{Data.Name,text}</a>'); $Category = CategoryModel::Categories(GetValue('CategoryID', $Fields)); $Activity = array('ActivityType' => 'Discussion', 'ActivityUserID' => $Fields['InsertUserID'], 'HeadlineFormat' => $HeadlineFormat, 'RecordType' => 'Discussion', 'RecordID' => $DiscussionID, 'Route' => DiscussionUrl($Fields), 'Data' => array('Name' => $DiscussionName, 'Category' => GetValue('Name', $Category))); // Allow simple fulltext notifications if (C('Vanilla.Activity.ShowDiscussionBody', FALSE)) { $Activity['Story'] = $Story; } // Notify all of the users that were mentioned in the discussion. $Usernames = array_merge(GetMentions($DiscussionName), GetMentions($Story)); $Usernames = array_unique($Usernames); // Use our generic Activity for events, not mentions $this->EventArguments['Activity'] = $Activity; // Notifications for mentions foreach ($Usernames as $Username) { $User = $UserModel->GetByUsername($Username); if (!$User) { continue; } // Check user can still see the discussion. if (!$UserModel->GetCategoryViewPermission($User->UserID, GetValue('CategoryID', $Fields))) { continue; } $Activity['HeadlineFormat'] = T('HeadlineFormat.Mention', '{ActivityUserID,user} mentioned you in <a href="{Url,html}">{Data.Name,text}</a>'); $Activity['NotifyUserID'] = GetValue('UserID', $User); $ActivityModel->Queue($Activity, 'Mention'); } // Notify everyone that has advanced notifications. if (!C('Vanilla.QueueNotifications')) { try { $Fields['DiscussionID'] = $DiscussionID; $this->NotifyNewDiscussion($Fields, $ActivityModel, $Activity); } catch (Exception $Ex) { throw $Ex; } } // Throw an event for users to add their own events. $this->EventArguments['Discussion'] = $Fields; $this->EventArguments['NotifiedUsers'] = $NotifiedUsers; $this->EventArguments['MentionedUsers'] = $Usernames; $this->EventArguments['ActivityModel'] = $ActivityModel; $this->FireEvent('BeforeNotification'); // Send all notifications. $ActivityModel->SaveQueue(); } // Get CategoryID of this discussion $Discussion = $this->GetID($DiscussionID, DATASET_TYPE_ARRAY); $CategoryID = GetValue('CategoryID', $Discussion, FALSE); // Update discussion counter for affected categories $this->UpdateDiscussionCount($CategoryID, $Insert ? $Discussion : FALSE); if ($StoredCategoryID) { $this->UpdateDiscussionCount($StoredCategoryID); } // Fire an event that the discussion was saved. $this->EventArguments['FormPostValues'] = $FormPostValues; $this->EventArguments['Fields'] = $Fields; $this->EventArguments['DiscussionID'] = $DiscussionID; $this->FireEvent('AfterSaveDiscussion'); } } return $DiscussionID; }
/** * * @param Gdn_Controller $Sender * @param array $Args */ public function ProfileController_JsConnect_Create($Sender, $Args = array()) { include_once dirname(__FILE__) . '/functions.jsconnect.php'; $client_id = $Sender->Request->Get('client_id', 0); $Provider = self::GetProvider($client_id); $client_id = GetValue('AuthenticationKey', $Provider); $Secret = GetValue('AssociationSecret', $Provider); if (Gdn::Session()->IsValid()) { $User = ArrayTranslate((array) Gdn::Session()->User, array('UserID' => 'UniqueID', 'Name', 'Email', 'PhotoUrl', 'DateOfBirth', 'Gender')); // $Sfx = 'F'; // $User['UniqueID'] .= $Sfx; // $User['Name'] .= $Sfx; // $User['Email'] = str_replace('@', '+'.$Sfx.'@', $User['Email']); if (!$User['PhotoUrl'] && function_exists('UserPhotoDefaultUrl')) { $User['PhotoUrl'] = Url(UserPhotoDefaultUrl(Gdn::Session()->User), TRUE); } } else { $User = array(); } ob_clean(); WriteJsConnect($User, $Sender->Request->Get(), $client_id, $Secret, GetValue('HashType', $Provider, TRUE)); exit; }
/** * Pre-populate the form with values from the query string. * * @param Gdn_Form $Form * @param bool $LimitCategories Whether to turn off the category dropdown if there is only one category to show. */ protected function PopulateForm($Form) { $Get = $this->Request->Get(); $Get = array_change_key_case($Get); $Values = ArrayTranslate($Get, array('name' => 'Name', 'tags' => 'Tags', 'body' => 'Body')); foreach ($Values as $Key => $Value) { $Form->SetValue($Key, $Value); } if (isset($Get['category'])) { $Category = CategoryModel::Categories($Get['category']); if ($Category && $Category['PermsDiscussionsAdd']) { $Form->SetValue('CategoryID', $Category['CategoryID']); } } }
public function Save() { $this->Permission('Garden.Users.Edit'); if (!Gdn::Request()->IsPostBack()) { throw new Exception('Requires POST', 405); } $Form = new Gdn_Form(); if ($SSOString = $Form->GetFormValue('SSOString')) { $Parts = explode(' ', $SSOString); $String = $Parts[0]; $Data = json_decode(base64_decode($String), TRUE); $User = ArrayTranslate($Data, array('name' => 'Name', 'email' => 'Email', 'photourl' => 'Photo', 'client_id' => 'ClientID', 'uniqueid' => 'UniqueID')); } else { $User = $Form->FormValues(); } if (!isset($User['UserID']) && isset($User['UniqueID'])) { // Try and find the user based on SSO. $Auth = Gdn::UserModel()->GetAuthentication($User['UniqueID'], $User['ClientID']); if ($Auth) { $User['UserID'] = $Auth['UserID']; } } if (!isset($User['UserID'])) { // Add some default values to make saving easier. if (!isset($User['RoleID'])) { $DefaultRoles = C('Garden.Registration.DefaultRoles', array()); $User['RoleID'] = $DefaultRoles; } elseif (is_numeric($User['RoleID'])) { // UserModel->Save() demands an array for RoleID. $User['RoleID'] = array($User['RoleID']); } if (!isset($User['Password'])) { $User['Password'] = md5(microtime()); $User['HashMethod'] = 'Random'; } } $UserID = Gdn::UserModel()->Save($User, array('SaveRoles' => isset($User['RoleID']), 'NoConfirmEmail' => TRUE)); if ($UserID) { if (!isset($User['UserID'])) { $User['UserID'] = $UserID; } if (isset($User['ClientID']) && isset($User['UniqueID'])) { Gdn::UserModel()->SaveAuthentication(array('UserID' => $User['UserID'], 'Provider' => $User['ClientID'], 'UniqueID' => $User['UniqueID'])); } $this->SetData('User', $User); } else { throw new Gdn_UserException(Gdn::UserModel()->Validation->ResultsText()); } $this->Render('Blank', 'Utility'); }
public function Save($Data, $Preference = FALSE, $Options = array()) { Trace('ActivityModel->Save()'); $Activity = $Data; $this->_Touch($Activity); if ($Activity['ActivityUserID'] == $Activity['NotifyUserID'] && !GetValue('Force', $Options)) { Trace('Skipping activity because it would notify the user of something they did.'); return; // don't notify users of something they did. } // Check the user's preference. if ($Preference) { list($Popup, $Email) = self::NotificationPreference($Preference, $Activity['NotifyUserID'], 'both'); if ($Popup && !$Activity['Notified']) { $Activity['Notified'] = self::SENT_PENDING; } if ($Email && !$Activity['Emailed']) { $Activity['Emailed'] = self::SENT_PENDING; } if (!$Activity['Notified'] && !$Activity['Emailed'] && !GetValue('Force', $Options)) { Trace("Skipping activity because the user has no preference set."); return; } } $ActivityType = self::GetActivityType($Activity['ActivityType']); $ActivityTypeID = ArrayValue('ActivityTypeID', $ActivityType); if (!$ActivityTypeID) { Trace("There is no {$ActivityType} activity type.", TRACE_WARNING); $ActivityType = self::GetActivityType('Default'); $ActivityTypeID = ArrayValue('ActivityTypeID', $ActivityType); } $Activity['ActivityTypeID'] = $ActivityTypeID; $NotificationInc = 0; if ($Activity['NotifyUserID'] > 0 && $Activity['Notified']) { $NotificationInc = 1; } // Check to see if we are sharing this activity with another one. if ($CommentActivityID = GetValue('CommentActivityID', $Activity['Data'])) { $CommentActivity = $this->GetID($CommentActivityID); $Activity['Data']['CommentNotifyUserID'] = $CommentActivity['NotifyUserID']; } // Make sure this activity isn't a duplicate. if (GetValue('CheckRecord', $Options)) { // Check to see if this record already notified so we don't notify multiple times. $Where = ArrayTranslate($Activity, array('NotifyUserID', 'RecordType', 'RecordID')); $Where['DateUpdated >'] = Gdn_Format::ToDateTime(strtotime('-2 days')); // index hint $CheckActivity = $this->SQL->GetWhere('Activity', $Where)->FirstRow(); if ($CheckActivity) { return FALSE; } } // Check to share the activity. if (GetValue('Share', $Options)) { $this->Share($Activity); } // Group he activity. if ($GroupBy = GetValue('GroupBy', $Options)) { $GroupBy = (array) $GroupBy; $Where = array(); foreach ($GroupBy as $ColumnName) { $Where[$ColumnName] = $Activity[$ColumnName]; } $Where['NotifyUserID'] = $Activity['NotifyUserID']; // Make sure to only group activities by day. $Where['DateInserted >'] = Gdn_Format::ToDateTime(strtotime('-1 day')); // See if there is another activity to group these into. $GroupActivity = $this->SQL->GetWhere('Activity', $Where)->FirstRow(DATASET_TYPE_ARRAY); if ($GroupActivity) { $GroupActivity['Data'] = @unserialize($GroupActivity['Data']); $Activity = $this->MergeActivities($GroupActivity, $Activity); $NotificationInc = 0; } } $Delete = FALSE; if ($Activity['Emailed'] == self::SENT_PENDING) { $this->Email($Activity); $Delete = GetValue('_Delete', $Activity); } $ActivityData = $Activity['Data']; if (isset($Activity['Data']) && is_array($Activity['Data'])) { $Activity['Data'] = serialize($Activity['Data']); } $this->DefineSchema(); $Activity = $this->FilterSchema($Activity); $ActivityID = GetValue('ActivityID', $Activity); if (!$ActivityID) { if (!$Delete) { $this->AddInsertFields($Activity); TouchValue('DateUpdated', $Activity, $Activity['DateInserted']); $this->EventArguments['Activity'] =& $Activity; $this->EventArguments['ActivityID'] = NULL; $this->FireEvent('BeforeSave'); if (count($this->ValidationResults()) > 0) { return FALSE; } if (GetValue('CheckSpam', $Options)) { // Check for spam $Spam = SpamModel::IsSpam('Activity', $Activity); if ($Spam) { return SPAM; } // Check for approval $ApprovalRequired = CheckRestriction('Vanilla.Approval.Require'); if ($ApprovalRequired && !GetValue('Verified', Gdn::Session()->User)) { LogModel::Insert('Pending', 'Activity', $Activity); return UNAPPROVED; } } $ActivityID = $this->SQL->Insert('Activity', $Activity); $Activity['ActivityID'] = $ActivityID; } } else { $Activity['DateUpdated'] = Gdn_Format::ToDateTime(); unset($Activity['ActivityID']); $this->EventArguments['Activity'] =& $Activity; $this->EventArguments['ActivityID'] = $ActivityID; $this->FireEvent('BeforeSave'); if (count($this->ValidationResults()) > 0) { return FALSE; } $this->SQL->Put('Activity', $Activity, array('ActivityID' => $ActivityID)); $Activity['ActivityID'] = $ActivityID; } $Activity['Data'] = $ActivityData; if (isset($CommentActivity)) { $CommentActivity['Data']['SharedActivityID'] = $Activity['ActivityID']; $CommentActivity['Data']['SharedNotifyUserID'] = $Activity['NotifyUserID']; $this->SetField($CommentActivity['ActivityID'], 'Data', $CommentActivity['Data']); } if ($NotificationInc > 0) { $CountNotifications = Gdn::UserModel()->GetID($Activity['NotifyUserID'])->CountNotifications + $NotificationInc; Gdn::UserModel()->SetField($Activity['NotifyUserID'], 'CountNotifications', $CountNotifications); } return $Activity; }
/** * * @param Gdn_Controller $Sender * @param array $Args */ public function profileController_jsConnect_create($Sender, $Args = array()) { include_once dirname(__FILE__) . '/functions.jsconnect.php'; $client_id = $Sender->Request->Get('client_id', 0); $Provider = self::getProvider($client_id); $client_id = GetValue('AuthenticationKey', $Provider); $Secret = GetValue('AssociationSecret', $Provider); if (Gdn::Session()->IsValid()) { $User = ArrayTranslate((array) Gdn::Session()->User, array('UserID' => 'UniqueID', 'Name', 'Email', 'PhotoUrl', 'DateOfBirth', 'Gender')); // Grab the user's roles. $Roles = Gdn::UserModel()->GetRoles(Gdn::Session()->UserID); $Roles = ConsolidateArrayValuesByKey($Roles, 'Name'); $User['Roles'] = ''; if (is_array($Roles) && sizeof($Roles)) { $User['Roles'] = implode(',', $Roles); } // $Sfx = 'F'; // $User['UniqueID'] .= $Sfx; // $User['Name'] .= $Sfx; // $User['Email'] = str_replace('@', '+'.$Sfx.'@', $User['Email']); if (!$User['PhotoUrl'] && function_exists('UserPhotoDefaultUrl')) { $User['PhotoUrl'] = Url(UserPhotoDefaultUrl(Gdn::Session()->User), TRUE); } } else { $User = array(); } ob_clean(); writeJsConnect($User, $Sender->Request->Get(), $client_id, $Secret, GetValue('HashType', $Provider, TRUE)); exit; }
public function EntryController_Sinaauthorize_Create($Sender, $Args) { $Query = ArrayTranslate($Sender->Request->Get(), array('display', 'Target')); $Query = http_build_query($Query); $this->Authorize($Query); }
public function _Settings($Sender, $Args) { $Sender->Form = $this->Form; // Grab the existing locale packs. $LocaleModel = new LocaleModel(); $LocalePacks = $LocaleModel->AvailableLocalePacks(); $LocalArray = array(); foreach ($LocalePacks as $Key => $Info) { $LocaleArray[$Key] = GetValue('Name', $Info, $Key); } $Sender->SetData('LocalePacks', $LocaleArray); if ($this->Form->IsPostBack()) { if ($this->Form->GetFormValue('Save')) { $Values = ArrayTranslate($this->Form->FormValues(), array('Key', 'Name', 'Locale', 'CaptureDefinitions')); $SaveValues = array(); foreach ($Values as $Key => $Value) { $SaveValues['Plugins.LocaleDeveloper.' . $Key] = $Value; } // Save the settings. SaveToConfig($SaveValues, '', array('RemoveEmpty' => TRUE)); $Sender->StatusMessage = T('Your changes have been saved.'); } elseif ($this->Form->GetFormValue('GenerateChanges')) { $Key = $this->Form->GetFormValue('LocalePackForChanges'); if (!$Key) { $this->Form->AddError('ValidateRequired', 'Locale Pack'); } $Path = PATH_ROOT . '/locales/' . $Key; if (!file_exists($Path)) { $this->Form->AddError('Could not find the selected locale pack.'); } if ($this->Form->ErrorCount() == 0) { try { $LocaleModel->GenerateChanges($Path, $this->LocalePath); $Sender->StatusMessage = T('Your changes have been saved.'); } catch (Exception $Ex) { $this->Form->AddError($Ex); } } } elseif ($this->Form->GetFormValue('Copy')) { $Key = $this->Form->GetFormValue('LocalePackForCopy'); if (!$Key) { $this->Form->AddError('ValidateRequired', 'Locale Pack'); } $Path = PATH_ROOT . '/locales/' . $Key; if (!file_exists($Path)) { $this->Form->AddError('Could not find the selected locale pack.'); } if ($this->Form->ErrorCount() == 0) { try { $LocaleModel->CopyDefinitions($Path, $this->LocalePath . '/copied.php'); $Sender->StatusMessage = T('Your changes have been saved.'); } catch (Exception $Ex) { $this->Form->AddError($Ex); } } } elseif ($this->Form->GetFormValue('Remove')) { $Files = SafeGlob($this->LocalePath . '/*'); foreach ($Files as $File) { $Result = unlink($File); if (!$Result) { $this->Form->AddError('@' . sprintf(T('Could not remove %s.'), $File)); } } if ($this->Form->ErrorCount() == 0) { $Sender->StatusMessage = T('Your changes have been saved.'); } } } else { $Values = C('Plugins.LocaleDeveloper'); foreach ($Values as $Key => $Value) { $this->Form->SetFormValue($Key, $Value); } } $Sender->SetData('LocalePath', $this->LocalePath); $Sender->Render('', '', 'plugins/LocaleDeveloper'); }
/** * Do password reset. * * @access public * @since 2.0.0 * * @param int $UserID Unique. * @param string $PasswordResetKey Authenticate with unique, 1-time code sent via email. */ public function PasswordReset($UserID = '', $PasswordResetKey = '') { $PasswordResetKey = trim($PasswordResetKey); if (!is_numeric($UserID) || $PasswordResetKey == '' || $this->UserModel->GetAttribute($UserID, 'PasswordResetKey', '') != $PasswordResetKey) { $this->Form->AddError('Failed to authenticate your password reset request. Try using the reset request form again.'); } $Expires = $this->UserModel->GetAttribute($UserID, 'PasswordResetExpires'); if ($this->Form->ErrorCount() === 0 && $Expires < time()) { $this->Form->AddError('@' . T('Your password reset token has expired.', 'Your password reset token has expired. Try using the reset request form again.')); } if ($this->Form->ErrorCount() == 0) { $User = $this->UserModel->GetID($UserID, DATASET_TYPE_ARRAY); if ($User) { $User = ArrayTranslate($User, array('UserID', 'Name', 'Email')); $this->SetData('User', $User); } } else { $this->SetData('Fatal', TRUE); } if ($this->Form->ErrorCount() == 0 && $this->Form->IsPostBack() === TRUE) { $Password = $this->Form->GetFormValue('Password', ''); $Confirm = $this->Form->GetFormValue('Confirm', ''); if ($Password == '') { $this->Form->AddError('Your new password is invalid'); } else { if ($Password != $Confirm) { $this->Form->AddError('Your passwords did not match.'); } } if ($this->Form->ErrorCount() == 0) { $User = $this->UserModel->PasswordReset($UserID, $Password); Gdn::Session()->Start($User->UserID, TRUE); // $Authenticator = Gdn::Authenticator()->AuthenticateWith('password'); // $Authenticator->FetchData($Authenticator, array('Email' => $User->Email, 'Password' => $Password, 'RememberMe' => FALSE)); // $AuthUserID = $Authenticator->Authenticate(); Redirect('/'); } } $this->Render(); }
public function SendPasswordEmail($UserID, $Password) { $Session = Gdn::Session(); $Sender = $this->GetID($Session->UserID); $User = $this->GetID($UserID); $AppTitle = Gdn::Config('Garden.Title'); $Email = new Gdn_Email(); $Email->Subject(sprintf(T('[%s] Password Reset'), $AppTitle)); $Email->To($User->Email); $Data = array(); $Data['User'] = ArrayTranslate((array) $User, array('Name', 'Email')); $Data['Sender'] = ArrayTranslate((array) $Sender, array('Name', 'Email')); $Data['Title'] = $AppTitle; $EmailFormat = T('EmailPassword'); if (strpos($EmailFormat, '{') !== FALSE) { $Message = FormatString($EmailFormat, $Data); } else { $Message = sprintf($EmailFormat, $User->Name, $Sender->Name, $AppTitle, ExternalUrl('/'), $Password, $User->Email); } $Message = $this->_AddEmailHeaderFooter($Message, $Data); $Email->Message($Message); $Email->Send(); }
/** * Add a method to the ModerationController to handle merging discussions. * @param Gdn_Controller $Sender */ public function ModerationController_MergeDiscussions_Create($Sender) { $Session = Gdn::Session(); $Sender->Form = new Gdn_Form(); $Sender->Title(T('Merge Discussions')); $DiscussionModel = new DiscussionModel(); $CheckedDiscussions = Gdn::UserModel()->GetAttribute($Session->User->UserID, 'CheckedDiscussions', array()); if (!is_array($CheckedDiscussions)) { $CheckedDiscussions = array(); } $DiscussionIDs = $CheckedDiscussions; $Sender->SetData('DiscussionIDs', $DiscussionIDs); $CountCheckedDiscussions = count($DiscussionIDs); $Sender->SetData('CountCheckedDiscussions', $CountCheckedDiscussions); $Discussions = $DiscussionModel->SQL->WhereIn('DiscussionID', $DiscussionIDs)->Get('Discussion')->ResultArray(); $Sender->SetData('Discussions', $Discussions); // Perform the merge if ($Sender->Form->AuthenticatedPostBack()) { // Create a new discussion record $MergeDiscussion = FALSE; $MergeDiscussionID = $Sender->Form->GetFormValue('MergeDiscussionID'); foreach ($Discussions as $Discussion) { if ($Discussion['DiscussionID'] == $MergeDiscussionID) { $MergeDiscussion = $Discussion; break; } } if ($MergeDiscussion) { $ErrorCount = 0; // Verify that the user has permission to perform the merge. $Category = CategoryModel::Categories($MergeDiscussion['CategoryID']); if ($Category && !$Category['PermsDiscussionsEdit']) { throw PermissionException('Vanilla.Discussions.Edit'); } // Assign the comments to the new discussion record $DiscussionModel->SQL->Update('Comment')->Set('DiscussionID', $MergeDiscussionID)->WhereIn('DiscussionID', $DiscussionIDs)->Put(); $CommentModel = new CommentModel(); foreach ($Discussions as $Discussion) { if ($Discussion['DiscussionID'] == $MergeDiscussionID) { continue; } // Create a comment out of the discussion. $Comment = ArrayTranslate($Discussion, array('Body', 'Format', 'DateInserted', 'InsertUserID', 'InsertIPAddress', 'DateUpdated', 'UpdateUserID', 'UpdateIPAddress', 'Attributes', 'Spam', 'Likes', 'Abuse')); $Comment['DiscussionID'] = $MergeDiscussionID; $CommentModel->Validation->Results(TRUE); $CommentID = $CommentModel->Save($Comment); if ($CommentID) { // Move any attachments (FileUpload plugin awareness) if (class_exists('MediaModel')) { $MediaModel = new MediaModel(); $MediaModel->Reassign($Discussion['DiscussionID'], 'discussion', $CommentID, 'comment'); } // Delete discussion that was merged $DiscussionModel->Delete($Discussion['DiscussionID']); } else { $Sender->InformMessage($CommentModel->Validation->ResultsText()); $ErrorCount++; } } // Update counts on all affected discussions. $CommentModel->UpdateCommentCount($MergeDiscussionID); $CommentModel->RemovePageCache($MergeDiscussionID); // Clear selections Gdn::UserModel()->SaveAttribute($Session->UserID, 'CheckedDiscussions', FALSE); ModerationController::InformCheckedDiscussions($Sender); if ($ErrorCount == 0) { $Sender->RedirectUrl = Url("/discussion/{$MergeDiscussionID}/" . Gdn_Format::Url($MergeDiscussion['Name'])); } } } $Sender->Render('MergeDiscussions', '', 'plugins/SplitMerge'); }
echo GetValue('Description', $Info, ''); ?> </td> </tr> <tr class="<?php echo $RowClass; ?> "> <td class="Info"><?php echo Anchor(T($ToggleText), '/settings/locales/' . strtolower($ToggleText) . '/' . urlencode($Key) . '/' . $Session->TransientKey(), $ToggleText . 'Addon SmallButton'); ?> </td> <td class="Alt Info"><?php $RequiredApplications = GetValue('RequiredApplications', $Info, FALSE); $RequiredPlugins = GetValue('RequiredPlugins', $Info, FALSE); $InfoItems = ArrayTranslate($Info, array('Locale' => T('_Locale'), 'Version' => T('Version'))); $InfoString = ImplodeAssoc(': ', '<span>|</span>', $InfoItems); // if (is_array($RequiredApplications) || is_array($RequiredPlugins)) { // if ($Info != '') // $Info .= '<span>|</span>'; // // $Info .= T('Requires: '); // } // $i = 0; // if (is_array($RequiredApplications)) { // if ($i > 0) // $Info .= ', '; // // foreach ($RequiredApplications as $RequiredApplication => $VersionInfo) { // $Info .= sprintf(T('%1$s Version %2$s'), $RequiredApplication, $VersionInfo); // ++$i;
public function Get($UserID = FALSE) { if (!$UserID) { $UserID = Gdn::Session()->UserID; } if (($UserID != Gdn::Session()->UserID || !Gdn::Session()->UserID) && !Gdn::Session()->CheckPermission('Garden.Users.Edit')) { throw new Exception(T('You do not have permission to view other profiles.'), 401); } $UserModel = new UserModel(); // Get the user. $User = $UserModel->GetID($UserID, DATASET_TYPE_ARRAY); if (!$User) { throw new Exception(T('User not found.'), 404); } $PhotoUrl = $User['Photo']; if ($PhotoUrl && strpos($PhotoUrl, '//') == FALSE) { $PhotoUrl = Url('/uploads/' . ChangeBasename($PhotoUrl, 'n%s'), TRUE); } $User['Photo'] = $PhotoUrl; // Remove unwanted fields. $this->Data = ArrayTranslate($User, array('UserID', 'Name', 'Email', 'Photo')); $this->Render(); }
public function SendWelcomeEmail($UserID, $Password, $RegisterType = 'Add', $AdditionalData = NULL) { $Session = Gdn::Session(); $Sender = $this->Get($Session->UserID); $User = $this->Get($UserID); $AppTitle = Gdn::Config('Garden.Title'); $Email = new Gdn_Email(); $Email->Subject(sprintf(T('[%s] Welcome Aboard!'), $AppTitle)); $Email->To($User->Email); // Check for the new email format. if (($EmailFormat = T("EmailWelcome{$RegisterType}", '#')) != '#') { $Data = array(); $Data['User'] = ArrayTranslate((array) $User, array('Name', 'Email')); $Data['Sender'] = ArrayTranslate((array) $Sender, array('Name', 'Email')); $Data['Title'] = $AppTitle; if (is_array($AdditionalData)) { $Data = array_merge($Data, $AdditionalData); } $Message = FormatString($EmailFormat, $Data); $Email->Message($Message); } else { $Email->Message(sprintf(T('EmailWelcome'), $User->Name, $Sender->Name, $AppTitle, Gdn_Url::WebRoot(TRUE), $Password, $User->Email)); } $Email->Send(); }