From a9b22883dc249c5311e2225ebe054925b6558328 Mon Sep 17 00:00:00 2001 From: KMY <tt@kmycode.net> Date: Sun, 24 Sep 2023 21:42:16 +0900 Subject: [PATCH 1/3] #13 Turn searchability private if account is silenced --- app/models/status.rb | 1 + spec/models/status_spec.rb | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/app/models/status.rb b/app/models/status.rb index 9f0299a511..719ba3eeda 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -426,6 +426,7 @@ class Status < ApplicationRecord def compute_searchability local = account.local? + return 'private' if public_searchability? && account.silenced? return 'direct' if unsupported_searchability? return searchability if local && !searchability.nil? return 'direct' if local || [:public, :private, :direct, :limited].exclude?(account.searchability.to_sym) diff --git a/spec/models/status_spec.rb b/spec/models/status_spec.rb index 16210592f4..89f90fc751 100644 --- a/spec/models/status_spec.rb +++ b/spec/models/status_spec.rb @@ -120,7 +120,8 @@ RSpec.describe Status do let(:account_searchability) { :public } let(:status_searchability) { :public } let(:account_domain) { 'example.com' } - let(:account) { Fabricate(:account, domain: account_domain, searchability: account_searchability) } + let(:silenced_at) { nil } + let(:account) { Fabricate(:account, domain: account_domain, searchability: account_searchability, silenced_at: silenced_at) } context 'when public-public' do it 'returns public' do @@ -128,6 +129,14 @@ RSpec.describe Status do end end + context 'when public-public but silenced' do + let(:silenced_at) { Time.now.utc } + + it 'returns private' do + expect(subject.compute_searchability).to eq 'private' + end + end + context 'when public-private' do let(:status_searchability) { :private } From 385ac0c1a2dad447e9f6e225dfa5d87d2170c51c Mon Sep 17 00:00:00 2001 From: KMY <tt@kmycode.net> Date: Mon, 25 Sep 2023 18:32:11 +0900 Subject: [PATCH 2/3] Add posting with limited visibility test --- app/services/post_status_service.rb | 1 + spec/services/post_status_service_spec.rb | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb index a549ab1c78..f48555245e 100644 --- a/app/services/post_status_service.rb +++ b/app/services/post_status_service.rb @@ -94,6 +94,7 @@ class PostStatusService < BaseService end def load_circle + raise ArgumentError if @options[:visibility] == 'limited' && @options[:circle_id].nil? return unless @options[:visibility] == 'circle' || (@options[:visibility] == 'limited' && @options[:circle_id].present?) @circle = @options[:circle_id].present? && Circle.find(@options[:circle_id]) diff --git a/spec/services/post_status_service_spec.rb b/spec/services/post_status_service_spec.rb index 3b953b9fc1..a2cf6fbfb0 100644 --- a/spec/services/post_status_service_spec.rb +++ b/spec/services/post_status_service_spec.rb @@ -206,6 +206,27 @@ RSpec.describe PostStatusService, type: :service do expect(status.mentioned_accounts.first.id).to eq circle_account.id end + it 'circle post with limited visibility' do + account = Fabricate(:account) + circle_account = Fabricate(:account) + circle = Fabricate(:circle, account: account) + text = 'This is an English text.' + + circle_account.follow!(account) + circle.accounts << circle_account + status = subject.call(account, text: text, visibility: 'limited', circle_id: circle.id) + + expect(status.visibility).to eq 'limited' + expect(status.limited_scope).to eq 'circle' + end + + it 'limited visibility and empty circle' do + account = Fabricate(:account) + text = 'This is an English text.' + + expect { subject.call(account, text: text, visibility: 'limited') }.to raise_exception ActiveRecord::RecordInvalid + end + it 'safeguards mentions' do account = Fabricate(:account) mentioned_account = Fabricate(:account, username: 'alice') From 2f21aa5193f21b8f3a62539973b6820323415555 Mon Sep 17 00:00:00 2001 From: KMY <tt@kmycode.net> Date: Mon, 25 Sep 2023 19:39:05 +0900 Subject: [PATCH 3/3] #15 Add misskey fork indexable support --- .../activitypub/process_account_service.rb | 8 ++++- spec/models/status_spec.rb | 8 +++++ .../process_account_service_spec.rb | 35 +++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/app/services/activitypub/process_account_service.rb b/app/services/activitypub/process_account_service.rb index 18277034cf..d2ba697545 100644 --- a/app/services/activitypub/process_account_service.rb +++ b/app/services/activitypub/process_account_service.rb @@ -265,7 +265,7 @@ class ActivityPub::ProcessAccountService < BaseService bio = searchability_from_bio return bio unless bio.nil? - return misskey_software? ? :public : :direct + return misskey_software? ? misskey_searchability_from_indexable : :direct end if audience_searchable_by.any? { |uri| ActivityPub::TagManager.instance.public_collection?(uri) } @@ -297,6 +297,12 @@ class ActivityPub::ProcessAccountService < BaseService searchability end + def misskey_searchability_from_indexable + return :public if @json['indexable'].nil? + + @json['indexable'] ? :public : :limited + end + def instance_info @instance_info ||= InstanceInfo.find_by(domain: @domain) end diff --git a/spec/models/status_spec.rb b/spec/models/status_spec.rb index 89f90fc751..6462307594 100644 --- a/spec/models/status_spec.rb +++ b/spec/models/status_spec.rb @@ -169,6 +169,14 @@ RSpec.describe Status do end end + context 'when limited-public' do + let(:account_searchability) { :limited } + + it 'returns limited' do + expect(subject.compute_searchability).to eq 'limited' + end + end + context 'when private-limited' do let(:account_searchability) { :private } let(:status_searchability) { :limited } diff --git a/spec/services/activitypub/process_account_service_spec.rb b/spec/services/activitypub/process_account_service_spec.rb index 1ea3b6491b..b23aa1cea3 100644 --- a/spec/services/activitypub/process_account_service_spec.rb +++ b/spec/services/activitypub/process_account_service_spec.rb @@ -11,6 +11,7 @@ RSpec.describe ActivityPub::ProcessAccountService, type: :service do let(:software) { 'mastodon' } let(:searchable_by) { 'https://www.w3.org/ns/activitystreams#Public' } let(:sender_bio) { '' } + let(:indexable) { nil } let(:payload) do { id: 'https://foo.test', @@ -18,6 +19,7 @@ RSpec.describe ActivityPub::ProcessAccountService, type: :service do inbox: 'https://foo.test/inbox', followers: 'https://example.com/followers', searchableBy: searchable_by, + indexable: indexable, summary: sender_bio, }.with_indifferent_access end @@ -73,6 +75,39 @@ RSpec.describe ActivityPub::ProcessAccountService, type: :service do it 'searchability is public' do expect(subject.searchability).to eq 'public' end + + context 'with true indexable' do + let(:indexable) { true } + + it 'searchability is public' do + expect(subject.searchability).to eq 'public' + end + end + + context 'with false indexable' do + let(:indexable) { false } + + it 'searchability is limited' do + expect(subject.searchability).to eq 'limited' + end + end + + context 'with no-indexable key' do + let(:payload) do + { + id: 'https://foo.test', + type: 'Actor', + inbox: 'https://foo.test/inbox', + followers: 'https://example.com/followers', + searchableBy: searchable_by, + summary: sender_bio, + }.with_indifferent_access + end + + it 'searchability is public' do + expect(subject.searchability).to eq 'public' + end + end end context 'with bio' do