# frozen_string_literal: true desc "Change topic/post ownership of all the topics/posts by a specific user (without creating new revision)" task "users:change_post_ownership", %i[old_username new_username archetype] => [:environment] do |_, args| old_username = args[:old_username] new_username = args[:new_username] archetype = args[:archetype] archetype = archetype.downcase if archetype if !old_username || !new_username puts "ERROR: Expecting rake users:change_post_ownership[old_username,new_username,archetype]" exit 1 end old_user = find_user(old_username) new_user = find_user(new_username) if archetype == "private" posts = Post.private_posts.where(user_id: old_user.id) elsif archetype == "public" || !archetype posts = Post.public_posts.where(user_id: old_user.id) else puts "ERROR: Expecting rake users:change_post_ownership[old_username,new_username,archetype] where archetype is public or private" exit 1 end puts "Changing post ownership" i = 0 posts.each do |p| PostOwnerChanger.new( post_ids: [p.id], topic_id: p.topic.id, new_owner: User.find_by(username_lower: new_user.username_lower), acting_user: User.find_by(username_lower: "system"), skip_revision: true, ).change_owner! putc "." i += 1 end puts "", "#{i} posts ownership changed!", "" end desc "Merge the source user into the target user" task "users:merge", %i[source_username target_username] => [:environment] do |_, args| source_username = args[:source_username] target_username = args[:target_username] if !source_username || !target_username puts "ERROR: Expecting rake users:merge[source_username,target_username]" exit 1 end source_user = find_user(source_username) target_user = find_user(target_username) UserMerger.new(source_user, target_user).merge! puts "", "Users merged!", "" end desc "Rename a user" task "users:rename", %i[old_username new_username] => [:environment] do |_, args| old_username = args[:old_username] new_username = args[:new_username] if !old_username || !new_username puts "ERROR: Expecting rake users:rename[old_username,new_username]" exit 1 end changer = UsernameChanger.new(find_user(old_username), new_username) changer.change(asynchronous: false) puts "", "User renamed!", "" end desc "Update username in quotes and mentions. Use this if the user was renamed before proper renaming existed." task "users:update_posts", %i[old_username current_username] => [:environment] do |_, args| old_username = args[:old_username] current_username = args[:current_username] if !old_username || !current_username puts "ERROR: Expecting rake users:update_posts[old_username,current_username]" exit 1 end user = find_user(current_username) UsernameChanger.update_username( user_id: user.id, old_username: old_username, new_username: user.username, avatar_template: user.avatar_template, asynchronous: false, ) puts "", "Username updated!", "" end desc "Recalculate post and topic counts in user stats" task "users:recalculate_post_counts" => :environment do puts "", "Updating user stats..." filter_public_posts_and_topics = <<~SQL p.deleted_at IS NULL AND NOT COALESCE(p.hidden, 't') AND p.post_type = 1 AND t.deleted_at IS NULL AND COALESCE(t.visible, 't') AND t.archetype <> 'private_message' AND p.user_id > 0 SQL puts "post counts..." # all public replies DB.exec <<~SQL WITH X AS ( SELECT p.user_id, COUNT(p.id) post_count FROM posts p JOIN topics t ON t.id = p.topic_id WHERE #{filter_public_posts_and_topics} AND p.post_number > 1 GROUP BY p.user_id ) UPDATE user_stats SET post_count = X.post_count FROM X WHERE user_stats.user_id = X.user_id AND user_stats.post_count <> X.post_count SQL puts "topic counts..." # public topics DB.exec <<~SQL WITH X AS ( SELECT p.user_id, COUNT(p.id) topic_count FROM posts p JOIN topics t ON t.id = p.topic_id WHERE #{filter_public_posts_and_topics} AND p.post_number = 1 GROUP BY p.user_id ) UPDATE user_stats SET topic_count = X.topic_count FROM X WHERE user_stats.user_id = X.user_id AND user_stats.topic_count <> X.topic_count SQL puts "Done!", "" end desc "Disable 2FA for user with the given username" task "users:disable_2fa", [:username] => [:environment] do |_, args| username = args[:username] user = find_user(username) UserSecondFactor.where(user_id: user.id, method: UserSecondFactor.methods[:totp]).each(&:destroy!) UserSecurityKey.where( user_id: user.id, factor_type: UserSecurityKey.factor_types[:second_factor], ).destroy_all UserSecondFactor.where(user_id: user.id, method: UserSecondFactor.methods[:backup_codes]).each( &:destroy! ) puts "2FA disabled for #{username}" end desc "Anonymize all users except staff" task "users:anonymize_all" => :environment do require "highline/import" non_staff_users = User.where("NOT admin AND NOT moderator") total = non_staff_users.count anonymized = 0 confirm_anonymize = ask("Are you sure you want to anonymize #{total} users? (Y/n)") exit 1 unless (confirm_anonymize == "" || confirm_anonymize.downcase == "y") system_user = Discourse.system_user non_staff_users.each do |user| begin UserAnonymizer.new(user, system_user).make_anonymous print_status(anonymized += 1, total) rescue StandardError # skip end end puts "", "#{total} users anonymized.", "" end desc "Anonymize user with the given username" task "users:anonymize", [:username] => [:environment] do |_, args| username = args[:username] user = find_user(username) system_user = Discourse.system_user UserAnonymizer.new(user, system_user).make_anonymous puts "User #{username} anonymized" end desc "List all users which have been staff in the last month" task "users:list_recent_staff" => :environment do current_staff_ids = User.human_users.where("admin OR moderator").pluck(:id) recent_actions = UserHistory.where("created_at > ?", 1.month.ago) recent_admin_ids = recent_actions.where(action: UserHistory.actions[:revoke_admin]).pluck(:target_user_id) recent_moderator_ids = recent_actions.where(action: UserHistory.actions[:revoke_moderation]).pluck(:target_user_id) all_ids = current_staff_ids + recent_admin_ids + recent_moderator_ids users = User.where(id: all_ids.uniq) puts "Users which have had staff privileges in the last month:" users.each { |user| puts "#{user.id}: #{user.username} (#{user.email})" } puts "----" puts "user_ids = [#{all_ids.uniq.join(",")}]" end desc "Check if a user exists for given email address" task "users:exists", [:email] => [:environment] do |_, args| email = args[:email] if User.find_by_email(email) puts "User with email #{email} exists" exit 0 end puts "ERROR: User with email #{email} not found" exit 1 end def find_user(username) user = User.find_by_username(username) if !user puts "ERROR: User with username #{username} does not exist" exit 1 end user end