Hide blocked users from more places (#12733)

* Hide blocked, muted, and blocked-by users from toot favourite lists

* Hide blocked, muted, and blocked-by users from toot reblog lists

* Hide blocked, muted, and blocked-by users from followers/following (API)

* Fix tests

* Hide blocked, muted, and blocked-by users from followers/following on public pages
This commit is contained in:
ThibG 2019-12-31 00:55:32 +01:00 committed by Eugen Rochko
parent 2999c95596
commit 3b3bdc7293
12 changed files with 128 additions and 18 deletions

View file

@ -21,7 +21,9 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController
def load_accounts def load_accounts
return [] if hide_results? return [] if hide_results?
default_accounts.merge(paginated_follows).to_a scope = default_accounts
scope = scope.where.not(id: current_account.excluded_from_timeline_account_ids) unless current_account.nil?
scope.merge(paginated_follows).to_a
end end
def hide_results? def hide_results?

View file

@ -21,7 +21,9 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController
def load_accounts def load_accounts
return [] if hide_results? return [] if hide_results?
default_accounts.merge(paginated_follows).to_a scope = default_accounts
scope = scope.where.not(id: current_account.excluded_from_timeline_account_ids) unless current_account.nil?
scope.merge(paginated_follows).to_a
end end
def hide_results? def hide_results?

View file

@ -17,7 +17,9 @@ class Api::V1::Statuses::FavouritedByAccountsController < Api::BaseController
private private
def load_accounts def load_accounts
default_accounts.merge(paginated_favourites).to_a scope = default_accounts
scope = scope.where.not(id: current_account.excluded_from_timeline_account_ids) unless current_account.nil?
scope.merge(paginated_favourites).to_a
end end
def default_accounts def default_accounts

View file

@ -17,7 +17,9 @@ class Api::V1::Statuses::RebloggedByAccountsController < Api::BaseController
private private
def load_accounts def load_accounts
default_accounts.merge(paginated_statuses).to_a scope = default_accounts
scope = scope.where.not(id: current_account.excluded_from_timeline_account_ids) unless current_account.nil?
scope.merge(paginated_statuses).to_a
end end
def default_accounts def default_accounts

View file

@ -36,7 +36,11 @@ class FollowerAccountsController < ApplicationController
private private
def follows def follows
@follows ||= Follow.where(target_account: @account).recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:account) return @follows if defined?(@follows)
scope = Follow.where(target_account: @account)
scope = scope.where.not(account_id: current_account.excluded_from_timeline_account_ids) if user_signed_in?
@follows = scope.recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:account)
end end
def page_requested? def page_requested?

View file

@ -36,7 +36,11 @@ class FollowingAccountsController < ApplicationController
private private
def follows def follows
@follows ||= Follow.where(account: @account).recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:target_account) return @follows if defined?(@follows)
scope = Follow.where(account: @account)
scope = scope.where.not(target_account_id: current_account.excluded_from_timeline_account_ids) if user_signed_in?
@follows = scope.recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:target_account)
end end
def page_requested? def page_requested?

View file

@ -3,19 +3,38 @@ require 'rails_helper'
describe Api::V1::Accounts::FollowerAccountsController do describe Api::V1::Accounts::FollowerAccountsController do
render_views render_views
let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') } let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') }
let(:account) { Fabricate(:account) }
let(:alice) { Fabricate(:account) }
let(:bob) { Fabricate(:account) }
before do before do
Fabricate(:follow, target_account: user.account) alice.follow!(account)
bob.follow!(account)
allow(controller).to receive(:doorkeeper_token) { token } allow(controller).to receive(:doorkeeper_token) { token }
end end
describe 'GET #index' do describe 'GET #index' do
it 'returns http success' do it 'returns http success' do
get :index, params: { account_id: user.account.id, limit: 1 } get :index, params: { account_id: account.id, limit: 2 }
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
end end
it 'returns accounts following the given account' do
get :index, params: { account_id: account.id, limit: 2 }
expect(body_as_json.size).to eq 2
expect([body_as_json[0][:id], body_as_json[1][:id]]).to match_array([alice.id.to_s, bob.id.to_s])
end
it 'does not return blocked users' do
user.account.block!(bob)
get :index, params: { account_id: account.id, limit: 2 }
expect(body_as_json.size).to eq 1
expect(body_as_json[0][:id]).to eq alice.id.to_s
end
end end
end end

View file

@ -3,19 +3,38 @@ require 'rails_helper'
describe Api::V1::Accounts::FollowingAccountsController do describe Api::V1::Accounts::FollowingAccountsController do
render_views render_views
let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') } let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') }
let(:account) { Fabricate(:account) }
let(:alice) { Fabricate(:account) }
let(:bob) { Fabricate(:account) }
before do before do
Fabricate(:follow, account: user.account) account.follow!(alice)
account.follow!(bob)
allow(controller).to receive(:doorkeeper_token) { token } allow(controller).to receive(:doorkeeper_token) { token }
end end
describe 'GET #index' do describe 'GET #index' do
it 'returns http success' do it 'returns http success' do
get :index, params: { account_id: user.account.id, limit: 1 } get :index, params: { account_id: account.id, limit: 2 }
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
end end
it 'returns accounts followed by the given account' do
get :index, params: { account_id: account.id, limit: 2 }
expect(body_as_json.size).to eq 2
expect([body_as_json[0][:id], body_as_json[1][:id]]).to match_array([alice.id.to_s, bob.id.to_s])
end
it 'does not return blocked users' do
user.account.block!(bob)
get :index, params: { account_id: account.id, limit: 2 }
expect(body_as_json.size).to eq 1
expect(body_as_json[0][:id]).to eq alice.id.to_s
end
end end
end end

