mirror of
https://github.com/discourse/discourse.git
synced 2024-11-26 02:40:53 -06:00
FEATURE: Create a rake task for destroying categories
Created a rake task for destroying multiple categories along with any subcategories and topics the belong to those categories. Also created a rake task for listing all of your categories. Refactored existing destroy rake tasks to use new logging method, that allows for puts output in the console but prevents it from showing in the specs.
This commit is contained in:
parent
98866ca043
commit
092eeb5ca3
@ -1,83 +1,110 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
## Because these methods are meant to be called from a rake task
|
||||
# we are capturing all log output into a log array to return
|
||||
# to the rake task rather than using `puts` statements.
|
||||
class DestroyTask
|
||||
def self.destroy_topics(category, parent_category = nil)
|
||||
|
||||
def initialize(io = $stdout)
|
||||
@io = io
|
||||
end
|
||||
|
||||
def destroy_topics(category, parent_category = nil, delete_system_topics = false)
|
||||
c = Category.find_by_slug(category, parent_category)
|
||||
log = []
|
||||
descriptive_slug = parent_category ? "#{parent_category}/#{category}" : category
|
||||
return "A category with the slug: #{descriptive_slug} could not be found" if c.nil?
|
||||
topics = Topic.where(category_id: c.id, pinned_at: nil).where.not(user_id: -1)
|
||||
log << "There are #{topics.count} topics to delete in #{descriptive_slug} category"
|
||||
return @io.puts "A category with the slug: #{descriptive_slug} could not be found" if c.nil?
|
||||
if delete_system_topics
|
||||
topics = Topic.where(category_id: c.id, pinned_at: nil)
|
||||
else
|
||||
topics = Topic.where(category_id: c.id, pinned_at: nil).where.not(user_id: -1)
|
||||
end
|
||||
@io.puts "There are #{topics.count} topics to delete in #{descriptive_slug} category"
|
||||
topics.each do |topic|
|
||||
log << "Deleting #{topic.slug}..."
|
||||
@io.puts "Deleting #{topic.slug}..."
|
||||
first_post = topic.ordered_posts.first
|
||||
if first_post.nil?
|
||||
return log << "Topic.ordered_posts.first was nil"
|
||||
return @io.puts "Topic.ordered_posts.first was nil"
|
||||
end
|
||||
system_user = User.find(-1)
|
||||
log << PostDestroyer.new(system_user, first_post).destroy
|
||||
@io.puts PostDestroyer.new(system_user, first_post).destroy
|
||||
end
|
||||
log
|
||||
end
|
||||
|
||||
def self.destroy_topics_all_categories
|
||||
def destroy_topics_in_category(category_id, delete_system_topics = false)
|
||||
c = Category.find(category_id)
|
||||
return @io.puts "A category with the id: #{category_id} could not be found" if c.nil?
|
||||
if delete_system_topics
|
||||
topics = Topic.where(category_id: c.id, pinned_at: nil)
|
||||
else
|
||||
topics = Topic.where(category_id: c.id, pinned_at: nil).where.not(user_id: -1)
|
||||
end
|
||||
@io.puts "There are #{topics.count} topics to delete in #{c.slug} category"
|
||||
topics.each do |topic|
|
||||
first_post = topic.ordered_posts.first
|
||||
return @io.puts "Topic.ordered_posts.first was nil for topic: #{topic.id}" if first_post.nil?
|
||||
system_user = User.find(-1)
|
||||
PostDestroyer.new(system_user, first_post).destroy
|
||||
end
|
||||
topics = Topic.where(category_id: c.id, pinned_at: nil)
|
||||
@io.puts "There are #{topics.count} topics that could not be deleted in #{c.slug} category"
|
||||
end
|
||||
|
||||
def destroy_topics_all_categories
|
||||
categories = Category.all
|
||||
log = []
|
||||
categories.each do |c|
|
||||
log << destroy_topics(c.slug, c.parent_category&.slug)
|
||||
@io.puts destroy_topics(c.slug, c.parent_category&.slug)
|
||||
end
|
||||
log
|
||||
end
|
||||
|
||||
def self.destroy_private_messages
|
||||
def destroy_private_messages
|
||||
pms = Topic.where(archetype: "private_message")
|
||||
current_user = User.find(-1) #system
|
||||
log = []
|
||||
pms.each do |pm|
|
||||
log << "Destroying #{pm.slug} pm"
|
||||
@io.puts "Destroying #{pm.slug} pm"
|
||||
first_post = pm.ordered_posts.first
|
||||
log << PostDestroyer.new(current_user, first_post).destroy
|
||||
@io.puts PostDestroyer.new(current_user, first_post).destroy
|
||||
end
|
||||
log
|
||||
end
|
||||
|
||||
def self.destroy_groups
|
||||
def destroy_category(category_id, destroy_system_topics = false)
|
||||
c = Category.find_by_id(category_id)
|
||||
return @io.puts "A category with the id: #{category_id} could not be found" if c.nil?
|
||||
subcategories = Category.where(parent_category_id: c.id).pluck(:id)
|
||||
@io.puts "There are #{subcategories.count} subcategories to delete" if subcategories
|
||||
subcategories.each do |subcategory_id|
|
||||
s = Category.find_by_id(subcategory_id)
|
||||
category_topic_destroyer(s, destroy_system_topics)
|
||||
end
|
||||
category_topic_destroyer(c, destroy_system_topics)
|
||||
end
|
||||
|
||||
def destroy_groups
|
||||
groups = Group.where(automatic: false)
|
||||
log = []
|
||||
groups.each do |group|
|
||||
log << "destroying group: #{group.id}"
|
||||
log << group.destroy
|
||||
@io.puts "destroying group: #{group.id}"
|
||||
@io.puts group.destroy
|
||||
end
|
||||
log
|
||||
end
|
||||
|
||||
def self.destroy_users
|
||||
log = []
|
||||
def destroy_users
|
||||
users = User.where(admin: false, id: 1..Float::INFINITY)
|
||||
log << "There are #{users.count} users to delete"
|
||||
@io.puts "There are #{users.count} users to delete"
|
||||
options = {}
|
||||
options[:delete_posts] = true
|
||||
current_user = User.find(-1) #system
|
||||
users.each do |user|
|
||||
begin
|
||||
if UserDestroyer.new(current_user).destroy(user, options)
|
||||
log << "#{user.username} deleted"
|
||||
@io.puts "#{user.username} deleted"
|
||||
else
|
||||
log << "#{user.username} not deleted"
|
||||
@io.puts "#{user.username} not deleted"
|
||||
end
|
||||
rescue UserDestroyer::PostsExistError
|
||||
raise Discourse::InvalidAccess.new("User #{user.username} has #{user.post_count} posts, so can't be deleted.")
|
||||
rescue NoMethodError
|
||||
log << "#{user.username} could not be deleted"
|
||||
@io.puts "#{user.username} could not be deleted"
|
||||
end
|
||||
end
|
||||
log
|
||||
end
|
||||
|
||||
def self.destroy_stats
|
||||
def destroy_stats
|
||||
ApplicationRequest.destroy_all
|
||||
IncomingLink.destroy_all
|
||||
UserVisit.destroy_all
|
||||
@ -90,4 +117,13 @@ class DestroyTask
|
||||
PostAction.unscoped.destroy_all
|
||||
EmailLog.destroy_all
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def category_topic_destroyer(category, destroy_system_topics = false)
|
||||
destroy_topics_log = destroy_topics_in_category(category.id, destroy_system_topics)
|
||||
@io.puts "Destroying #{category.slug} category"
|
||||
category.destroy
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -36,3 +36,11 @@ end
|
||||
def print_status(current, max)
|
||||
print "\r%9d / %d (%5.1f%%)" % [current, max, ((current.to_f / max.to_f) * 100).round(1)]
|
||||
end
|
||||
|
||||
desc "Output a list of categories"
|
||||
task "categories:list" => :environment do
|
||||
categories = Category.pluck(:id, :slug, :parent_category_id)
|
||||
categories.each do |c|
|
||||
puts "id: #{c[0]}, slug: #{c[1]}, parent: #{c[2]}"
|
||||
end
|
||||
end
|
||||
|
@ -1,43 +1,60 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
## These tasks are destructive and are for clearing out all the
|
||||
# content and users from your site, but keeping your site settings,
|
||||
# theme, and category structure.
|
||||
# content and users from your site.
|
||||
desc "Remove all topics in a category"
|
||||
task "destroy:topics", [:category, :parent_category] => :environment do |t, args|
|
||||
destroy_task = DestroyTask.new
|
||||
category = args[:category]
|
||||
parent_category = args[:parent_category]
|
||||
descriptive_slug = parent_category ? "#{parent_category}/#{category}" : category
|
||||
puts "Going to delete all topics in the #{descriptive_slug} category"
|
||||
puts log = DestroyTask.destroy_topics(category, parent_category)
|
||||
destroy_task.destroy_topics(category, parent_category)
|
||||
end
|
||||
|
||||
desc "Remove all topics in all categories"
|
||||
task "destroy:topics_all_categories" => :environment do
|
||||
destroy_task = DestroyTask.new
|
||||
puts "Going to delete all topics in all categories..."
|
||||
puts log = DestroyTask.destroy_topics_all_categories
|
||||
puts log = destroy_task.destroy_topics_all_categories
|
||||
end
|
||||
|
||||
desc "Remove all private messages"
|
||||
task "destroy:private_messages" => :environment do
|
||||
destroy_task = DestroyTask.new
|
||||
puts "Going to delete all private messages..."
|
||||
puts log = DestroyTask.destroy_private_messages
|
||||
puts log = destroy_task.destroy_private_messages
|
||||
end
|
||||
|
||||
desc "Destroy all groups"
|
||||
task "destroy:groups" => :environment do
|
||||
destroy_task = DestroyTask.new
|
||||
puts "Going to delete all non-default groups..."
|
||||
puts log = DestroyTask.destroy_groups
|
||||
puts log = destroy_task.destroy_groups
|
||||
end
|
||||
|
||||
desc "Destroy all non-admin users"
|
||||
task "destroy:users" => :environment do
|
||||
destroy_task = DestroyTask.new
|
||||
puts "Going to delete all non-admin users..."
|
||||
puts log = DestroyTask.destroy_users
|
||||
puts log = destroy_task.destroy_users
|
||||
end
|
||||
|
||||
desc "Destroy site stats"
|
||||
task "destroy:stats" => :environment do
|
||||
destroy_task = DestroyTask.new
|
||||
puts "Going to delete all site stats..."
|
||||
DestroyTask.destroy_stats
|
||||
destroy_task.destroy_stats
|
||||
end
|
||||
|
||||
# Example: rake destroy:categories[28,29,44,85]
|
||||
# Run rake categories:list for a list of category ids
|
||||
desc "Destroy a comma separated list of category ids."
|
||||
task "destroy:categories" => :environment do |t, args|
|
||||
destroy_task = DestroyTask.new
|
||||
categories = args.extras
|
||||
puts "Going to delete these categories: #{categories}"
|
||||
categories.each do |id|
|
||||
destroy_task.destroy_category(id, true)
|
||||
end
|
||||
end
|
||||
|
@ -11,37 +11,68 @@ describe DestroyTask do
|
||||
fab!(:c2) { Fabricate(:category) }
|
||||
fab!(:t2) { Fabricate(:topic, category: c2) }
|
||||
let!(:p2) { Fabricate(:post, topic: t2) }
|
||||
fab!(:sc) { Fabricate(:category, parent_category: c) }
|
||||
fab!(:sc) { Fabricate(:category, parent_category: c2) }
|
||||
fab!(:t3) { Fabricate(:topic, category: sc) }
|
||||
let!(:p3) { Fabricate(:post, topic: t3) }
|
||||
|
||||
it 'destroys all topics in a category' do
|
||||
expect { DestroyTask.destroy_topics(c.slug) }
|
||||
destroy_task = DestroyTask.new(StringIO.new)
|
||||
expect { destroy_task.destroy_topics(c.slug) }
|
||||
.to change { Topic.where(category_id: c.id).count }.by (-1)
|
||||
end
|
||||
|
||||
it 'destroys all topics in a sub category' do
|
||||
expect { DestroyTask.destroy_topics(sc.slug, c.slug) }
|
||||
destroy_task = DestroyTask.new(StringIO.new)
|
||||
expect { destroy_task.destroy_topics(sc.slug, c2.slug) }
|
||||
.to change { Topic.where(category_id: sc.id).count }.by(-1)
|
||||
end
|
||||
|
||||
it "doesn't destroy system topics" do
|
||||
DestroyTask.destroy_topics(c2.slug)
|
||||
destroy_task = DestroyTask.new(StringIO.new)
|
||||
destroy_task.destroy_topics(c2.slug)
|
||||
expect(Topic.where(category_id: c2.id).count).to eq 1
|
||||
end
|
||||
|
||||
it 'destroys topics in all categories' do
|
||||
DestroyTask.destroy_topics_all_categories
|
||||
destroy_task = DestroyTask.new(StringIO.new)
|
||||
destroy_task.destroy_topics_all_categories
|
||||
expect(Post.where(topic_id: [t.id, t2.id, t3.id]).count).to eq 0
|
||||
end
|
||||
end
|
||||
|
||||
describe 'destroy categories' do
|
||||
fab!(:c) { Fabricate(:category) }
|
||||
fab!(:t) { Fabricate(:topic, category: c) }
|
||||
let!(:p) { Fabricate(:post, topic: t) }
|
||||
fab!(:c2) { Fabricate(:category) }
|
||||
fab!(:t2) { Fabricate(:topic, category: c) }
|
||||
let!(:p2) { Fabricate(:post, topic: t2) }
|
||||
fab!(:sc) { Fabricate(:category, parent_category: c2) }
|
||||
fab!(:t3) { Fabricate(:topic, category: sc) }
|
||||
let!(:p3) { Fabricate(:post, topic: t3) }
|
||||
|
||||
it 'destroys specified category' do
|
||||
destroy_task = DestroyTask.new(StringIO.new)
|
||||
|
||||
expect { destroy_task.destroy_category(c.id) }
|
||||
.to change { Category.where(id: c.id).count }.by (-1)
|
||||
end
|
||||
|
||||
it 'destroys sub-categories when destroying parent category' do
|
||||
destroy_task = DestroyTask.new(StringIO.new)
|
||||
|
||||
expect { destroy_task.destroy_category(c2.id) }
|
||||
.to change { Category.where(id: sc.id).count }.by (-1)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'private messages' do
|
||||
let!(:pm) { Fabricate(:private_message_post) }
|
||||
let!(:pm2) { Fabricate(:private_message_post) }
|
||||
|
||||
it 'destroys all private messages' do
|
||||
DestroyTask.destroy_private_messages
|
||||
destroy_task = DestroyTask.new(StringIO.new)
|
||||
destroy_task.destroy_private_messages
|
||||
expect(Topic.where(archetype: "private_message").count).to eq 0
|
||||
end
|
||||
end
|
||||
@ -51,13 +82,15 @@ describe DestroyTask do
|
||||
let!(:g2) { Fabricate(:group) }
|
||||
|
||||
it 'destroys all groups' do
|
||||
DestroyTask.destroy_groups
|
||||
destroy_task = DestroyTask.new(StringIO.new)
|
||||
destroy_task.destroy_groups
|
||||
expect(Group.where(automatic: false).count).to eq 0
|
||||
end
|
||||
|
||||
it "doesn't destroy default groups" do
|
||||
destroy_task = DestroyTask.new(StringIO.new)
|
||||
before_count = Group.count
|
||||
DestroyTask.destroy_groups
|
||||
destroy_task.destroy_groups
|
||||
expect(Group.count).to eq before_count - 2
|
||||
end
|
||||
end
|
||||
@ -70,7 +103,8 @@ describe DestroyTask do
|
||||
Fabricate(:user)
|
||||
Fabricate(:admin)
|
||||
|
||||
DestroyTask.destroy_users
|
||||
destroy_task = DestroyTask.new(StringIO.new)
|
||||
destroy_task.destroy_users
|
||||
expect(User.where(admin: false).count).to eq 0
|
||||
# admin does not get detroyed
|
||||
expect(User.count).to eq before_count + 1
|
||||
@ -79,7 +113,8 @@ describe DestroyTask do
|
||||
|
||||
describe 'stats' do
|
||||
it 'destroys all site stats' do
|
||||
DestroyTask.destroy_stats
|
||||
destroy_task = DestroyTask.new(StringIO.new)
|
||||
destroy_task.destroy_stats
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user