/** * Delete all of the Vanilla related information for a specific user. * @param int $UserID The ID of the user to delete. * @param array $Options An array of options: * - DeleteMethod: One of delete, wipe, or NULL * @since 2.1 */ public function DeleteUserData($UserID, $Options = array(), &$Data = NULL) { $SQL = Gdn::SQL(); // Remove discussion watch records and drafts. $SQL->Delete('UserDiscussion', array('UserID' => $UserID)); Gdn::UserModel()->GetDelete('Draft', array('InsertUserID' => $UserID), $Data); // Comment deletion depends on method selected $DeleteMethod = GetValue('DeleteMethod', $Options, 'delete'); if ($DeleteMethod == 'delete') { // Clear out the last posts to the categories. $SQL->Update('Category c')->Join('Discussion d', 'd.DiscussionID = c.LastDiscussionID')->Where('d.InsertUserID', $UserID)->Set('c.LastDiscussionID', NULL)->Set('c.LastCommentID', NULL)->Put(); $SQL->Update('Category c')->Join('Comment d', 'd.CommentID = c.LastCommentID')->Where('d.InsertUserID', $UserID)->Set('c.LastDiscussionID', NULL)->Set('c.LastCommentID', NULL)->Put(); // Grab all of the discussions that the user has engaged in. $DiscussionIDs = $SQL->Select('DiscussionID')->From('Comment')->Where('InsertUserID', $UserID)->GroupBy('DiscussionID')->Get()->ResultArray(); $DiscussionIDs = ConsolidateArrayValuesByKey($DiscussionIDs, 'DiscussionID'); Gdn::UserModel()->GetDelete('Comment', array('InsertUserID' => $UserID), $Data); // Update the comment counts. $CommentCounts = $SQL->Select('DiscussionID')->Select('CommentID', 'count', 'CountComments')->Select('CommentID', 'max', 'LastCommentID')->WhereIn('DiscussionID', $DiscussionIDs)->GroupBy('DiscussionID')->Get('Comment')->ResultArray(); foreach ($CommentCounts as $Row) { $SQL->Put('Discussion', array('CountComments' => $Row['CountComments'] + 1, 'LastCommentID' => $Row['LastCommentID']), array('DiscussionID' => $Row['DiscussionID'])); } // Update the last user IDs. $SQL->Update('Discussion d')->Join('Comment c', 'd.LastCommentID = c.CommentID', 'left')->Set('d.LastCommentUserID', 'c.InsertUserID', FALSE, FALSE)->Set('d.DateLastComment', 'c.DateInserted', FALSE, FALSE)->WhereIn('d.DiscussionID', $DiscussionIDs)->Put(); // Update the last posts. $Discussions = $SQL->WhereIn('DiscussionID', $DiscussionIDs)->Where('LastCommentUserID', $UserID)->Get('Discussion'); // Delete the user's dicussions Gdn::UserModel()->GetDelete('Discussion', array('InsertUserID' => $UserID), $Data); // Update the appropriat recent posts in the categories. $CategoryModel = new CategoryModel(); $Categories = $CategoryModel->GetWhere(array('LastDiscussionID' => NULL))->ResultArray(); foreach ($Categories as $Category) { $CategoryModel->SetRecentPost($Category['CategoryID']); } } else { if ($DeleteMethod == 'wipe') { // Erase the user's dicussions $SQL->Update('Discussion')->Set('Body', T('The user and all related content has been deleted.'))->Set('Format', 'Deleted')->Where('InsertUserID', $UserID)->Put(); // Erase the user's comments $SQL->From('Comment')->Join('Discussion d', 'c.DiscussionID = d.DiscussionID')->Delete('Comment c', array('d.InsertUserID' => $UserID)); $SQL->Update('Comment')->Set('Body', T('The user and all related content has been deleted.'))->Set('Format', 'Deleted')->Where('InsertUserID', $UserID)->Put(); } else { // Leave comments } } // Remove the user's profile information related to this application $SQL->Update('User')->Set(array('CountDiscussions' => 0, 'CountUnreadDiscussions' => 0, 'CountComments' => 0, 'CountDrafts' => 0, 'CountBookmarks' => 0))->Where('UserID', $UserID)->Put(); }
/** * Delete a comment. * * This is a hard delete that completely removes it from the database. * Events: DeleteComment, BeforeDeleteComment. * * @since 2.0.0 * @access public * * @param int $CommentID Unique ID of the comment to be deleted. * @param array $Options Additional options for the delete. * @param bool Always returns TRUE. */ public function delete($CommentID, $Options = array()) { $this->EventArguments['CommentID'] = $CommentID; $Comment = $this->getID($CommentID, DATASET_TYPE_ARRAY); if (!$Comment) { return false; } $Discussion = $this->SQL->getWhere('Discussion', array('DiscussionID' => $Comment['DiscussionID']))->firstRow(DATASET_TYPE_ARRAY); // Decrement the UserDiscussion comment count if the user has seen this comment $Offset = $this->GetOffset($CommentID); $this->SQL->update('UserDiscussion')->set('CountComments', 'CountComments - 1', false)->where('DiscussionID', $Comment['DiscussionID'])->where('CountComments >', $Offset)->put(); $this->EventArguments['Discussion'] = $Discussion; $this->fireEvent('DeleteComment'); $this->fireEvent('BeforeDeleteComment'); // Log the deletion. $Log = val('Log', $Options, 'Delete'); LogModel::insert($Log, 'Comment', $Comment, val('LogOptions', $Options, array())); // Delete the comment. $this->SQL->delete('Comment', array('CommentID' => $CommentID)); // Update the comment count $this->UpdateCommentCount($Discussion, array('Slave' => false)); // Update the user's comment count $this->UpdateUser($Comment['InsertUserID']); // Update the category. $Category = CategoryModel::categories(val('CategoryID', $Discussion)); if ($Category && $Category['LastCommentID'] == $CommentID) { $CategoryModel = new CategoryModel(); $CategoryModel->SetRecentPost($Category['CategoryID']); } // Clear the page cache. $this->RemovePageCache($Comment['DiscussionID']); return true; }
/** * Updates the CountDiscussions value on the category based on the CategoryID * being saved. * * @since 2.0.0 * @access public * * @param int $CategoryID Unique ID of category we are updating. */ public function updateDiscussionCount($CategoryID, $Discussion = false) { $DiscussionID = val('DiscussionID', $Discussion, false); if (strcasecmp($CategoryID, 'All') == 0) { $Exclude = (bool) Gdn::config('Vanilla.Archive.Exclude'); $ArchiveDate = Gdn::config('Vanilla.Archive.Date'); $Params = array(); $Where = ''; if ($Exclude && $ArchiveDate) { $Where = 'where d.DateLastComment > :ArchiveDate'; $Params[':ArchiveDate'] = $ArchiveDate; } // Update all categories. $Sql = "update :_Category c\n left join (\n select\n d.CategoryID,\n coalesce(count(d.DiscussionID), 0) as CountDiscussions,\n coalesce(sum(d.CountComments), 0) as CountComments\n from :_Discussion d\n {$Where}\n group by d.CategoryID\n ) d\n on c.CategoryID = d.CategoryID\n set\n c.CountDiscussions = coalesce(d.CountDiscussions, 0),\n c.CountComments = coalesce(d.CountComments, 0)"; $Sql = str_replace(':_', $this->Database->DatabasePrefix, $Sql); $this->Database->query($Sql, $Params, 'DiscussionModel_UpdateDiscussionCount'); } elseif (is_numeric($CategoryID)) { $this->SQL->select('d.DiscussionID', 'count', 'CountDiscussions')->select('d.CountComments', 'sum', 'CountComments')->from('Discussion d')->where('d.CategoryID', $CategoryID); $this->AddArchiveWhere(); $Data = $this->SQL->get()->firstRow(); $CountDiscussions = (int) GetValue('CountDiscussions', $Data, 0); $CountComments = (int) GetValue('CountComments', $Data, 0); $CacheAmendment = array('CountDiscussions' => $CountDiscussions, 'CountComments' => $CountComments); if ($DiscussionID) { $CacheAmendment = array_merge($CacheAmendment, array('LastDiscussionID' => $DiscussionID, 'LastCommentID' => null, 'LastDateInserted' => val('DateInserted', $Discussion))); } $CategoryModel = new CategoryModel(); $CategoryModel->setField($CategoryID, $CacheAmendment); $CategoryModel->SetRecentPost($CategoryID); } }
/** * Delete a comment. * * This is a hard delete that completely removes it from the database. * Events: DeleteComment. * * @since 2.0.0 * @access public * * @param int $CommentID Unique ID of the comment to be deleted. * @param array $Options Additional options for the delete. * @param bool Always returns TRUE. */ public function Delete($CommentID, $Options = array()) { $this->EventArguments['CommentID'] = $CommentID; $Comment = $this->GetID($CommentID, DATASET_TYPE_ARRAY); if (!$Comment) { return FALSE; } $Discussion = $this->SQL->GetWhere('Discussion', array('DiscussionID' => $Comment['DiscussionID']))->FirstRow(DATASET_TYPE_ARRAY); // Decrement the UserDiscussion comment count if the user has seen this comment $Offset = $this->GetOffset($CommentID); $this->SQL->Update('UserDiscussion')->Set('CountComments', 'CountComments - 1', FALSE)->Where('DiscussionID', $Comment['DiscussionID'])->Where('CountComments >', $Offset)->Put(); $this->FireEvent('DeleteComment'); // Log the deletion. $Log = GetValue('Log', $Options, 'Delete'); LogModel::Insert($Log, 'Comment', $Comment, GetValue('LogOptions', $Options, array())); // Delete the comment. $this->SQL->Delete('Comment', array('CommentID' => $CommentID)); // Update the comment count $this->UpdateCommentCount($Discussion); // Update the user's comment count $this->UpdateUser($Comment['InsertUserID']); // Update the category. $Category = CategoryModel::Categories(GetValue('CategoryID', $Discussion)); if ($Category && $Category['LastCommentID'] == $CommentID) { $CategoryModel = new CategoryModel(); $CategoryModel->SetRecentPost($Category['CategoryID']); } // Clear the page cache. $this->RemovePageCache($Comment['DiscussionID']); return TRUE; }
/** * Form to ask for the destination of the move, confirmation and permission check. */ public function confirmDiscussionMoves($DiscussionID = null) { $Session = Gdn::session(); $this->Form = new Gdn_Form(); $DiscussionModel = new DiscussionModel(); $CategoryModel = new CategoryModel(); $this->title(t('Confirm')); if ($DiscussionID) { $CheckedDiscussions = (array) $DiscussionID; $ClearSelection = false; } else { $CheckedDiscussions = Gdn::userModel()->getAttribute($Session->User->UserID, 'CheckedDiscussions', array()); if (!is_array($CheckedDiscussions)) { $CheckedDiscussions = array(); } $ClearSelection = true; } $DiscussionIDs = $CheckedDiscussions; $CountCheckedDiscussions = count($DiscussionIDs); $this->setData('CountCheckedDiscussions', $CountCheckedDiscussions); // Check for edit permissions on each discussion $AllowedDiscussions = array(); $DiscussionData = $DiscussionModel->SQL->select('DiscussionID, Name, DateLastComment, CategoryID, CountComments')->from('Discussion')->whereIn('DiscussionID', $DiscussionIDs)->get(); $DiscussionData = Gdn_DataSet::Index($DiscussionData->resultArray(), array('DiscussionID')); foreach ($DiscussionData as $DiscussionID => $Discussion) { $Category = CategoryModel::categories($Discussion['CategoryID']); if ($Category && $Category['PermsDiscussionsEdit']) { $AllowedDiscussions[] = $DiscussionID; } } $this->setData('CountAllowed', count($AllowedDiscussions)); $CountNotAllowed = $CountCheckedDiscussions - count($AllowedDiscussions); $this->setData('CountNotAllowed', $CountNotAllowed); if ($this->Form->authenticatedPostBack()) { // Retrieve the category id $CategoryID = $this->Form->getFormValue('CategoryID'); $Category = CategoryModel::categories($CategoryID); $RedirectLink = $this->Form->getFormValue('RedirectLink'); // User must have add permission on the target category if (!$Category['PermsDiscussionsAdd']) { throw forbiddenException('@' . t('You do not have permission to add discussions to this category.')); } $AffectedCategories = array(); // Iterate and move. foreach ($AllowedDiscussions as $DiscussionID) { $Discussion = val($DiscussionID, $DiscussionData); // Create the shadow redirect. if ($RedirectLink) { $DiscussionModel->defineSchema(); $MaxNameLength = val('Length', $DiscussionModel->Schema->GetField('Name')); $RedirectDiscussion = array('Name' => SliceString(sprintf(t('Moved: %s'), $Discussion['Name']), $MaxNameLength), 'DateInserted' => $Discussion['DateLastComment'], 'Type' => 'redirect', 'CategoryID' => $Discussion['CategoryID'], 'Body' => formatString(t('This discussion has been <a href="{url,html}">moved</a>.'), array('url' => DiscussionUrl($Discussion))), 'Format' => 'Html', 'Closed' => true); // Pass a forced input formatter around this exception. if (c('Garden.ForceInputFormatter')) { $InputFormat = c('Garden.InputFormatter'); saveToConfig('Garden.InputFormatter', 'Html', false); } $RedirectID = $DiscussionModel->save($RedirectDiscussion); // Reset the input formatter if (c('Garden.ForceInputFormatter')) { saveToConfig('Garden.InputFormatter', $InputFormat, false); } if (!$RedirectID) { $this->Form->setValidationResults($DiscussionModel->validationResults()); break; } } $DiscussionModel->setField($DiscussionID, 'CategoryID', $CategoryID); if (!isset($AffectedCategories[$Discussion['CategoryID']])) { $AffectedCategories[$Discussion['CategoryID']] = array(-1, -$Discussion['CountComments']); } else { $AffectedCategories[$Discussion['CategoryID']][0] -= 1; $AffectedCategories[$Discussion['CategoryID']][1] -= $Discussion['CountComments']; } if (!isset($AffectedCategories[$CategoryID])) { $AffectedCategories[$CategoryID] = array(1, $Discussion['CountComments']); } else { $AffectedCategories[$CategoryID][0] += 1; $AffectedCategories[$CategoryID][1] += $Discussion['CountComments']; } } // Update recent posts and counts on all affected categories. foreach ($AffectedCategories as $CategoryID => $Counts) { $CategoryModel->SetRecentPost($CategoryID); $CategoryModel->SQL->update('Category')->set('CountDiscussions', 'CountDiscussions' . ($Counts[0] < 0 ? ' - ' : ' + ') . abs($Counts[0]), false)->set('CountComments', 'CountComments' . ($Counts[1] < 0 ? ' - ' : ' + ') . abs($Counts[1]), false)->where('CategoryID', $CategoryID)->put(); } // Clear selections. if ($ClearSelection) { Gdn::userModel()->saveAttribute($Session->UserID, 'CheckedDiscussions', false); ModerationController::InformCheckedDiscussions($this); } if ($this->Form->errorCount() == 0) { $this->jsonTarget('', '', 'Refresh'); } } $this->render(); }