Skip to content
This repository was archived by the owner on Jan 27, 2020. It is now read-only.

Commit 9d1d393

Browse files
Gargronnoellabo
authored andcommitted
Add handler for Move activity (mastodon#9629)
1 parent 17bd27a commit 9d1d393

11 files changed

Lines changed: 134 additions & 1 deletion

File tree

app/lib/activitypub/activity.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ def klass
5050
ActivityPub::Activity::Add
5151
when 'Remove'
5252
ActivityPub::Activity::Remove
53+
when 'Move'
54+
ActivityPub::Activity::Move
5355
end
5456
end
5557
end
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# frozen_string_literal: true
2+
3+
class ActivityPub::Activity::Move < ActivityPub::Activity
4+
PROCESSING_COOLDOWN = 7.days.seconds
5+
6+
def perform
7+
return if origin_account.uri != object_uri || processed?
8+
9+
mark_as_processing!
10+
11+
target_account = ActivityPub::FetchRemoteAccountService.new.call(target_uri)
12+
13+
return if target_account.nil? || !target_account.also_known_as.include?(origin_account.uri)
14+
15+
# In case for some reason we didn't have a redirect for the profile already, set it
16+
origin_account.update(moved_to_account: target_account) if origin_account.moved_to_account_id.nil?
17+
18+
# Initiate a re-follow for each follower
19+
origin_account.followers.local.select(:id).find_in_batches do |follower_accounts|
20+
UnfollowFollowWorker.push_bulk(follower_accounts.map(&:id)) do |follower_account_id|
21+
[follower_account_id, origin_account.id, target_account.id]
22+
end
23+
end
24+
end
25+
26+
private
27+
28+
def origin_account
29+
@account
30+
end
31+
32+
def target_uri
33+
value_or_id(@json['target'])
34+
end
35+
36+
def processed?
37+
redis.exists("move_in_progress:#{@account.id}")
38+
end
39+
40+
def mark_as_processing!
41+
redis.setex("move_in_progress:#{@account.id}", PROCESSING_COOLDOWN, true)
42+
end
43+
end

app/lib/activitypub/adapter.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class ActivityPub::Adapter < ActiveModelSerializers::Adapter::Base
1010
'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers',
1111
'sensitive' => 'as:sensitive',
1212
'movedTo' => 'as:movedTo',
13+
'alsoKnownAs' => { '@id' => 'as:alsoKnownAs', '@type' => '@id' },
1314
'Hashtag' => 'as:Hashtag',
1415
'ostatus' => 'http://ostatus.org#',
1516
'atomUri' => 'ostatus:atomUri',

app/models/account.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
# featured_collection_url :string
4747
# fields :jsonb
4848
# actor_type :string
49+
# also_known_as :string is an Array
4950
#
5051

5152
class Account < ApplicationRecord
@@ -213,6 +214,10 @@ def keypair
213214
@keypair ||= OpenSSL::PKey::RSA.new(private_key || public_key)
214215
end
215216

217+
def also_known_as
218+
self[:also_known_as] || []
219+
end
220+
216221
def fields
217222
(self[:fields] || []).map { |f| Field.new(self, f) }
218223
end

app/serializers/activitypub/actor_serializer.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class ActivityPub::ActorSerializer < ActiveModel::Serializer
1414
has_many :virtual_attachments, key: :attachment
1515

1616
attribute :moved_to, if: :moved?
17+
attribute :also_known_as, if: :also_known_as?
1718

1819
class EndpointsSerializer < ActiveModel::Serializer
1920
include RoutingHelper
@@ -116,6 +117,10 @@ def moved_to
116117
ActivityPub::TagManager.instance.uri_for(object.moved_to_account)
117118
end
118119

120+
def also_known_as?
121+
!object.also_known_as.empty?
122+
end
123+
119124
class CustomEmojiSerializer < ActivityPub::EmojiSerializer
120125
end
121126

app/services/activitypub/process_account_service.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ def set_immediate_attributes!
7373
@account.note = @json['summary'] || ''
7474
@account.locked = @json['manuallyApprovesFollowers'] || false
7575
@account.fields = property_values || {}
76+
@account.also_known_as = as_array(@json['alsoKnownAs'] || []).map { |item| value_or_id(item) }
7677
@account.actor_type = actor_type
7778
end
7879

app/services/follow_service.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def call(source_account, uri, reblogs: nil)
1212
target_account = uri.is_a?(Account) ? uri : ResolveAccountService.new.call(uri)
1313

1414
raise ActiveRecord::RecordNotFound if target_account.nil? || target_account.id == source_account.id || target_account.suspended?
15-
raise Mastodon::NotPermittedError if target_account.blocking?(source_account) || source_account.blocking?(target_account)
15+
raise Mastodon::NotPermittedError if target_account.blocking?(source_account) || source_account.blocking?(target_account) || target_account.moved?
1616

1717
if source_account.following?(target_account)
1818
# We're already following this account, but we'll call follow! again to
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# frozen_string_literal: true
2+
3+
class UnfollowFollowWorker
4+
include Sidekiq::Worker
5+
6+
sidekiq_options queue: 'pull'
7+
8+
def perform(follower_account_id, old_target_account_id, new_target_account_id)
9+
follower_account = Account.find(follower_account_id)
10+
old_target_account = Account.find(old_target_account_id)
11+
new_target_account = Account.find(new_target_account_id)
12+
13+
UnfollowService.new.call(follower_account, old_target_account)
14+
FollowService.new.call(follower_account, new_target_account)
15+
rescue ActiveRecord::RecordNotFound
16+
true
17+
end
18+
end
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class AddAlsoKnownAsToAccounts < ActiveRecord::Migration[5.2]
2+
def change
3+
add_column :accounts, :also_known_as, :string, array: true
4+
end
5+
end

db/schema.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
t.string "featured_collection_url"
7777
t.jsonb "fields"
7878
t.string "actor_type"
79+
t.string "also_known_as", array: true
7980
t.index "(((setweight(to_tsvector('simple'::regconfig, (display_name)::text), 'A'::\"char\") || setweight(to_tsvector('simple'::regconfig, (username)::text), 'B'::\"char\")) || setweight(to_tsvector('simple'::regconfig, (COALESCE(domain, ''::character varying))::text), 'C'::\"char\")))", name: "search_index", using: :gin
8081
t.index "lower((username)::text), lower((domain)::text)", name: "index_accounts_on_username_and_domain_lower"
8182
t.index ["uri"], name: "index_accounts_on_uri"

0 commit comments

Comments
 (0)