about summary refs log tree commit diff
path: root/lib
diff options
context:
space:
mode:
authorThibaut Girka <thib@sitedethib.com>2019-04-08 15:57:56 +0200
committerThibaut Girka <thib@sitedethib.com>2019-04-08 15:57:56 +0200
commitf5f6d23d554b3a81020feebc65188cc64f644095 (patch)
treeb30197858c2018a32be559f5b4b479571c75dee3 /lib
parent30500dff7cbf27fbee6eb45e20cc24ca0b7a9e77 (diff)
parent3f036ac6b8f9919b3b141012db163476f18fe299 (diff)
Merge branch 'master' into glitch-soc/merge-upstream
Conflicts:
- config/locales/pl.yml
  Conflict caused by new upstream string too close to glitch-specific
  “flavour” string. Took both strings.
Diffstat (limited to 'lib')
-rw-r--r--lib/mastodon/accounts_cli.rb111
-rw-r--r--lib/mastodon/emoji_cli.rb6
-rw-r--r--lib/mastodon/statuses_cli.rb10
3 files changed, 125 insertions, 2 deletions
diff --git a/lib/mastodon/accounts_cli.rb b/lib/mastodon/accounts_cli.rb
index f02b2149b..9dc84f1b5 100644
--- a/lib/mastodon/accounts_cli.rb
+++ b/lib/mastodon/accounts_cli.rb
@@ -219,12 +219,14 @@ module Mastodon
     def cull
       skip_threshold = 7.days.ago
       culled         = 0
+      dry_run_culled = []
       skip_domains   = Set.new
       dry_run        = options[:dry_run] ? ' (DRY RUN)' : ''
 
       Account.remote.where(protocol: :activitypub).partitioned.find_each do |account|
         next if account.updated_at >= skip_threshold || (account.last_webfingered_at.present? && account.last_webfingered_at >= skip_threshold)
 
+        code = 0
         unless skip_domains.include?(account.domain)
           begin
             code = Request.new(:head, account.uri).perform(&:code)
@@ -236,7 +238,11 @@ module Mastodon
         end
 
         if [404, 410].include?(code)
-          SuspendAccountService.new.call(account, destroy: true) unless options[:dry_run]
+          if options[:dry_run]
+            dry_run_culled << account.acct
+          else
+            SuspendAccountService.new.call(account, destroy: true)
+          end
           culled += 1
           say('+', :green, false)
         else
@@ -252,6 +258,11 @@ module Mastodon
         say('The following servers were not available during the check:', :yellow)
         skip_domains.each { |domain| say('    ' + domain) }
       end
+
+      unless dry_run_culled.empty?
+        say('The following accounts would have been deleted:', :green)
+        dry_run_culled.each { |account| say('    ' + account) }
+      end
     end
 
     option :all, type: :boolean
@@ -356,6 +367,104 @@ module Mastodon
       say("OK, unfollowed target from #{processed} accounts, skipped #{failed}", :green)
     end
 
+    option :follows, type: :boolean, default: false
+    option :followers, type: :boolean, default: false
+    desc 'reset-relationships USERNAME', 'Reset all follows and/or followers for a user'
+    long_desc <<-LONG_DESC
+      Reset all follows and/or followers for a user specified by USERNAME.
+
+      With the --follows option, the command unfollows everyone that the account follows,
+      and then re-follows the users that would be followed by a brand new account.
+
+      With the --followers option, the command removes all followers of the account.
+    LONG_DESC
+    def reset_relationships(username)
+      unless options[:follows] || options[:followers]
+        say('Please specify either --follows or --followers, or both', :red)
+        exit(1)
+      end
+
+      account = Account.find_local(username)
+
+      if account.nil?
+        say('No user with such username', :red)
+        exit(1)
+      end
+
+      if options[:follows]
+        processed = 0
+        failed    = 0
+
+        say("Unfollowing #{account.username}'s followees, this might take a while...")
+
+        Account.where(id: ::Follow.where(account: account).select(:target_account_id)).find_each do |target_account|
+          begin
+            UnfollowService.new.call(account, target_account)
+            processed += 1
+            say('.', :green, false)
+          rescue StandardError
+            failed += 1
+            say('.', :red, false)
+          end
+        end
+
+        BootstrapTimelineWorker.perform_async(account.id)
+
+        say("OK, unfollowed #{processed} followees, skipped #{failed}", :green)
+      end
+
+      if options[:followers]
+        processed = 0
+        failed    = 0
+
+        say("Removing #{account.username}'s followers, this might take a while...")
+
+        Account.where(id: ::Follow.where(target_account: account).select(:account_id)).find_each do |target_account|
+          begin
+            UnfollowService.new.call(target_account, account)
+            processed += 1
+            say('.', :green, false)
+          rescue StandardError
+            failed += 1
+            say('.', :red, false)
+          end
+        end
+
+        say("OK, removed #{processed} followers, skipped #{failed}", :green)
+      end
+    end
+
+    option :number, type: :numeric, aliases: [:n]
+    option :all, type: :boolean
+    desc 'approve [USERNAME]', 'Approve pending accounts'
+    long_desc <<~LONG_DESC
+      When registrations require review from staff, approve pending accounts,
+      either all of them with the --all option, or a specific number of them
+      specified with the --number (-n) option, or only a single specific
+      account identified by its username.
+    LONG_DESC
+    def approve(username = nil)
+      if options[:all]
+        User.pending.find_each(&:approve!)
+        say('OK', :green)
+      elsif options[:number]
+        User.pending.limit(options[:number]).each(&:approve!)
+        say('OK', :green)
+      elsif username.present?
+        account = Account.find_local(username)
+
+        if account.nil?
+          say('No such account', :red)
+          exit(1)
+        end
+
+        account.user&.approve!
+        say('OK', :green)
+      else
+        exit(1)
+      end
+    end
+
     private
 
     def rotate_keys_for_account(account, delay = 0)
diff --git a/lib/mastodon/emoji_cli.rb b/lib/mastodon/emoji_cli.rb
index 2262040d4..32827dd45 100644
--- a/lib/mastodon/emoji_cli.rb
+++ b/lib/mastodon/emoji_cli.rb
@@ -66,6 +66,12 @@ module Mastodon
       say("Imported #{imported}, skipped #{skipped}, failed to import #{failed}", color(imported, skipped, failed))
     end
 
+    desc 'purge', 'Remove all custom emoji'
+    def purge
+      CustomEmoji.in_batches.destroy_all
+      say('OK', :green)
+    end
+
     private
 
     def color(green, _yellow, red)
diff --git a/lib/mastodon/statuses_cli.rb b/lib/mastodon/statuses_cli.rb
index 5881ba260..7f2fbfa85 100644
--- a/lib/mastodon/statuses_cli.rb
+++ b/lib/mastodon/statuses_cli.rb
@@ -13,7 +13,15 @@ module Mastodon
     end
 
     option :days, type: :numeric, default: 90
-    desc 'remove', 'Remove statuses'
+    desc 'remove', 'Remove unreferenced statuses'
+    long_desc <<~LONG_DESC
+      Remove statuses that are not referenced by local user activity, such as
+      ones that came from relays, or belonging to users that were once followed
+      by someone locally but no longer are.
+
+      This is a computationally heavy procedure that creates extra database
+      indicides before commencing, and removes them afterward.
+    LONG_DESC
     def remove
       say('Creating temporary database indices...')