Merge branch 'main' into glitch-soc/merge-upstream

Conflicts:
- `app/lib/activitypub/activity/create.rb`:
  Upstream refactored how `Create` activities are handled and how values are
  extracted from `Create`d objects. This conflicted with how glitch-soc
  supported the `directMessage` flag to explicitly distinguish between
  limited and direct messages.
  Ported glitch-soc's changes to latest upstream changes.
- `app/services/fan_out_on_write_service.rb`:
  Upstream largely refactored that file and changed some of the logic.
  This conflicted with glitch-soc's handling of the direct timeline and
  the options to allow replies and boosts in public feeds.
  Ported those glitch-soc changes on top of latest upstream changes.
- `app/services/process_mentions_service.rb`:
  Upstream refactored to move mention-related ActivityPub deliveries to
  `ActivityPub::DeliveryWorker`, while glitch-soc contained an extra check
  to not send local-only toots to remote mentioned users.
  Took upstream's version, as the check is not needed anymore, since it is
  performed at the `ActivityPub::DeliveryWorker` call site already.
- `app/workers/feed_insert_worker.rb`:
  Upstream added support for `update` toot events, while glitch-soc had
  support for an extra timeline support, `direct`.
  Ported upstream changes and extended them to the `direct` timeline.

Additional changes:
- `app/lib/activitypub/parser/status_parser.rb`:
  Added code to handle the `directMessage` flag and take it into account
  to compute visibility.
- `app/lib/feed_manager.rb`:
  Extended upstream's support of `update` toot events to glitch-soc's
  `direct` timeline.
This commit is contained in:
Claire
2022-01-19 23:19:00 +01:00
56 changed files with 1434 additions and 594 deletions

View File

@@ -67,7 +67,7 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
expect(status).to_not be_nil
expect(status.url).to eq "https://#{valid_domain}/watch?v=12345"
expect(strip_tags(status.text)).to eq "Nyan Cat 10 hours remix https://#{valid_domain}/watch?v=12345"
expect(strip_tags(status.text)).to eq "Nyan Cat 10 hours remixhttps://#{valid_domain}/watch?v=12345"
end
end
@@ -100,7 +100,7 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
expect(status).to_not be_nil
expect(status.url).to eq "https://#{valid_domain}/watch?v=12345"
expect(strip_tags(status.text)).to eq "Nyan Cat 10 hours remix https://#{valid_domain}/watch?v=12345"
expect(strip_tags(status.text)).to eq "Nyan Cat 10 hours remixhttps://#{valid_domain}/watch?v=12345"
end
end
@@ -120,7 +120,7 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
expect(status).to_not be_nil
expect(status.url).to eq "https://#{valid_domain}/@foo/1234"
expect(strip_tags(status.text)).to eq "Let's change the world https://#{valid_domain}/@foo/1234"
expect(strip_tags(status.text)).to eq "Let's change the worldhttps://#{valid_domain}/@foo/1234"
end
end

View File

@@ -1,37 +1,112 @@
require 'rails_helper'
RSpec.describe FanOutOnWriteService, type: :service do
let(:author) { Fabricate(:account, username: 'tom') }
let(:status) { Fabricate(:status, text: 'Hello @alice #test', account: author) }
let(:alice) { Fabricate(:user, account: Fabricate(:account, username: 'alice')).account }
let(:follower) { Fabricate(:account, username: 'bob') }
let(:last_active_at) { Time.now.utc }
subject { FanOutOnWriteService.new }
let!(:alice) { Fabricate(:user, current_sign_in_at: last_active_at, account: Fabricate(:account, username: 'alice')).account }
let!(:bob) { Fabricate(:user, current_sign_in_at: last_active_at, account: Fabricate(:account, username: 'bob')).account }
let!(:tom) { Fabricate(:user, current_sign_in_at: last_active_at, account: Fabricate(:account, username: 'tom')).account }
subject { described_class.new }
let(:status) { Fabricate(:status, account: alice, visibility: visibility, text: 'Hello @bob #hoge') }
before do
alice
follower.follow!(author)
bob.follow!(alice)
tom.follow!(alice)
ProcessMentionsService.new.call(status)
ProcessHashtagsService.new.call(status)
allow(Redis.current).to receive(:publish)
subject.call(status)
end
it 'delivers status to home timeline' do
expect(HomeFeed.new(author).get(10).map(&:id)).to include status.id
def home_feed_of(account)
HomeFeed.new(account).get(10).map(&:id)
end
it 'delivers status to local followers' do
pending 'some sort of problem in test environment causes this to sometimes fail'
expect(HomeFeed.new(follower).get(10).map(&:id)).to include status.id
context 'when status is public' do
let(:visibility) { 'public' }
it 'is added to the home feed of its author' do
expect(home_feed_of(alice)).to include status.id
end
it 'is added to the home feed of a follower' do
expect(home_feed_of(bob)).to include status.id
expect(home_feed_of(tom)).to include status.id
end
it 'is broadcast to the hashtag stream' do
expect(Redis.current).to have_received(:publish).with('timeline:hashtag:hoge', anything)
expect(Redis.current).to have_received(:publish).with('timeline:hashtag:hoge:local', anything)
end
it 'is broadcast to the public stream' do
expect(Redis.current).to have_received(:publish).with('timeline:public', anything)
expect(Redis.current).to have_received(:publish).with('timeline:public:local', anything)
end
end
it 'delivers status to hashtag' do
expect(TagFeed.new(Tag.find_by(name: 'test'), alice).get(20).map(&:id)).to include status.id
context 'when status is limited' do
let(:visibility) { 'limited' }
it 'is added to the home feed of its author' do
expect(home_feed_of(alice)).to include status.id
end
it 'is added to the home feed of the mentioned follower' do
expect(home_feed_of(bob)).to include status.id
end
it 'is not added to the home feed of the other follower' do
expect(home_feed_of(tom)).to_not include status.id
end
it 'is not broadcast publicly' do
expect(Redis.current).to_not have_received(:publish).with('timeline:hashtag:hoge', anything)
expect(Redis.current).to_not have_received(:publish).with('timeline:public', anything)
end
end
it 'delivers status to public timeline' do
expect(PublicFeed.new(alice).get(20).map(&:id)).to include status.id
context 'when status is private' do
let(:visibility) { 'private' }
it 'is added to the home feed of its author' do
expect(home_feed_of(alice)).to include status.id
end
it 'is added to the home feed of a follower' do
expect(home_feed_of(bob)).to include status.id
expect(home_feed_of(tom)).to include status.id
end
it 'is not broadcast publicly' do
expect(Redis.current).to_not have_received(:publish).with('timeline:hashtag:hoge', anything)
expect(Redis.current).to_not have_received(:publish).with('timeline:public', anything)
end
end
context 'when status is direct' do
let(:visibility) { 'direct' }
it 'is added to the home feed of its author' do
expect(home_feed_of(alice)).to include status.id
end
it 'is added to the home feed of the mentioned follower' do
expect(home_feed_of(bob)).to include status.id
end
it 'is not added to the home feed of the other follower' do
expect(home_feed_of(tom)).to_not include status.id
end
it 'is not broadcast publicly' do
expect(Redis.current).to_not have_received(:publish).with('timeline:hashtag:hoge', anything)
expect(Redis.current).to_not have_received(:publish).with('timeline:public', anything)
end
end
end

