/** * * @param Gdn_Controller $Sender * @throws Exception */ public function __construct($Sender = null) { if (property_exists($Sender, 'Conversation')) { $this->Conversation = $Sender->Conversation; } // Allowed to use this module? $this->AddUserAllowed = $Sender->ConversationModel->addUserAllowed($this->Conversation->ConversationID); $this->Form = Gdn::factory('Form', 'AddPeople'); // If the form was posted back, check for people to add to the conversation if ($this->Form->authenticatedPostBack()) { // Defer exceptions until they try to use the form so we don't fill our logs if (!$this->AddUserAllowed || !checkPermission('Conversations.Conversations.Add')) { throw permissionException(); } $NewRecipientUserIDs = array(); $NewRecipients = explode(',', $this->Form->getFormValue('AddPeople', '')); $UserModel = Gdn::factory("UserModel"); foreach ($NewRecipients as $Name) { if (trim($Name) != '') { $User = $UserModel->getByUsername(trim($Name)); if (is_object($User)) { $NewRecipientUserIDs[] = $User->UserID; } } } $Sender->ConversationModel->addUserToConversation($this->Conversation->ConversationID, $NewRecipientUserIDs); $Sender->informMessage(t('Your changes were saved.')); $Sender->RedirectUrl = url('/messages/' . $this->Conversation->ConversationID); } $this->_ApplicationFolder = $Sender->Application; $this->_ThemeFolder = $Sender->Theme; }
/** * * * @param $Category * @param $Month * @param bool $Page * @throws Exception * @throws Gdn_UserException */ public function archives($Category, $Month, $Page = false) { $Category = CategoryModel::categories($Category); if (!$Category) { throw notFoundException('Category'); } if (!$Category['PermsDiscussionsView']) { throw permissionException(); } $Timestamp = strtotime($Month); if (!$Timestamp) { throw new Gdn_UserException("The archive month is not a valid date."); } $this->setData('Category', $Category); // Round the month to the first day. $From = gmdate('Y-m-01', $Timestamp); $To = gmdate('Y-m-01', strtotime('+1 month', strtotime($From))); // Grab the discussions. list($Offset, $Limit) = offsetLimit($Page, c('Vanilla.Discussions.PerPage', 30)); $Where = array('CategoryID' => $Category['CategoryID'], 'Announce' => 'all', 'DateInserted >=' => $From, 'DateInserted <' => $To); saveToConfig('Vanilla.Discussions.SortField', 'd.DateInserted', false); $DiscussionModel = new DiscussionModel(); $DiscussionModel->setSort(Gdn::request()->get()); $DiscussionModel->setFilters(Gdn::request()->get()); $this->setData('Sort', $DiscussionModel->getSort()); $this->setData('Filters', $DiscussionModel->getFilters()); $Discussions = $DiscussionModel->getWhereRecent($Where, $Limit, $Offset); $this->DiscussionData = $this->setData('Discussions', $Discussions); $this->setData('_CurrentRecords', count($Discussions)); $this->setData('_Limit', $Limit); $Canonical = '/categories/archives/' . rawurlencode($Category['UrlCode']) . '/' . gmdate('Y-m', $Timestamp); $Page = PageNumber($Offset, $Limit, true, false); $this->canonicalUrl(url($Canonical . ($Page ? '?page=' . $Page : ''), true)); PagerModule::Current()->configure($Offset, $Limit, false, $Canonical . '?page={Page}'); // PagerModule::Current()->Offset = $Offset; // PagerModule::Current()->Url = '/categories/archives'.rawurlencode($Category['UrlCode']).'?page={Page}'; Gdn_Theme::section(val('CssClass', $Category)); Gdn_Theme::section('DiscussionList'); $this->title(htmlspecialchars(val('Name', $Category, ''))); $this->Description(sprintf(t("Archives for %s"), gmdate('F Y', strtotime($From))), true); $this->addJsFile('discussions.js'); $this->Head->addTag('meta', array('name' => 'robots', 'content' => 'noindex')); $this->ControllerName = 'DiscussionsController'; $this->CssClass = 'Discussions'; $this->render(); }
/** * Set user preference for sorting discussions. * * @param string $Target The target to redirect to. */ public function sort($Target = '') { deprecated("sort"); if (!Gdn::session()->isValid()) { throw permissionException(); } if (!$this->Request->isAuthenticatedPostBack()) { throw forbiddenException('GET'); } if ($Target) { redirect($Target); } // Send sorted discussions. $this->setData('Deprecated', true); $this->deliveryMethod(DELIVERY_METHOD_JSON); $this->render(); }
/** * * * @param DiscussionController $sender Sending controller instance. * @param array $args Event arguments. * * @throws notFoundException */ public function discussionController_QnA_create($sender, $args) { $Comment = Gdn::SQL()->getWhere('Comment', array('CommentID' => $sender->Request->get('commentid')))->firstRow(DATASET_TYPE_ARRAY); if (!$Comment) { throw notFoundException('Comment'); } $Discussion = Gdn::SQL()->getWhere('Discussion', array('DiscussionID' => $Comment['DiscussionID']))->firstRow(DATASET_TYPE_ARRAY); // Check for permission. if (!(Gdn::session()->UserID == val('InsertUserID', $Discussion) || Gdn::session()->checkPermission('Garden.Moderation.Manage'))) { throw permissionException('Garden.Moderation.Manage'); } if (!Gdn::session()->validateTransientKey($sender->Request->get('tkey'))) { throw permissionException(); } switch ($args[0]) { case 'accept': $QnA = 'Accepted'; break; case 'reject': $QnA = 'Rejected'; break; } if (isset($QnA)) { $DiscussionSet = array('QnA' => $QnA); $CommentSet = array('QnA' => $QnA); if ($QnA == 'Accepted') { $CommentSet['DateAccepted'] = Gdn_Format::toDateTime(); $CommentSet['AcceptedUserID'] = Gdn::session()->UserID; if (!$Discussion['DateAccepted']) { $DiscussionSet['DateAccepted'] = Gdn_Format::toDateTime(); $DiscussionSet['DateOfAnswer'] = $Comment['DateInserted']; } } // Update the comment. Gdn::SQL()->put('Comment', $CommentSet, array('CommentID' => $Comment['CommentID'])); // Update the discussion. if ($Discussion['QnA'] != $QnA && (!$Discussion['QnA'] || in_array($Discussion['QnA'], array('Unanswered', 'Answered', 'Rejected')))) { Gdn::SQL()->put('Discussion', $DiscussionSet, array('DiscussionID' => $Comment['DiscussionID'])); } // Determine QnA change if ($Comment['QnA'] != $QnA) { $Change = 0; switch ($QnA) { case 'Rejected': $Change = -1; if ($Comment['QnA'] != 'Accepted') { $Change = 0; } break; case 'Accepted': $Change = 1; if (!$this->Reactions && c('QnA.Points.Enabled', false) && $Discussion['InsertUserID'] != $Comment['InsertUserID']) { UserModel::givePoints($Comment['InsertUserID'], c('QnA.Points.AcceptedAnswer', 1), 'QnA'); } break; default: if ($Comment['QnA'] == 'Rejected') { $Change = 0; } if ($Comment['QnA'] == 'Accepted') { $Change = -1; } break; } } // Apply change effects if ($Change) { // Update the user $UserID = val('InsertUserID', $Comment); $this->recalculateUserQnA($UserID); // Update reactions if ($this->Reactions) { include_once Gdn::controller()->fetchViewLocation('reaction_functions', '', 'plugins/Reactions'); $Rm = new ReactionModel(); // If there's change, reactions will take care of it $Rm->react('Comment', $Comment['CommentID'], 'AcceptAnswer', null, true); } } // Record the activity. if ($QnA == 'Accepted') { $Activity = array('ActivityType' => 'AnswerAccepted', 'NotifyUserID' => $Comment['InsertUserID'], 'HeadlineFormat' => '{ActivityUserID,You} accepted {NotifyUserID,your} answer.', 'RecordType' => 'Comment', 'RecordID' => $Comment['CommentID'], 'Route' => commentUrl($Comment, '/'), 'Emailed' => ActivityModel::SENT_PENDING, 'Notified' => ActivityModel::SENT_PENDING); $ActivityModel = new ActivityModel(); $ActivityModel->save($Activity); $this->EventArguments['Activity'] =& $Activity; $this->fireEvent('AfterAccepted'); } } redirect("/discussion/comment/{$Comment['CommentID']}#Comment_{$Comment['CommentID']}"); }
/** * Delete a screenshot from an addon. * * @param string $AddonPictureID Picture id to remove. * @throws Gdn_UserException No permission to delete this picture. */ public function deletePicture($AddonPictureID = '') { $AddonPictureModel = new Gdn_Model('AddonPicture'); $Picture = $AddonPictureModel->getWhere(array('AddonPictureID' => $AddonPictureID))->firstRow(); $AddonModel = new AddonModel(); $Addon = $AddonModel->getID($Picture->AddonID); $Session = Gdn::session(); if ($Session->UserID != $Addon['InsertUserID'] && !$Session->checkPermission('Addons.Addon.Manage')) { throw permissionException(); } if ($this->Form->authenticatedPostBack() && $this->Form->getFormValue('Yes')) { if ($Picture) { $Upload = new Gdn_Upload(); $Upload->delete(changeBasename($Picture->File, 'ao%s')); $Upload->delete(changeBasename($Picture->File, 'at%s')); $AddonPictureModel->delete(array('AddonPictureID' => $AddonPictureID)); } $this->RedirectUrl = url('/addon/' . $Picture->AddonID); } $this->render('deletepicture'); }
/** * 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); // Make sure none of the selected discussions are ghost redirects. $discussionTypes = array_column($Discussions, 'Type'); if (in_array('redirect', $discussionTypes)) { throw Gdn_UserException('You cannot merge redirects.', 400); } // 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 = val('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'); }
/** * Form for sending a test email. * On postback, sends a test email to the addresses specified in the form. * * @throws Exception * @throws Gdn_UserException */ public function emailTest() { if (!Gdn::session()->checkPermission('Garden.Community.Manage')) { throw permissionException(); } $this->setHighlightRoute('dashboard/settings/email'); $this->Form = new Gdn_Form(); $validation = new Gdn_Validation(); $configurationModel = new Gdn_ConfigurationModel($validation); $this->Form->setModel($configurationModel); if ($this->Form->authenticatedPostBack() !== false) { $addressList = $this->Form->getFormValue('EmailTestAddresses'); $addresses = explode(',', $addressList); if (sizeof($addresses) > 10) { $this->Form->addError(sprintf(t('Too many addresses! We\'ll send up to %s addresses at once.'), '10')); } else { $emailer = $this->getTestEmail(); $emailer->to($addresses); $emailer->subject(sprintf(t('Test email from %s'), c('Garden.Title'))); try { if ($emailer->send()) { $this->informMessage(t("The email has been sent.")); } else { $this->Form->addError(t('Error sending email. Please review the addresses and try again.')); } } catch (Exception $e) { if (debug()) { throw $e; } } } } $this->render(); }
/** * * * @throws Exception */ public function setHourOffset() { $Form = new Gdn_Form(); if ($Form->authenticatedPostBack()) { if (!Gdn::session()->isValid()) { throw permissionException('Garden.SignIn.Allow'); } $HourOffset = $Form->getFormValue('HourOffset'); Gdn::userModel()->setField(Gdn::session()->UserID, 'HourOffset', $HourOffset); $this->setData('Result', true); $this->setData('HourOffset', $HourOffset); $time = time(); $this->setData('UTCDateTime', gmdate('r', $time)); $this->setData('UserDateTime', gmdate('r', $time + $HourOffset * 3600)); } else { throw forbiddenException('GET'); } $this->render('Blank'); }
/** * Retrieve the user to be manipulated. Defaults to current user. * * @since 2.0.0 * @access public * @param mixed $User Unique identifier, possibly username or ID. * @param string $Username . * @param int $UserID Unique ID. * @param bool $CheckPermissions Whether or not to check user permissions. * @return bool Always true. */ public function getUserInfo($UserReference = '', $Username = '', $UserID = '', $CheckPermissions = false) { if ($this->_UserInfoRetrieved) { return; } if (!c('Garden.Profile.Public') && !Gdn::session()->isValid()) { throw permissionException(); } // If a UserID was provided as a querystring parameter, use it over anything else: if ($UserID) { $UserReference = $UserID; $Username = '******'; // Fill this with a value so the $UserReference is assumed to be an integer/userid. } $this->Roles = array(); if ($UserReference == '') { if ($Username) { $this->User = $this->UserModel->getByUsername($Username); } else { $this->User = $this->UserModel->getID(Gdn::session()->UserID); } } elseif (is_numeric($UserReference) && $Username != '') { $this->User = $this->UserModel->getID($UserReference); } else { $this->User = $this->UserModel->getByUsername($UserReference); } $this->fireEvent('UserLoaded'); if ($this->User === false) { throw notFoundException('User'); } elseif ($this->User->Deleted == 1) { redirect('dashboard/home/deleted'); } else { $this->RoleData = $this->UserModel->getRoles($this->User->UserID); if ($this->RoleData !== false && $this->RoleData->numRows(DATASET_TYPE_ARRAY) > 0) { $this->Roles = array_column($this->RoleData->resultArray(), 'Name'); } // Hide personal info roles if (!checkPermission('Garden.PersonalInfo.View')) { $this->Roles = array_filter($this->Roles, 'RoleModel::FilterPersonalInfo'); } $this->setData('Profile', $this->User); $this->setData('UserRoles', $this->Roles); if ($CssClass = val('_CssClass', $this->User)) { $this->CssClass .= ' ' . $CssClass; } } if ($CheckPermissions && Gdn::session()->UserID != $this->User->UserID) { $this->permission(array('Garden.Users.Edit', 'Moderation.Profiles.Edit'), false); } $this->addSideMenu(); $this->_UserInfoRetrieved = true; return true; }
/** * * * @param $ConversationID * @param null $LastMessageID * @throws Exception */ public function getNew($ConversationID, $LastMessageID = null) { $this->RecipientData = $this->ConversationModel->getRecipients($ConversationID); $this->setData('Recipients', $this->RecipientData); // Check permissions on the recipients. $InConversation = false; foreach ($this->RecipientData->result() as $Recipient) { if ($Recipient->UserID == Gdn::session()->UserID) { $InConversation = true; break; } } if (!$InConversation) { // Conversation moderation must be enabled and they must have permission if (!c('Conversations.Moderation.Allow', false)) { throw permissionException(); } $this->permission('Conversations.Moderation.Manage'); } $this->Conversation = $this->ConversationModel->getID($ConversationID); $this->setData('Conversation', $this->Conversation); // Bad conversation? Redirect if ($this->Conversation === false) { throw notFoundException('Conversation'); } $Where = array(); if ($LastMessageID) { if (strpos($LastMessageID, '_') !== false) { $LastMessageID = array_pop(explode('_', $LastMessageID)); } $Where['MessageID >='] = $LastMessageID; } // Fetch message data $this->setData('MessageData', $this->ConversationMessageModel->get($ConversationID, Gdn::session()->UserID, 0, 50, $Where), true); $this->render('Messages'); }
/** * Delete an activity item. * * @since 2.0.0 * @access public * * @param int $ActivityID Unique ID of item to delete. * @param string $TransientKey Verify intent. */ public function delete($ActivityID = '', $TransientKey = '') { $session = Gdn::session(); if (!$session->validateTransientKey($TransientKey)) { throw permissionException(); } if (!is_numeric($ActivityID)) { throw Gdn_UserException('Invalid ID'); } if (!$this->ActivityModel->canDelete($this->ActivityModel->getID($ActivityID))) { throw permissionException(); } $this->ActivityModel->delete($ActivityID); if ($this->_DeliveryType === DELIVERY_TYPE_ALL) { redirect(GetIncomingValue('Target', $this->SelfUrl)); } // Still here? Getting a 404. $this->ControllerName = 'Home'; $this->View = 'FileNotFound'; $this->render(); }
/** * Set user preference for sorting discussions. */ public function sort($Target = '') { if (!Gdn::session()->isValid()) { throw permissionException(); } if (!$this->Request->isAuthenticatedPostBack()) { throw forbiddenException('GET'); } // Get param $SortField = Gdn::request()->Post('DiscussionSort'); $SortField = 'd.' . stringBeginsWith($SortField, 'd.', true, true); // Use whitelist here too to keep database clean if (!in_array($SortField, DiscussionModel::AllowedSortFields())) { throw new Gdn_UserException("Unknown sort {$SortField}."); } // Set user pref Gdn::userModel()->SavePreference(Gdn::session()->UserID, 'Discussions.SortField', $SortField); if ($Target) { redirect($Target); } // Send sorted discussions. $this->deliveryMethod(DELIVERY_METHOD_JSON); $this->render(); }
/** * * @param PostController $Sender * @param type $RecordType * @param type $ID * @throws type */ public function postController_facebook_create($Sender, $RecordType, $ID) { if (!$this->socialReactions()) { throw permissionException(); } $Row = getRecord($RecordType, $ID, true); if ($Row) { $Message = sliceParagraph(Gdn_Format::plainText($Row['Body'], $Row['Format']), 160); if ($this->accessToken() && $Sender->Request->isPostBack()) { $R = $this->api('/me/feed', array('link' => $Row['ShareUrl'], 'message' => $Message)); $Sender->setJson('R', $R); $Sender->informMessage(t('Thanks for sharing!')); } else { $Get = array('app_id' => c('Plugins.Facebook.ApplicationID'), 'link' => $Row['ShareUrl'], 'name' => Gdn_Format::plainText($Row['Name'], 'Text'), 'description' => $Message, 'redirect_uri' => url('/post/shared/facebook', true)); $Url = 'http://www.facebook.com/dialog/feed?' . http_build_query($Get); redirect($Url); } } $Sender->render('Blank', 'Utility', 'Dashboard'); }
/** * * * @param $UserID * @param $Verified * @throws Exception */ public function verify($UserID, $Verified) { $this->permission('Garden.Moderation.Manage'); if (!$this->Request->isAuthenticatedPostBack()) { throw permissionException('Javascript'); } // First, set the field value. Gdn::userModel()->setField($UserID, 'Verified', $Verified); $User = Gdn::userModel()->getID($UserID); if (!$User) { throw notFoundException('User'); } // Send back the verified button. require_once $this->fetchViewLocation('helper_functions', 'Profile', 'Dashboard'); $this->jsonTarget('.User-Verified', userVerified($User), 'ReplaceWith'); $this->render('Blank', 'Utility', 'Dashboard'); }
/** * * * @throws Exception */ public function setHourOffset() { $Form = new Gdn_Form(); if ($Form->authenticatedPostBack()) { if (!Gdn::session()->isValid()) { throw permissionException('Garden.SignIn.Allow'); } $HourOffset = $Form->getFormValue('HourOffset'); Gdn::userModel()->setField(Gdn::session()->UserID, 'HourOffset', $HourOffset); // If we receive a time zone, only accept it if we can verify it as a valid identifier. $timeZone = $Form->getFormValue('TimeZone'); if (!empty($timeZone)) { try { $tz = new DateTimeZone($timeZone); Gdn::userModel()->saveAttribute(Gdn::session()->UserID, ['TimeZone' => $tz->getName(), 'SetTimeZone' => null]); } catch (\Exception $ex) { Logger::log(Logger::ERROR, $ex->getMessage(), ['timeZone' => $timeZone]); Gdn::userModel()->saveAttribute(Gdn::session()->UserID, ['TimeZone' => null, 'SetTimeZone' => $timeZone]); $timeZone = ''; } } elseif ($currentTimeZone = Gdn::session()->getAttribute('TimeZone')) { // Check to see if the current timezone agrees with the posted offset. try { $tz = new DateTimeZone($currentTimeZone); $currentHourOffset = $tz->getOffset(new DateTime()) / 3600; if ($currentHourOffset != $HourOffset) { // Clear out the current timezone or else it will override the browser's offset. Gdn::userModel()->saveAttribute(Gdn::session()->UserID, ['TimeZone' => null, 'SetTimeZone' => null]); } else { $timeZone = $tz->getName(); } } catch (Exception $ex) { Logger::log(Logger::ERROR, "Clearing out bad timezone: {timeZone}", ['timeZone' => $currentTimeZone]); // Clear out the bad timezone. Gdn::userModel()->saveAttribute(Gdn::session()->UserID, ['TimeZone' => null, 'SetTimeZone' => null]); } } $this->setData('Result', true); $this->setData('HourOffset', $HourOffset); $this->setData('TimeZone', $timeZone); $time = time(); $this->setData('UTCDateTime', gmdate('r', $time)); $this->setData('UserDateTime', gmdate('r', $time + $HourOffset * 3600)); } else { throw forbiddenException('GET'); } $this->render('Blank'); }
/** * Synchronizes the user based on a given UserKey. * * @param string $UserKey A string that uniquely identifies this user. * @param array $Data Information to put in the user table. * @return int The ID of the user. */ public function synchronize($UserKey, $Data) { $UserID = 0; $Attributes = val('Attributes', $Data); if (is_string($Attributes)) { $Attributes = dbdecode($Attributes); } if (!is_array($Attributes)) { $Attributes = []; } // If the user didnt log in, they won't have a UserID yet. That means they want a new // account. So create one for them. if (!isset($Data['UserID']) || $Data['UserID'] <= 0) { // Prepare the user data. $UserData = []; $UserData['Name'] = $Data['Name']; $UserData['Password'] = randomString(16); $UserData['Email'] = val('Email', $Data, '*****@*****.**'); $UserData['Gender'] = strtolower(substr(val('Gender', $Data, 'u'), 0, 1)); $UserData['HourOffset'] = val('HourOffset', $Data, 0); $UserData['DateOfBirth'] = val('DateOfBirth', $Data, ''); $UserData['CountNotifications'] = 0; $UserData['Attributes'] = $Attributes; $UserData['InsertIPAddress'] = ipEncode(Gdn::request()->ipAddress()); if ($UserData['DateOfBirth'] == '') { $UserData['DateOfBirth'] = '1975-09-16'; } // Make sure there isn't another user with this username. if ($this->validateUniqueFields($UserData['Name'], $UserData['Email'])) { if (!BanModel::checkUser($UserData, $this->Validation, true)) { throw permissionException('Banned'); } // Insert the new user. $this->addInsertFields($UserData); $UserID = $this->insertInternal($UserData); } if ($UserID > 0) { $NewUserRoleIDs = $this->newUserRoleIDs(); // Save the roles. $Roles = val('Roles', $Data, false); if (empty($Roles)) { $Roles = $NewUserRoleIDs; } $this->saveRoles($UserID, $Roles, false); } } else { $UserID = $Data['UserID']; } // Synchronize the transientkey from the external user data source if it is present (eg. WordPress' wpnonce). if (array_key_exists('TransientKey', $Attributes) && $Attributes['TransientKey'] != '' && $UserID > 0) { $this->setTransientKey($UserID, $Attributes['TransientKey']); } return $UserID; }
/** * Delete an activity item. * * @since 2.0.0 * @access public * * @param int $ActivityID Unique ID of item to delete. * @param string $TransientKey Verify intent. */ public function delete($ActivityID = '', $TransientKey = '') { $session = Gdn::session(); if (!$session->validateTransientKey($TransientKey)) { throw permissionException(); } if (!is_numeric($ActivityID)) { throw Gdn_UserException('Invalid ID'); } if (!$this->ActivityModel->canDelete($this->ActivityModel->getID($ActivityID))) { throw permissionException(); } $this->ActivityModel->deleteID($ActivityID); if ($this->_DeliveryType === DELIVERY_TYPE_ALL) { $target = Gdn::request()->get('Target'); if ($target) { // Bail with a redirect if we got one. redirect($target); } else { // We got this as a full page somehow, so send them back to /activity. $this->RedirectUrl = url('activity'); } } $this->render(); }
/** * Display 'no permission' page. * * @since 2.0.0 * @access public */ public function unauthorized() { Gdn_Theme::section('Error'); if ($this->deliveryMethod() == DELIVERY_METHOD_XHTML) { safeHeader("HTTP/1.0 401", true, 401); $this->render(); } else { $this->RenderException(permissionException()); } }
/** * * * @param PostController $Sender * @param type $RecordType * @param type $ID * @throws type */ public function postController_twitter_create($Sender, $RecordType, $ID) { if (!$this->socialReactions()) { throw permissionException(); } // if (!Gdn::request()->isPostBack()) // throw permissionException('Javascript'); $Row = GetRecord($RecordType, $ID, true); if ($Row) { // Grab the tweet message. switch (strtolower($RecordType)) { case 'discussion': $Message = Gdn_Format::plainText($Row['Name'], 'Text'); break; case 'comment': default: $Message = Gdn_Format::plainText($Row['Body'], $Row['Format']); } $Elips = '...'; $Message = preg_replace('`\\s+`', ' ', $Message); // if (function_exists('normalizer_is_normalized')) { // // Slice the string to 119 characters (21 reservered for the url. // if (!normalizer_is_normalized($Message)) // $Message = Normalizer::normalize($Message, Normalizer::FORM_D); // $Elips = Normalizer::normalize($Elips, Normalizer::FORM_D); // } $Max = 140; $LinkLen = 22; $Max -= $LinkLen; $Message = SliceParagraph($Message, $Max); if (strlen($Message) > $Max) { $Message = substr($Message, 0, $Max - strlen($Elips)) . $Elips; } // echo $Message.strlen($Message); if ($this->accessToken()) { Gdn::controller()->setData('Message', $Message); $Message .= ' ' . $Row['ShareUrl']; $R = $this->api('/statuses/update.json', array('status' => $Message), 'POST'); $Sender->setJson('R', $R); $Sender->informMessage(t('Thanks for sharing!')); } else { $Get = array('text' => $Message, 'url' => $Row['ShareUrl']); $Url = "https://twitter.com/share?" . http_build_query($Get); redirect($Url); } } $Sender->render('Blank', 'Utility', 'Dashboard'); }
/** * Re-fetch a discussion's content based on its foreign url. * @param type $DiscussionID */ public function refetchPageInfo($DiscussionID) { // Make sure we are posting back. if (!$this->Request->isAuthenticatedPostBack(true)) { throw permissionException('Javascript'); } // Grab the discussion. $Discussion = $this->DiscussionModel->getID($DiscussionID); if (!$Discussion) { throw notFoundException('Discussion'); } // Make sure the user has permission to edit this discussion. $this->permission('Vanilla.Discussions.Edit', true, 'Category', $Discussion->PermissionCategoryID); $ForeignUrl = valr('Attributes.ForeignUrl', $Discussion); if (!$ForeignUrl) { throw new Gdn_UserException(t("This discussion isn't associated with a url.")); } $Stub = $this->DiscussionModel->fetchPageInfo($ForeignUrl, true); // Save the stub. $this->DiscussionModel->setField($DiscussionID, (array) $Stub); // Send some of the stuff back. if (isset($Stub['Name'])) { $this->jsonTarget('.PageTitle h1', Gdn_Format::text($Stub['Name'])); } if (isset($Stub['Body'])) { $this->jsonTarget("#Discussion_{$DiscussionID} .Message", Gdn_Format::to($Stub['Body'], $Stub['Format'])); } $this->informMessage('The page was successfully fetched.'); $this->render('Blank', 'Utility', 'Dashboard'); }
/** * Do permission check. * * @since 2.0.0 * @access protected */ protected function _permission($RoleID = null) { $this->permission(array('Garden.Settings.Manage', 'Garden.Roles.Manage'), false); if ($RoleID && !checkPermission('Garden.Settings.Manage')) { // Make sure the user can assign this role. $Assignable = $this->RoleModel->getAssignable(); if (!isset($Assignable[$RoleID])) { throw permissionException('@' . t("You don't have permission to modify this role.")); } } return true; }
/** * * * @param string|unknown_type $InvitationID * @return bool * @throws Exception */ public function delete($InvitationID) { $Session = Gdn::session(); $UserID = $Session->UserID; // Validate that this user can delete this invitation: $Invitation = $this->getID($InvitationID, DATASET_TYPE_ARRAY); // Does the invitation exist? if (!$Invitation) { throw notFoundException('Invitation'); } // Does this user own the invitation? if ($UserID != $Invitation['InsertUserID'] && !$Session->checkPermission('Garden.Moderation.Manage')) { throw permissionException('@' . t('InviteErrorPermission', t('ErrorPermission'))); } // Delete it. $this->SQL->delete($this->Name, array('InvitationID' => $InvitationID)); // Add the invitation back onto the user's account if the invitation has not been accepted. if (!$Invitation->AcceptedUserID) { Gdn::userModel()->IncreaseInviteCount($UserID); } return true; }
/** * Edit a discussion (wrapper for PostController::Discussion). * * Will throw an error if both params are blank. * * @since 2.0.0 * @access public * * @param int $DiscussionID Unique ID of the discussion to edit. * @param int $DraftID Unique ID of draft discussion to edit. */ public function editDiscussion($DiscussionID = '', $DraftID = '') { if ($DraftID != '') { $this->Draft = $this->DraftModel->getID($DraftID); $this->CategoryID = $this->Draft->CategoryID; // Verify this is their draft if (val('InsertUserID', $this->Draft) != Gdn::session()->UserID) { throw permissionException(); } } else { $this->setData('Discussion', $this->DiscussionModel->getID($DiscussionID), true); $this->CategoryID = $this->Discussion->CategoryID; } if (c('Garden.ForceInputFormatter')) { $this->Form->removeFormValue('Format'); } $this->setData('_CancelUrl', discussionUrl($this->data('Discussion'))); // Set view and render $this->View = 'Discussion'; $this->discussion($this->CategoryID); }
public function notSpam($LogIDs) { $this->permission(array('Garden.Moderation.Manage', 'Moderation.Spam.Manage'), false); if (!$this->Request->isPostBack()) { throw permissionException('Javascript'); } $Logs = array(); // Verify the appropriate users. $UserIDs = $this->Form->getFormValue('UserID', array()); if (!is_array($UserIDs)) { $UserIDs = array(); } foreach ($UserIDs as $UserID) { Gdn::userModel()->setField($UserID, 'Verified', true); $Logs = array_merge($Logs, $this->LogModel->getWhere(array('Operation' => 'Spam', 'RecordUserID' => $UserID))); } // Grab the logs. $Logs = array_merge($Logs, $this->LogModel->getIDs($LogIDs)); // try { foreach ($Logs as $Log) { $this->LogModel->restore($Log); } // } catch (Exception $Ex) { // $this->Form->addError($Ex->getMessage()); // } $this->LogModel->recalculate(); $this->setData('Complete'); $this->setData('Count', count($Logs)); $this->render('Blank', 'Utility'); }
/** * Form for adding an email image. * Exposes the Garden.EmailTemplate.Image setting. * Garden.EmailTemplate.Image must be an upload. * * Saves the image based on 2 config settings: * Garden.EmailTemplate.ImageMaxWidth (default 400px) and * Garden.EmailTemplate.ImageMaxHeight (default 300px) * * @throws Gdn_UserException */ public function emailImage() { if (!Gdn::session()->checkPermission('Garden.Community.Manage')) { throw permissionException(); } $this->addJsFile('email.js'); $this->addSideMenu('dashboard/settings/email'); $image = c('Garden.EmailTemplate.Image'); $this->Form = new Gdn_Form(); $validation = new Gdn_Validation(); $configurationModel = new Gdn_ConfigurationModel($validation); // Set the model on the form. $this->Form->setModel($configurationModel); if ($this->Form->authenticatedPostBack() !== false) { try { $upload = new Gdn_UploadImage(); // Validate the upload $tmpImage = $upload->validateUpload('EmailImage', false); if ($tmpImage) { // Generate the target image name $targetImage = $upload->generateTargetName(PATH_UPLOADS); $imageBaseName = pathinfo($targetImage, PATHINFO_BASENAME); // Delete any previously uploaded images. if ($image) { $upload->delete($image); } // Save the uploaded image $parts = $upload->saveImageAs($tmpImage, $imageBaseName, c('Garden.EmailTemplate.ImageMaxWidth', 400), c('Garden.EmailTemplate.ImageMaxHeight', 300)); $imageBaseName = $parts['SaveName']; saveToConfig('Garden.EmailTemplate.Image', $imageBaseName); $this->setData('EmailImage', Gdn_UploadImage::url($imageBaseName)); } else { $this->Form->addError(t('There\'s been an error uploading the image. Your email logo can uploaded in one of the following filetypes: gif, jpg, png')); } } catch (Exception $ex) { $this->Form->addError($ex); } } $this->render(); }
/** * Delete a single draft. * * Redirects user back to Index unless DeliveryType is set. * * @since 2.0.0 * @access public * * @param int $DraftID Unique ID of draft to be deleted. * @param string $TransientKey Single-use hash to prove intent. */ public function delete($DraftID = '', $TransientKey = '') { $Form = Gdn::factory('Form'); $Session = Gdn::session(); if (is_numeric($DraftID) && $DraftID > 0) { $Draft = $this->DraftModel->getID($DraftID); } if ($Draft) { if ($Session->validateTransientKey($TransientKey) && (val('InsertUserID', $Draft) == $Session->UserID || checkPermission('Garden.Community.Manage'))) { // Delete the draft if (!$this->DraftModel->deleteID($DraftID)) { $Form->addError('Failed to delete draft'); } } else { throw permissionException('Garden.Community.Manage'); } } else { throw notFoundException('Draft'); } // Redirect if ($this->_DeliveryType === DELIVERY_TYPE_ALL) { $Target = GetIncomingValue('Target', '/drafts'); redirect($Target); } // Return any errors if ($Form->errorCount() > 0) { $this->setJson('ErrorMessage', $Form->errors()); } // Render default view $this->render(); }