Skip to content

Commit af77e42

Browse files
Gargronhiyuki2578
authored andcommitted
Add handler for Move activity (mastodon#9629)
1 parent 754f61a commit af77e42

12 files changed

Lines changed: 136 additions & 3 deletions

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

app/lib/activitypub/activity/follow.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ def perform
66

77
return if target_account.nil? || !target_account.local? || delete_arrived_first?(@json['id']) || @account.requested?(target_account)
88

9-
if target_account.blocking?(@account) || target_account.domain_blocking?(@account.domain)
9+
if target_account.blocking?(@account) || target_account.domain_blocking?(@account.domain) || target_account.moved?
1010
reject_follow_request!(target_account)
1111
return
1212
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' => { '@id' => 'as:movedTo', '@type' => '@id' },
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
@@ -45,6 +45,7 @@
4545
# actor_type :string
4646
# cat :boolean default(FALSE), not null
4747
# discoverable :boolean
48+
# also_known_as :string is an Array
4849
#
4950

5051
class Account < ApplicationRecord
@@ -228,6 +229,10 @@ def tags_as_strings=(tag_names)
228229
end
229230
end
230231

232+
def also_known_as
233+
self[:also_known_as] || []
234+
end
235+
231236
def fields
232237
(self[:fields] || []).map { |f| Field.new(self, f) }
233238
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
@@ -120,6 +121,10 @@ def moved_to
120121
ActivityPub::TagManager.instance.uri_for(object.moved_to_account)
121122
end
122123

124+
def also_known_as?
125+
!object.also_known_as.empty?
126+
end
127+
123128
class CustomEmojiSerializer < ActivityPub::EmojiSerializer
124129
end
125130

app/services/activitypub/process_account_service.rb

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

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, target_account, reblogs: nil)
1212
target_account = ResolveAccountService.new.call(target_account, skip_webfinger: true)
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

0 commit comments

Comments
 (0)