View File

@@ -9,75 +9,55 @@ RSpec.describe ProcessMentionsService, type: :service do
context 'ActivityPub' do
context do
let(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') }
let!(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') }
before do
stub_request(:post, remote_user.inbox_url)
subject.call(status)
end
it 'creates a mention' do
expect(remote_user.mentions.where(status: status).count).to eq 1
end
it 'sends activity to the inbox' do
expect(a_request(:post, remote_user.inbox_url)).to have_been_made.once
end
end
context 'with an IDN domain' do
let(:remote_user) { Fabricate(:account, username: 'sneak', protocol: :activitypub, domain: 'xn--hresiar-mxa.ch', inbox_url: 'http://example.com/inbox') }
let(:status) { Fabricate(:status, account: account, text: "Hello @sneak@hæresiar.ch") }
let!(:remote_user) { Fabricate(:account, username: 'sneak', protocol: :activitypub, domain: 'xn--hresiar-mxa.ch', inbox_url: 'http://example.com/inbox') }
let!(:status) { Fabricate(:status, account: account, text: "Hello @sneak@hæresiar.ch") }
before do
stub_request(:post, remote_user.inbox_url)
subject.call(status)
end
it 'creates a mention' do
expect(remote_user.mentions.where(status: status).count).to eq 1
end
it 'sends activity to the inbox' do
expect(a_request(:post, remote_user.inbox_url)).to have_been_made.once
end
end
context 'with an IDN TLD' do
let(:remote_user) { Fabricate(:account, username: 'foo', protocol: :activitypub, domain: 'xn--y9a3aq.xn--y9a3aq', inbox_url: 'http://example.com/inbox') }
let(:status) { Fabricate(:status, account: account, text: "Hello @foo@հայ.հայ") }
let!(:remote_user) { Fabricate(:account, username: 'foo', protocol: :activitypub, domain: 'xn--y9a3aq.xn--y9a3aq', inbox_url: 'http://example.com/inbox') }
let!(:status) { Fabricate(:status, account: account, text: "Hello @foo@հայ.հայ") }
before do
stub_request(:post, remote_user.inbox_url)
subject.call(status)
end
it 'creates a mention' do
expect(remote_user.mentions.where(status: status).count).to eq 1
end
it 'sends activity to the inbox' do
expect(a_request(:post, remote_user.inbox_url)).to have_been_made.once
end
end
end
context 'Temporarily-unreachable ActivityPub user' do
let(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox', last_webfingered_at: nil) }
let!(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox', last_webfingered_at: nil) }
before do
stub_request(:get, "https://example.com/.well-known/host-meta").to_return(status: 404)
stub_request(:get, "https://example.com/.well-known/webfinger?resource=acct:remote_user@example.com").to_return(status: 500)
stub_request(:post, remote_user.inbox_url)
subject.call(status)
end
it 'creates a mention' do
expect(remote_user.mentions.where(status: status).count).to eq 1
end
it 'sends activity to the inbox' do
expect(a_request(:post, remote_user.inbox_url)).to have_been_made.once
end
end
end