/** * Start a new conversation. * * @since 2.0.0 * @access public * * @param string $Recipient Username of the recipient. */ public function add($Recipient = '') { $this->permission('Conversations.Conversations.Add'); $this->Form->setModel($this->ConversationModel); // Set recipient limit if (!checkPermission('Garden.Moderation.Manage') && c('Conversations.MaxRecipients')) { $this->addDefinition('MaxRecipients', c('Conversations.MaxRecipients')); $this->setData('MaxRecipients', c('Conversations.MaxRecipients')); } if ($this->Form->authenticatedPostBack()) { $RecipientUserIDs = array(); $To = explode(',', $this->Form->getFormValue('To', '')); $UserModel = new UserModel(); foreach ($To as $Name) { if (trim($Name) != '') { $User = $UserModel->getByUsername(trim($Name)); if (is_object($User)) { $RecipientUserIDs[] = $User->UserID; } } } // Enforce MaxRecipients if (!$this->ConversationModel->addUserAllowed(0, count($RecipientUserIDs))) { // Reuse the Info message now as an error. $this->Form->addError(sprintf(plural($this->data('MaxRecipients'), "You are limited to %s recipient.", "You are limited to %s recipients."), c('Conversations.MaxRecipients'))); } $this->EventArguments['Recipients'] = $RecipientUserIDs; $this->fireEvent('BeforeAddConversation'); $this->Form->setFormValue('RecipientUserID', $RecipientUserIDs); $ConversationID = $this->Form->save($this->ConversationMessageModel); if ($ConversationID !== false) { $Target = $this->Form->getFormValue('Target', 'messages/' . $ConversationID); $this->RedirectUrl = url($Target); $Conversation = $this->ConversationModel->getID($ConversationID, Gdn::session()->UserID); $NewMessageID = val('FirstMessageID', $Conversation); $this->EventArguments['MessageID'] = $NewMessageID; $this->fireEvent('AfterConversationSave'); } } else { if ($Recipient != '') { $this->Form->setValue('To', $Recipient); } } if ($Target = Gdn::request()->get('Target')) { $this->Form->addHidden('Target', $Target); } Gdn_Theme::section('PostConversation'); $this->title(t('New Conversation')); $this->setData('Breadcrumbs', array(array('Name' => t('Inbox'), 'Url' => '/messages/inbox'), array('Name' => $this->data('Title'), 'Url' => 'messages/add'))); $this->CssClass = 'NoPanel'; $this->render(); }
/** * Manage options for a theme. * * @since 2.0.0 * @access public * @param string $Style Unique ID. * @todo Why is this in a giant try/catch block? */ public function themeOptions($Style = null) { $this->permission('Garden.Settings.Manage'); try { $this->addJsFile('addons.js'); $this->addSideMenu('dashboard/settings/themeoptions'); $ThemeManager = new Gdn_ThemeManager(); $this->setData('ThemeInfo', $ThemeManager->enabledThemeInfo()); if ($this->Form->authenticatedPostBack()) { // Save the styles to the config. $StyleKey = $this->Form->getFormValue('StyleKey'); $ConfigSaveData = array('Garden.ThemeOptions.Styles.Key' => $StyleKey, 'Garden.ThemeOptions.Styles.Value' => $this->data("ThemeInfo.Options.Styles.{$StyleKey}.Basename")); // Save the text to the locale. $Translations = array(); foreach ($this->data('ThemeInfo.Options.Text', array()) as $Key => $Default) { $Value = $this->Form->getFormValue($this->Form->escapeString('Text_' . $Key)); $ConfigSaveData["ThemeOption.{$Key}"] = $Value; //$this->Form->setFormValue('Text_'.$Key, $Value); } saveToConfig($ConfigSaveData); $this->informMessage(t("Your changes have been saved.")); } elseif ($Style) { saveToConfig(array('Garden.ThemeOptions.Styles.Key' => $Style, 'Garden.ThemeOptions.Styles.Value' => $this->data("ThemeInfo.Options.Styles.{$Style}.Basename"))); } $this->setData('ThemeOptions', c('Garden.ThemeOptions')); $StyleKey = $this->data('ThemeOptions.Styles.Key'); if (!$this->Form->isPostBack()) { foreach ($this->data('ThemeInfo.Options.Text', array()) as $Key => $Options) { $Default = val('Default', $Options, ''); $Value = c("ThemeOption.{$Key}", '#DEFAULT#'); if ($Value === '#DEFAULT#') { $Value = $Default; } $this->Form->setValue($this->Form->escapeString('Text_' . $Key), $Value); } } $this->setData('ThemeFolder', $ThemeManager->enabledTheme()); $this->title(t('Theme Options')); $this->Form->addHidden('StyleKey', $StyleKey); } catch (Exception $Ex) { $this->Form->addError($Ex); } $this->render(); }
/** * Attach editor anywhere 'BodyBox' is used. * * It is not being used for editing a posted reply, so find another event to hook into. * * @param Gdn_Form $Sender */ public function gdn_form_beforeBodyBox_handler($Sender, $Args) { // TODO have some way to prevent this content from getting loaded when in embedded. // The only problem is figuring out how to know when content is embedded. $attributes = array(); if (val('Attributes', $Args)) { $attributes = val('Attributes', $Args); } // TODO move this property to constructor $this->Format = $Sender->getValue('Format'); // Make sure we have some sort of format. if (!$this->Format) { $this->Format = c('Garden.InputFormatter', 'Html'); $Sender->setValue('Format', $this->Format); } // If force Wysiwyg enabled in settings $needsConversion = !in_array($this->Format, array('Html', 'Wysiwyg')); if (c('Garden.InputFormatter', 'Wysiwyg') == 'Wysiwyg' && $this->ForceWysiwyg == true && $needsConversion) { $wysiwygBody = Gdn_Format::to($Sender->getValue('Body'), $this->Format); $Sender->setValue('Body', $wysiwygBody); $this->Format = 'Wysiwyg'; $Sender->setValue('Format', $this->Format); } if (in_array(strtolower($this->Format), array_map('strtolower', $this->Formats))) { $c = Gdn::controller(); // Set minor data for view $c->setData('_EditorInputFormat', $this->Format); // Get the generated editor toolbar from getEditorToolbar, and assign it data object for view. if (!isset($c->Data['_EditorToolbar'])) { $editorToolbar = $this->getEditorToolbar($attributes); $this->EventArguments['EditorToolbar'] =& $editorToolbar; $this->fireEvent('InitEditorToolbar'); // Set data for view $c->setData('_EditorToolbar', $editorToolbar); } $c->addDefinition('canUpload', $this->canUpload); $c->setData('_canUpload', $this->canUpload); // Determine which controller (post or discussion) is invoking this. // At the moment they're both the same, but in future you may want // to know this information to modify it accordingly. $View = $c->fetchView('editor', '', 'plugins/editor'); $Args['BodyBox'] .= $View; } }
/** * Invitation-only registration. Requires code. * * @param int $InvitationCode * @since 2.0.0 */ public function registerInvitation($InvitationCode = 0) { $this->Form->setModel($this->UserModel); // Define gender dropdown options $this->GenderOptions = array('u' => t('Unspecified'), 'm' => t('Male'), 'f' => t('Female')); if (!$this->Form->isPostBack()) { $this->Form->setValue('InvitationCode', $InvitationCode); } $InvitationModel = new InvitationModel(); // Look for the invitation. $Invitation = $InvitationModel->getWhere(array('Code' => $this->Form->getValue('InvitationCode')))->firstRow(DATASET_TYPE_ARRAY); if (!$Invitation) { $this->Form->addError('Invitation not found.', 'Code'); } else { if ($Expires = val('DateExpires', $Invitation)) { $Expires = Gdn_Format::toTimestamp($Expires); if ($Expires <= time()) { } } } $this->Form->addHidden('ClientHour', date('Y-m-d H:00')); // Use the server's current hour as a default $this->Form->addHidden('Target', $this->target()); Gdn::userModel()->addPasswordStrength($this); if ($this->Form->isPostBack() === true) { $this->InvitationCode = $this->Form->getValue('InvitationCode'); // Add validation rules that are not enforced by the model $this->UserModel->defineSchema(); $this->UserModel->Validation->applyRule('Name', 'Username', $this->UsernameError); $this->UserModel->Validation->applyRule('TermsOfService', 'Required', t('You must agree to the terms of service.')); $this->UserModel->Validation->applyRule('Password', 'Required'); $this->UserModel->Validation->applyRule('Password', 'Strength'); $this->UserModel->Validation->applyRule('Password', 'Match'); // $this->UserModel->Validation->applyRule('DateOfBirth', 'MinimumAge'); $this->fireEvent('RegisterValidation'); try { $Values = $this->Form->formValues(); $Values = $this->UserModel->filterForm($Values, true); unset($Values['Roles']); $AuthUserID = $this->UserModel->register($Values, array('Method' => 'Invitation')); $this->setData('UserID', $AuthUserID); if (!$AuthUserID) { $this->Form->setValidationResults($this->UserModel->validationResults()); } else { // The user has been created successfully, so sign in now. Gdn::session()->start($AuthUserID); if ($this->Form->getFormValue('RememberMe')) { Gdn::authenticator()->setIdentity($AuthUserID, true); } $this->fireEvent('RegistrationSuccessful'); // ... and redirect them appropriately $Route = $this->redirectTo(); if ($this->_DeliveryType != DELIVERY_TYPE_ALL) { $this->RedirectUrl = url($Route); } else { if ($Route !== false) { redirect($Route); } } } } catch (Exception $Ex) { $this->Form->addError($Ex); } } else { // Set some form defaults. if ($Name = val('Name', $Invitation)) { $this->Form->setValue('Name', $Name); } $this->InvitationCode = $InvitationCode; } // Make sure that the hour offset for new users gets defined when their account is created $this->addJsFile('entry.js'); $this->render(); }
/** * 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']); } } }
/** * Manage list of locales. * * @since 2.0.0 * @access public * @param string $Op 'enable' or 'disable' * @param string $LocaleKey Unique ID of locale to be modified. * @param string $TransientKey Security token. */ public function locales($Op = null, $LocaleKey = null, $TransientKey = null) { $this->permission('Garden.Settings.Manage'); $this->title(t('Locales')); $this->addSideMenu('dashboard/settings/locales'); $this->addJsFile('addons.js'); $LocaleModel = new LocaleModel(); // Get the available locale packs. $AvailableLocales = $LocaleModel->availableLocalePacks(); // Get the enabled locale packs. $EnabledLocales = $LocaleModel->enabledLocalePacks(); // Check to enable/disable a locale. if ($TransientKey && Gdn::session()->validateTransientKey($TransientKey) || $this->Form->authenticatedPostBack()) { if ($Op) { $Refresh = false; switch (strtolower($Op)) { case 'enable': $Locale = val($LocaleKey, $AvailableLocales); if (!is_array($Locale)) { $this->Form->addError('@' . sprintf(t('The %s locale pack does not exist.'), htmlspecialchars($LocaleKey)), 'LocaleKey'); } elseif (!isset($Locale['Locale'])) { $this->Form->addError('ValidateRequired', 'Locale'); } else { saveToConfig("EnabledLocales.{$LocaleKey}", $Locale['Locale']); $EnabledLocales[$LocaleKey] = $Locale['Locale']; $Refresh = true; } break; case 'disable': RemoveFromConfig("EnabledLocales.{$LocaleKey}"); unset($EnabledLocales[$LocaleKey]); $Refresh = true; break; } // Set default locale field if just doing enable/disable $this->Form->setValue('Locale', Gdn_Locale::canonicalize(c('Garden.Locale', 'en'))); } elseif ($this->Form->authenticatedPostBack()) { // Save the default locale. saveToConfig('Garden.Locale', $this->Form->getFormValue('Locale')); $Refresh = true; $this->informMessage(t("Your changes have been saved.")); } if ($Refresh) { Gdn::locale()->refresh(); redirect('/settings/locales'); } } elseif (!$this->Form->isPostBack()) { $this->Form->setValue('Locale', Gdn_Locale::canonicalize(c('Garden.Locale', 'en'))); } // Check for the default locale warning. $DefaultLocale = Gdn_Locale::canonicalize(c('Garden.Locale')); if ($DefaultLocale !== 'en') { $LocaleFound = false; $MatchingLocales = array(); foreach ($AvailableLocales as $Key => $LocaleInfo) { $Locale = val('Locale', $LocaleInfo); if ($Locale == $DefaultLocale) { $MatchingLocales[] = val('Name', $LocaleInfo, $Key); } if (val($Key, $EnabledLocales) == $DefaultLocale) { $LocaleFound = true; } } $this->setData('DefaultLocale', $DefaultLocale); $this->setData('DefaultLocaleWarning', !$LocaleFound); $this->setData('MatchingLocalePacks', htmlspecialchars(implode(', ', $MatchingLocales))); } $this->setData('AvailableLocales', $AvailableLocales); $this->setData('EnabledLocales', $EnabledLocales); $this->setData('Locales', $LocaleModel->availableLocales()); $this->render(); }
/** * Edit user account. * * @since 2.0.0 * @access public * @param mixed $UserReference Username or User ID. */ public function edit($UserReference = '', $Username = '', $UserID = '') { $this->permission('Garden.SignIn.Allow'); $this->getUserInfo($UserReference, $Username, $UserID, true); $UserID = valr('User.UserID', $this); $Settings = array(); // Set up form $User = Gdn::userModel()->getID($UserID, DATASET_TYPE_ARRAY); $this->Form->setModel(Gdn::userModel()); $this->Form->setData($User); // Decide if they have ability to edit the username $CanEditUsername = (bool) c("Garden.Profile.EditUsernames") || Gdn::session()->checkPermission('Garden.Users.Edit'); $this->setData('_CanEditUsername', $CanEditUsername); // Decide if they have ability to edit the email $EmailEnabled = (bool) c('Garden.Profile.EditEmails', true) && !UserModel::noEmail(); $CanEditEmail = $EmailEnabled && $UserID == Gdn::session()->UserID || checkPermission('Garden.Users.Edit'); $this->setData('_CanEditEmail', $CanEditEmail); // Decide if they have ability to confirm users $Confirmed = (bool) valr('User.Confirmed', $this); $CanConfirmEmail = UserModel::requireConfirmEmail() && checkPermission('Garden.Users.Edit'); $this->setData('_CanConfirmEmail', $CanConfirmEmail); $this->setData('_EmailConfirmed', $Confirmed); $this->Form->setValue('ConfirmEmail', (int) $Confirmed); // Decide if we can *see* email $this->setData('_CanViewPersonalInfo', Gdn::session()->UserID == val('UserID', $User) || checkPermission('Garden.PersonalInfo.View') || checkPermission('Garden.Users.Edit')); // Define gender dropdown options $this->GenderOptions = array('u' => t('Unspecified'), 'm' => t('Male'), 'f' => t('Female')); $this->fireEvent('BeforeEdit'); // If seeing the form for the first time... if ($this->Form->authenticatedPostBack()) { $this->Form->setFormValue('UserID', $UserID); if (!$CanEditUsername) { $this->Form->setFormValue("Name", $User['Name']); } else { $UsernameError = t('UsernameError', 'Username can only contain letters, numbers, underscores, and must be between 3 and 20 characters long.'); Gdn::userModel()->Validation->applyRule('Name', 'Username', $UsernameError); } // API // These options become available when POSTing as a user with Garden.Settings.Manage permissions if (Gdn::session()->checkPermission('Garden.Settings.Manage')) { // Role change $RequestedRoles = $this->Form->getFormValue('RoleID', null); if (!is_null($RequestedRoles)) { $RoleModel = new RoleModel(); $AllRoles = $RoleModel->getArray(); if (!is_array($RequestedRoles)) { $RequestedRoles = is_numeric($RequestedRoles) ? array($RequestedRoles) : array(); } $RequestedRoles = array_flip($RequestedRoles); $UserNewRoles = array_intersect_key($AllRoles, $RequestedRoles); // Put the data back into the forum object as if the user had submitted // this themselves $this->Form->setFormValue('RoleID', array_keys($UserNewRoles)); // Allow saving roles $Settings['SaveRoles'] = true; } // Password change $NewPassword = $this->Form->getFormValue('Password', null); if (!is_null($NewPassword)) { } } // Allow mods to confirm emails $this->Form->removeFormValue('Confirmed'); $Confirmation = $this->Form->getFormValue('ConfirmEmail', null); $Confirmation = !is_null($Confirmation) ? (bool) $Confirmation : null; if ($CanConfirmEmail && is_bool($Confirmation)) { $this->Form->setFormValue('Confirmed', (int) $Confirmation); } if ($this->Form->save($Settings) !== false) { $User = Gdn::userModel()->getID($UserID, DATASET_TYPE_ARRAY); $this->setData('Profile', $User); $this->informMessage(sprite('Check', 'InformSprite') . t('Your changes have been saved.'), 'Dismissable AutoDismiss HasSprite'); } if (!$CanEditEmail) { $this->Form->setFormValue("Email", $User['Email']); } } $this->title(t('Edit Profile')); $this->_setBreadcrumbs(t('Edit Profile'), '/profile/edit'); $this->render(); }
/** * Editing a category. * * @since 2.0.0 * @access public * * @param int $CategoryID Unique ID of the category to be updated. */ public function editCategory($CategoryID = '') { // Check permission $this->permission('Garden.Community.Manage'); // Set up models $RoleModel = new RoleModel(); $PermissionModel = Gdn::permissionModel(); $this->Form->setModel($this->CategoryModel); if (!$CategoryID && $this->Form->authenticatedPostBack()) { if ($ID = $this->Form->getFormValue('CategoryID')) { $CategoryID = $ID; } } // Get category data $this->Category = $this->CategoryModel->getID($CategoryID); if (!$this->Category) { throw notFoundException('Category'); } $this->Category->CustomPermissions = $this->Category->CategoryID == $this->Category->PermissionCategoryID; // Set up head $this->addJsFile('jquery.alphanumeric.js'); $this->addJsFile('categories.js'); $this->addJsFile('jquery.gardencheckboxgrid.js'); $this->title(t('Edit Category')); $this->addSideMenu('vanilla/settings/managecategories'); // Make sure the form knows which item we are editing. $this->Form->addHidden('CategoryID', $CategoryID); $this->setData('CategoryID', $CategoryID); // Load all roles with editable permissions $this->RoleArray = $RoleModel->getArray(); $this->fireEvent('AddEditCategory'); if ($this->Form->authenticatedPostBack()) { $this->setupDiscussionTypes($this->Category); $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, $ImageBaseName); $this->Form->setFormValue('Photo', $Parts['SaveName']); } $this->Form->setFormValue('CustomPoints', (bool) $this->Form->getFormValue('CustomPoints')); if ($this->Form->save()) { $Category = CategoryModel::categories($CategoryID); $this->setData('Category', $Category); if ($this->deliveryType() == DELIVERY_TYPE_ALL) { redirect('vanilla/settings/managecategories'); } } } else { $this->Form->setData($this->Category); $this->setupDiscussionTypes($this->Category); $this->Form->setValue('CustomPoints', $this->Category->PointsCategoryID == $this->Category->CategoryID); } // Get all of the currently selected role/permission combinations for this junction. $Permissions = $PermissionModel->getJunctionPermissions(array('JunctionID' => $CategoryID), 'Category', '', array('AddDefaults' => !$this->Category->CustomPermissions)); $Permissions = $PermissionModel->unpivotPermissions($Permissions, true); if ($this->deliveryType() == DELIVERY_TYPE_ALL) { $this->setData('PermissionData', $Permissions, true); } // Render default view $this->render(); }
/** * Editing a category. * * @since 2.0.0 * @param int|string $CategoryID Unique ID of the category to be updated. * @throws Exception when category cannot be found. */ public function editCategory($CategoryID = '') { // Check permission $this->permission(['Garden.Community.Manage', 'Garden.Settings.Manage'], false); // Set up models $RoleModel = new RoleModel(); $PermissionModel = Gdn::permissionModel(); $this->Form->setModel($this->CategoryModel); if (!$CategoryID && $this->Form->authenticatedPostBack()) { if ($ID = $this->Form->getFormValue('CategoryID')) { $CategoryID = $ID; } } // Get category data $this->Category = CategoryModel::categories($CategoryID); if (!$this->Category) { throw notFoundException('Category'); } // Category data is expected to be in the form of an object. $this->Category = (object) $this->Category; $this->Category->CustomPermissions = $this->Category->CategoryID == $this->Category->PermissionCategoryID; $displayAsOptions = categoryModel::getDisplayAsOptions(); // Restrict "Display As" types based on parent. $parentCategory = $this->CategoryModel->getID($this->Category->ParentCategoryID); $parentDisplay = val('DisplayAs', $parentCategory); if ($parentDisplay === 'Flat') { unset($displayAsOptions['Heading']); } // Set up head $this->addJsFile('jquery.alphanumeric.js'); $this->addJsFile('manage-categories.js'); $this->addJsFile('jquery.gardencheckboxgrid.js'); $this->title(t('Edit Category')); $this->setHighlightRoute('vanilla/settings/categories'); // Make sure the form knows which item we are editing. $this->Form->addHidden('CategoryID', $CategoryID); $this->setData('CategoryID', $CategoryID); // Load all roles with editable permissions $this->RoleArray = $RoleModel->getArray(); $this->fireAs('SettingsController'); $this->fireEvent('AddEditCategory'); if ($this->Form->authenticatedPostBack()) { $this->setupDiscussionTypes($this->Category); $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, $ImageBaseName); $this->Form->setFormValue('Photo', $Parts['SaveName']); } $this->Form->setFormValue('CustomPoints', (bool) $this->Form->getFormValue('CustomPoints')); // Enforces tinyint values on boolean fields to comply with strict mode $this->Form->setFormValue('HideAllDiscussions', forceBool($this->Form->getFormValue('HideAllDiscussions'), '0', '1', '0')); $this->Form->setFormValue('Archived', forceBool($this->Form->getFormValue('Archived'), '0', '1', '0')); $this->Form->setFormValue('AllowFileUploads', forceBool($this->Form->getFormValue('AllowFileUploads'), '0', '1', '0')); if ($parentDisplay === 'Flat' && $this->Form->getFormValue('DisplayAs') === 'Heading') { $this->Form->addError('Cannot display as a heading when your parent category is displayed flat.', 'DisplayAs'); } if ($this->Form->save()) { $Category = CategoryModel::categories($CategoryID); $this->setData('Category', $Category); if ($this->deliveryType() == DELIVERY_TYPE_ALL) { $destination = $this->categoryPageByParent($parentCategory); redirect($destination); } elseif ($this->deliveryType() === DELIVERY_TYPE_DATA && method_exists($this, 'getCategory')) { $this->Data = []; $this->getCategory($CategoryID); return; } } } else { $this->Form->setData($this->Category); $this->setupDiscussionTypes($this->Category); $this->Form->setValue('CustomPoints', $this->Category->PointsCategoryID == $this->Category->CategoryID); } // Get all of the currently selected role/permission combinations for this junction. $Permissions = $PermissionModel->getJunctionPermissions(array('JunctionID' => $CategoryID), 'Category', '', array('AddDefaults' => !$this->Category->CustomPermissions)); $Permissions = $PermissionModel->unpivotPermissions($Permissions, true); if ($this->deliveryType() == DELIVERY_TYPE_ALL) { $this->setData('PermissionData', $Permissions, true); } // Render default view $this->setData('Operation', 'Edit'); $this->setData('DisplayAsOptions', $displayAsOptions); $this->render(); }