about summary refs log tree commit diff
path: root/lib
diff options
context:
space:
mode:
authorStarfall <us@starfall.systems>2020-12-01 10:50:41 -0600
committerStarfall <us@starfall.systems>2020-12-01 10:50:41 -0600
commit63f2eb0c84d0c51f7ece341cc3f35518a3d69520 (patch)
tree57d362f393ff7ae7fdf6b4a00d654f8dbd9c9d7c /lib
parent19548d0a4bc303ca8017599577e21a6d522eb7bd (diff)
parent29812c2e59e02ea5ff8e4818a38b59944e2367ba (diff)
Merge branch 'glitch' into main
Diffstat (limited to 'lib')
-rw-r--r--lib/mastodon/accounts_cli.rb43
-rw-r--r--lib/mastodon/maintenance_cli.rb37
2 files changed, 43 insertions, 37 deletions
diff --git a/lib/mastodon/accounts_cli.rb b/lib/mastodon/accounts_cli.rb
index 7565620cf..bef4093a8 100644
--- a/lib/mastodon/accounts_cli.rb
+++ b/lib/mastodon/accounts_cli.rb
@@ -196,6 +196,46 @@ module Mastodon
       say('OK', :green)
     end
 
+    option :force, type: :boolean, aliases: [:f], description: 'Override public key check'
+    desc 'merge FROM TO', 'Merge two remote accounts into one'
+    long_desc <<-LONG_DESC
+      Merge two remote accounts specified by their username@domain
+      into one, whereby the TO account is the one being merged into
+      and kept, while the FROM one is removed. It is primarily meant
+      to fix duplicates caused by other servers changing their domain.
+
+      The command by default only works if both accounts have the same
+      public key to prevent mistakes. To override this, use the --force.
+    LONG_DESC
+    def merge(from_acct, to_acct)
+      username, domain = from_acct.split('@')
+      from_account = Account.find_remote(username, domain)
+
+      if from_account.nil? || from_account.local?
+        say("No such account (#{from_acct})", :red)
+        exit(1)
+      end
+
+      username, domain = to_acct.split('@')
+      to_account = Account.find_remote(username, domain)
+
+      if to_account.nil? || to_account.local?
+        say("No such account (#{to_acct})", :red)
+        exit(1)
+      end
+
+      if from_account.public_key != to_account.public_key && !options[:force]
+        say("Accounts don't have the same public key, might not be duplicates!", :red)
+        say('Override with --force', :red)
+        exit(1)
+      end
+
+      to_account.merge_with!(from_account)
+      from_account.destroy
+
+      say('OK', :green)
+    end
+
     desc 'backup USERNAME', 'Request a backup for a user'
     long_desc <<-LONG_DESC
       Request a new backup for an account with a given USERNAME.
@@ -335,7 +375,8 @@ module Mastodon
     option :verbose, type: :boolean, aliases: [:v]
     desc 'unfollow ACCT', 'Make all local accounts unfollow account specified by ACCT'
     def unfollow(acct)
-      target_account = Account.find_remote(*acct.split('@'))
+      username, domain = acct.split('@')
+      target_account = Account.find_remote(username, domain)
 
       if target_account.nil?
         say('No such account', :red)
diff --git a/lib/mastodon/maintenance_cli.rb b/lib/mastodon/maintenance_cli.rb
index 191a3b03f..547238ec6 100644
--- a/lib/mastodon/maintenance_cli.rb
+++ b/lib/mastodon/maintenance_cli.rb
@@ -476,48 +476,13 @@ module Mastodon
         if other_account.public_key == reference_account.public_key
           # The accounts definitely point to the same resource, so
           # it's safe to re-attribute content and relationships
-          merge_accounts!(reference_account, other_account)
+          reference_account.merge_with!(other_account)
         end
 
         other_account.destroy
       end
     end
 
-    def merge_accounts!(main_account, duplicate_account)
-      # Since it's the same remote resource, the remote resource likely
-      # already believes we are following/blocking, so it's safe to
-      # re-attribute the relationships too. However, during the presence
-      # of the index bug users could have *also* followed the reference
-      # account already, therefore mass update will not work and we need
-      # to check for (and skip past) uniqueness errors
-      owned_classes = [
-        Status, StatusPin, MediaAttachment, Poll, Report, Tombstone, Favourite,
-        Follow, FollowRequest, Block, Mute, AccountIdentityProof,
-        AccountModerationNote, AccountPin, AccountStat, ListAccount,
-        PollVote, Mention
-      ]
-      owned_classes.each do |klass|
-        klass.where(account_id: duplicate_account.id).find_each do |record|
-          begin
-            record.update_attribute(:account_id, main_account.id)
-          rescue ActiveRecord::RecordNotUnique
-            next
-          end
-        end
-      end
-
-      target_classes = [Follow, FollowRequest, Block, Mute, AccountModerationNote, AccountPin]
-      target_classes.each do |klass|
-        klass.where(target_account_id: duplicate_account.id).find_each do |record|
-          begin
-            record.update_attribute(:target_account_id, main_account.id)
-          rescue ActiveRecord::RecordNotUnique
-            next
-          end
-        end
-      end
-    end
-
     def merge_conversations!(main_conv, duplicate_conv)
       owned_classes = [ConversationMute, AccountConversation]
       owned_classes.each do |klass|