View file

@ -6,6 +6,8 @@ RSpec.describe Api::V1::Statuses::FavouritedByAccountsController, type: :control
let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') } let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: app, scopes: 'read:accounts') } let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: app, scopes: 'read:accounts') }
let(:alice) { Fabricate(:account) }
let(:bob) { Fabricate(:account) }
context 'with an oauth token' do context 'with an oauth token' do
before do before do
@ -16,14 +18,28 @@ RSpec.describe Api::V1::Statuses::FavouritedByAccountsController, type: :control
let(:status) { Fabricate(:status, account: user.account) } let(:status) { Fabricate(:status, account: user.account) }
before do before do
Fabricate(:favourite, status: status) Favourite.create!(account: alice, status: status)
Favourite.create!(account: bob, status: status)
end end
it 'returns http success' do it 'returns http success' do
get :index, params: { status_id: status.id, limit: 1 } get :index, params: { status_id: status.id, limit: 2 }
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
expect(response.headers['Link'].links.size).to eq(2) expect(response.headers['Link'].links.size).to eq(2)
end end
it 'returns accounts who favorited the status' do
get :index, params: { status_id: status.id, limit: 2 }
expect(body_as_json.size).to eq 2
expect([body_as_json[0][:id], body_as_json[1][:id]]).to match_array([alice.id.to_s, bob.id.to_s])
end
it 'does not return blocked users' do
user.account.block!(bob)
get :index, params: { status_id: status.id, limit: 2 }
expect(body_as_json.size).to eq 1
expect(body_as_json[0][:id]).to eq alice.id.to_s
end
end end
end end

View file

@ -6,6 +6,8 @@ RSpec.describe Api::V1::Statuses::RebloggedByAccountsController, type: :controll
let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') } let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: app, scopes: 'read:accounts') } let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: app, scopes: 'read:accounts') }
let(:alice) { Fabricate(:account) }
let(:bob) { Fabricate(:account) }
context 'with an oauth token' do context 'with an oauth token' do
before do before do
@ -16,14 +18,28 @@ RSpec.describe Api::V1::Statuses::RebloggedByAccountsController, type: :controll
let(:status) { Fabricate(:status, account: user.account) } let(:status) { Fabricate(:status, account: user.account) }
before do before do
Fabricate(:status, reblog_of_id: status.id) Fabricate(:status, account: alice, reblog_of_id: status.id)
Fabricate(:status, account: bob, reblog_of_id: status.id)
end end
it 'returns http success' do it 'returns http success' do
get :index, params: { status_id: status.id, limit: 1 } get :index, params: { status_id: status.id, limit: 2 }
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
expect(response.headers['Link'].links.size).to eq(2) expect(response.headers['Link'].links.size).to eq(2)
end end
it 'returns accounts who reblogged the status' do
get :index, params: { status_id: status.id, limit: 2 }
expect(body_as_json.size).to eq 2
expect([body_as_json[0][:id], body_as_json[1][:id]]).to match_array([alice.id.to_s, bob.id.to_s])
end
it 'does not return blocked users' do
user.account.block!(bob)
get :index, params: { status_id: status.id, limit: 2 }
expect(body_as_json.size).to eq 1
expect(body_as_json[0][:id]).to eq alice.id.to_s
end
end end
end end

View file

@ -22,6 +22,18 @@ describe FollowerAccountsController do
expect(assigned[0]).to eq follow1 expect(assigned[0]).to eq follow1
expect(assigned[1]).to eq follow0 expect(assigned[1]).to eq follow0
end end
it 'does not assign blocked users' do
user = Fabricate(:user)
user.account.block!(follower0)
sign_in(user)
expect(response).to have_http_status(200)
assigned = assigns(:follows).to_a
expect(assigned.size).to eq 1
expect(assigned[0]).to eq follow1
end
end end
context 'when format is json' do context 'when format is json' do

View file

@ -22,6 +22,18 @@ describe FollowingAccountsController do
expect(assigned[0]).to eq follow1 expect(assigned[0]).to eq follow1
expect(assigned[1]).to eq follow0 expect(assigned[1]).to eq follow0
end end
it 'does not assign blocked users' do
user = Fabricate(:user)
user.account.block!(followee0)
sign_in(user)
expect(response).to have_http_status(200)
assigned = assigns(:follows).to_a
expect(assigned.size).to eq 1
expect(assigned[0]).to eq follow1
end
end end
context 'when format is json' do context 'when format is json' do