Merge commit '9e245d147bcb2c72cc552ff8c276a1c34e2f686d' into glitch-soc/merge-upstream
Conflicts: - `app/views/settings/profiles/show.html.haml`: Upstream redesigned the settings page, where glitch-soc had changes because of the ability to set some custom limits. Went with upstream's design while keeping our custom limits. - `yarn.lock`: Upstream updated dependencies textually close to a glitch-soc-only dependency. Updated the dependnencies as well.
This commit is contained in:
@ -3,17 +3,17 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::FollowersSynchronizationsController do
|
||||
let!(:account) { Fabricate(:account) }
|
||||
let!(:follower_1) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/users/a') }
|
||||
let!(:follower_2) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/users/b') }
|
||||
let!(:follower_3) { Fabricate(:account, domain: 'foo.com', uri: 'https://foo.com/users/a') }
|
||||
let!(:follower_4) { Fabricate(:account, username: 'instance-actor', domain: 'example.com', uri: 'https://example.com') }
|
||||
let!(:account) { Fabricate(:account) }
|
||||
let!(:follower_example_com_user_a) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/users/a') }
|
||||
let!(:follower_example_com_user_b) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/users/b') }
|
||||
let!(:follower_foo_com_user_a) { Fabricate(:account, domain: 'foo.com', uri: 'https://foo.com/users/a') }
|
||||
let!(:follower_example_com_instance_actor) { Fabricate(:account, username: 'instance-actor', domain: 'example.com', uri: 'https://example.com') }
|
||||
|
||||
before do
|
||||
follower_1.follow!(account)
|
||||
follower_2.follow!(account)
|
||||
follower_3.follow!(account)
|
||||
follower_4.follow!(account)
|
||||
follower_example_com_user_a.follow!(account)
|
||||
follower_example_com_user_b.follow!(account)
|
||||
follower_foo_com_user_a.follow!(account)
|
||||
follower_example_com_instance_actor.follow!(account)
|
||||
|
||||
allow(controller).to receive(:signed_request_actor).and_return(remote_account)
|
||||
end
|
||||
@ -47,7 +47,11 @@ RSpec.describe ActivityPub::FollowersSynchronizationsController do
|
||||
|
||||
it 'returns orderedItems with followers from example.com' do
|
||||
expect(body[:orderedItems]).to be_an Array
|
||||
expect(body[:orderedItems]).to contain_exactly(follower_4.uri, follower_1.uri, follower_2.uri)
|
||||
expect(body[:orderedItems]).to contain_exactly(
|
||||
follower_example_com_instance_actor.uri,
|
||||
follower_example_com_user_a.uri,
|
||||
follower_example_com_user_b.uri
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns private Cache-Control header' do
|
||||
|
@ -7,9 +7,9 @@ RSpec.describe Admin::InstancesController do
|
||||
|
||||
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
|
||||
let!(:account) { Fabricate(:account, domain: 'popular') }
|
||||
let!(:account2) { Fabricate(:account, domain: 'popular') }
|
||||
let!(:account3) { Fabricate(:account, domain: 'less.popular') }
|
||||
let!(:account_popular_main) { Fabricate(:account, domain: 'popular') }
|
||||
let!(:account_popular_other) { Fabricate(:account, domain: 'popular') }
|
||||
let!(:account_less_popular) { Fabricate(:account, domain: 'less.popular') }
|
||||
|
||||
before do
|
||||
sign_in current_user, scope: :user
|
||||
|
@ -13,14 +13,6 @@ RSpec.describe Api::V1::AccountsController do
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope|
|
||||
let(:scopes) { wrong_scope }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
let(:app) { Fabricate(:application) }
|
||||
let(:token) { Doorkeeper::AccessToken.find_or_create_for(application: app, resource_owner: nil, scopes: 'read write', use_refresh_token: false) }
|
||||
|
@ -15,22 +15,6 @@ RSpec.describe Api::V1::Admin::AccountActionsController do
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope|
|
||||
let(:scopes) { wrong_scope }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role|
|
||||
let(:role) { UserRole.find_by(name: wrong_role) }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
context 'with type of disable' do
|
||||
before do
|
||||
|
@ -15,22 +15,6 @@ RSpec.describe Api::V1::Admin::AccountsController do
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope|
|
||||
let(:scopes) { wrong_scope }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role|
|
||||
let(:role) { UserRole.find_by(name: wrong_role) }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
let!(:remote_account) { Fabricate(:account, domain: 'example.org') }
|
||||
let!(:other_remote_account) { Fabricate(:account, domain: 'foo.bar') }
|
||||
|
@ -16,22 +16,6 @@ describe Api::V1::Admin::Trends::Links::PreviewCardProvidersController do
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope|
|
||||
let(:scopes) { wrong_scope }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role|
|
||||
let(:role) { UserRole.find_by(name: wrong_role) }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
it 'returns http success' do
|
||||
get :index, params: { account_id: account.id, limit: 2 }
|
||||
|
@ -16,22 +16,6 @@ describe Api::V1::Admin::Trends::LinksController do
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope|
|
||||
let(:scopes) { wrong_scope }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role|
|
||||
let(:role) { UserRole.find_by(name: wrong_role) }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
it 'returns http success' do
|
||||
get :index, params: { account_id: account.id, limit: 2 }
|
||||
|
@ -16,22 +16,6 @@ describe Api::V1::Admin::Trends::StatusesController do
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope|
|
||||
let(:scopes) { wrong_scope }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role|
|
||||
let(:role) { UserRole.find_by(name: wrong_role) }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
it 'returns http success' do
|
||||
get :index, params: { account_id: account.id, limit: 2 }
|
||||
|
@ -16,22 +16,6 @@ describe Api::V1::Admin::Trends::TagsController do
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope|
|
||||
let(:scopes) { wrong_scope }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role|
|
||||
let(:role) { UserRole.find_by(name: wrong_role) }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
it 'returns http success' do
|
||||
get :index, params: { account_id: account.id, limit: 2 }
|
||||
|
@ -1,45 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe Api::V1::Apps::CredentialsController do
|
||||
render_views
|
||||
|
||||
let(:token) { Fabricate(:accessible_access_token, scopes: 'read', application: Fabricate(:application)) }
|
||||
|
||||
context 'with an oauth token' do
|
||||
before do
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
before do
|
||||
get :show
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'does not contain client credentials' do
|
||||
json = body_as_json
|
||||
|
||||
expect(json).to_not have_key(:client_secret)
|
||||
expect(json).to_not have_key(:client_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without an oauth token' do
|
||||
before do
|
||||
allow(controller).to receive(:doorkeeper_token).and_return(nil)
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
it 'returns http unauthorized' do
|
||||
get :show
|
||||
expect(response).to have_http_status(401)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -35,5 +35,23 @@ RSpec.describe Api::V1::ConversationsController do
|
||||
json = body_as_json
|
||||
expect(json.size).to eq 1
|
||||
end
|
||||
|
||||
context 'with since_id' do
|
||||
context 'when requesting old posts' do
|
||||
it 'returns conversations' do
|
||||
get :index, params: { since_id: Mastodon::Snowflake.id_at(1.hour.ago, with_random: false) }
|
||||
json = body_as_json
|
||||
expect(json.size).to eq 1
|
||||
end
|
||||
end
|
||||
|
||||
context 'when requesting posts in the future' do
|
||||
it 'returns no conversation' do
|
||||
get :index, params: { since_id: Mastodon::Snowflake.id_at(1.hour.from_now, with_random: false) }
|
||||
json = body_as_json
|
||||
expect(json.size).to eq 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,77 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Api::V1::DomainBlocksController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
|
||||
before do
|
||||
user.account.block_domain!('example.com')
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope|
|
||||
let(:scopes) { wrong_scope }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
let(:scopes) { 'read:blocks' }
|
||||
|
||||
before do
|
||||
get :show, params: { limit: 1 }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns blocked domains' do
|
||||
expect(body_as_json.first).to eq 'example.com'
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
let(:scopes) { 'write:blocks' }
|
||||
|
||||
before do
|
||||
post :create, params: { domain: 'example.org' }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'creates a domain block' do
|
||||
expect(user.account.domain_blocking?('example.org')).to be true
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
end
|
||||
|
||||
describe 'DELETE #destroy' do
|
||||
let(:scopes) { 'write:blocks' }
|
||||
|
||||
before do
|
||||
delete :destroy, params: { domain: 'example.com' }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'deletes a domain block' do
|
||||
expect(user.account.domain_blocking?('example.com')).to be false
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
end
|
||||
end
|
@ -1,72 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Api::V1::FollowRequestsController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user, account_attributes: { locked: true }) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:follower) { Fabricate(:account) }
|
||||
|
||||
before do
|
||||
FollowService.new.call(follower, user.account)
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
let(:scopes) { 'read:follows' }
|
||||
|
||||
before do
|
||||
get :index, params: { limit: 1 }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #authorize' do
|
||||
let(:scopes) { 'write:follows' }
|
||||
|
||||
before do
|
||||
post :authorize, params: { id: follower.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'allows follower to follow' do
|
||||
expect(follower.following?(user.account)).to be true
|
||||
end
|
||||
|
||||
it 'returns JSON with followed_by=true' do
|
||||
json = body_as_json
|
||||
|
||||
expect(json[:followed_by]).to be true
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #reject' do
|
||||
let(:scopes) { 'write:follows' }
|
||||
|
||||
before do
|
||||
post :reject, params: { id: follower.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'removes follow request' do
|
||||
expect(FollowRequest.where(target_account: user.account, account: follower).count).to eq 0
|
||||
end
|
||||
|
||||
it 'returns JSON with followed_by=false' do
|
||||
json = body_as_json
|
||||
|
||||
expect(json[:followed_by]).to be false
|
||||
end
|
||||
end
|
||||
end
|
@ -1,80 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Api::V1::ListsController do
|
||||
render_views
|
||||
|
||||
let!(:user) { Fabricate(:user) }
|
||||
let!(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let!(:list) { Fabricate(:list, account: user.account) }
|
||||
|
||||
before { allow(controller).to receive(:doorkeeper_token) { token } }
|
||||
|
||||
describe 'GET #index' do
|
||||
let(:scopes) { 'read:lists' }
|
||||
|
||||
it 'returns http success' do
|
||||
get :index
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
let(:scopes) { 'read:lists' }
|
||||
|
||||
it 'returns http success' do
|
||||
get :show, params: { id: list.id }
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
let(:scopes) { 'write:lists' }
|
||||
|
||||
before do
|
||||
post :create, params: { title: 'Foo bar' }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'creates list' do
|
||||
expect(List.where(account: user.account).count).to eq 2
|
||||
expect(List.last.title).to eq 'Foo bar'
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT #update' do
|
||||
let(:scopes) { 'write:lists' }
|
||||
|
||||
before do
|
||||
put :update, params: { id: list.id, title: 'Updated title' }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'updates the list' do
|
||||
expect(list.reload.title).to eq 'Updated title'
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE #destroy' do
|
||||
let(:scopes) { 'write:lists' }
|
||||
|
||||
before do
|
||||
delete :destroy, params: { id: list.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'deletes the list' do
|
||||
expect(List.find_by(id: list.id)).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
@ -15,22 +15,6 @@ RSpec.describe Api::V2::Admin::AccountsController do
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope|
|
||||
let(:scopes) { wrong_scope }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role|
|
||||
let(:role) { UserRole.find_by(name: wrong_role) }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
let!(:remote_account) { Fabricate(:account, domain: 'example.org') }
|
||||
let!(:other_remote_account) { Fabricate(:account, domain: 'foo.bar') }
|
||||
|
@ -5,13 +5,13 @@ require 'rails_helper'
|
||||
describe FollowerAccountsController do
|
||||
render_views
|
||||
|
||||
let(:alice) { Fabricate(:account) }
|
||||
let(:follower0) { Fabricate(:account) }
|
||||
let(:follower1) { Fabricate(:account) }
|
||||
let(:alice) { Fabricate(:account, username: 'alice') }
|
||||
let(:follower_bob) { Fabricate(:account, username: 'bob') }
|
||||
let(:follower_chris) { Fabricate(:account, username: 'curt') }
|
||||
|
||||
describe 'GET #index' do
|
||||
let!(:follow0) { follower0.follow!(alice) }
|
||||
let!(:follow1) { follower1.follow!(alice) }
|
||||
let!(:follow_from_bob) { follower_bob.follow!(alice) }
|
||||
let!(:follow_from_chris) { follower_chris.follow!(alice) }
|
||||
|
||||
context 'when format is html' do
|
||||
subject(:response) { get :index, params: { account_username: alice.username, format: :html } }
|
||||
|
@ -5,13 +5,13 @@ require 'rails_helper'
|
||||
describe FollowingAccountsController do
|
||||
render_views
|
||||
|
||||
let(:alice) { Fabricate(:account) }
|
||||
let(:followee0) { Fabricate(:account) }
|
||||
let(:followee1) { Fabricate(:account) }
|
||||
let(:alice) { Fabricate(:account, username: 'alice') }
|
||||
let(:followee_bob) { Fabricate(:account, username: 'bob') }
|
||||
let(:followee_chris) { Fabricate(:account, username: 'chris') }
|
||||
|
||||
describe 'GET #index' do
|
||||
let!(:follow0) { alice.follow!(followee0) }
|
||||
let!(:follow1) { alice.follow!(followee1) }
|
||||
let!(:follow_of_bob) { alice.follow!(followee_bob) }
|
||||
let!(:follow_of_chris) { alice.follow!(followee_chris) }
|
||||
|
||||
context 'when format is html' do
|
||||
subject(:response) { get :index, params: { account_username: alice.username, format: :html } }
|
||||
|
@ -5,31 +5,31 @@ require 'rails_helper'
|
||||
RSpec.describe AccountReachFinder do
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
let(:follower1) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/inbox-1') }
|
||||
let(:follower2) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/inbox-2') }
|
||||
let(:follower3) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://foo.bar/users/a/inbox', shared_inbox_url: 'https://foo.bar/inbox') }
|
||||
let(:ap_follower_example_com) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/inbox-1') }
|
||||
let(:ap_follower_example_org) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.org/inbox-2') }
|
||||
let(:ap_follower_with_shared) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://foo.bar/users/a/inbox', shared_inbox_url: 'https://foo.bar/inbox') }
|
||||
|
||||
let(:mentioned1) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://foo.bar/users/b/inbox', shared_inbox_url: 'https://foo.bar/inbox') }
|
||||
let(:mentioned2) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/inbox-3') }
|
||||
let(:mentioned3) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/inbox-4') }
|
||||
let(:ap_mentioned_with_shared) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://foo.bar/users/b/inbox', shared_inbox_url: 'https://foo.bar/inbox') }
|
||||
let(:ap_mentioned_example_com) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/inbox-3') }
|
||||
let(:ap_mentioned_example_org) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.org/inbox-4') }
|
||||
|
||||
let(:unrelated_account) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/unrelated-inbox') }
|
||||
|
||||
before do
|
||||
follower1.follow!(account)
|
||||
follower2.follow!(account)
|
||||
follower3.follow!(account)
|
||||
ap_follower_example_com.follow!(account)
|
||||
ap_follower_example_org.follow!(account)
|
||||
ap_follower_with_shared.follow!(account)
|
||||
|
||||
Fabricate(:status, account: account).tap do |status|
|
||||
status.mentions << Mention.new(account: follower1)
|
||||
status.mentions << Mention.new(account: mentioned1)
|
||||
status.mentions << Mention.new(account: ap_follower_example_com)
|
||||
status.mentions << Mention.new(account: ap_mentioned_with_shared)
|
||||
end
|
||||
|
||||
Fabricate(:status, account: account)
|
||||
|
||||
Fabricate(:status, account: account).tap do |status|
|
||||
status.mentions << Mention.new(account: mentioned2)
|
||||
status.mentions << Mention.new(account: mentioned3)
|
||||
status.mentions << Mention.new(account: ap_mentioned_example_com)
|
||||
status.mentions << Mention.new(account: ap_mentioned_example_org)
|
||||
end
|
||||
|
||||
Fabricate(:status).tap do |status|
|
||||
@ -39,11 +39,11 @@ RSpec.describe AccountReachFinder do
|
||||
|
||||
describe '#inboxes' do
|
||||
it 'includes the preferred inbox URL of followers' do
|
||||
expect(described_class.new(account).inboxes).to include(*[follower1, follower2, follower3].map(&:preferred_inbox_url))
|
||||
expect(described_class.new(account).inboxes).to include(*[ap_follower_example_com, ap_follower_example_org, ap_follower_with_shared].map(&:preferred_inbox_url))
|
||||
end
|
||||
|
||||
it 'includes the preferred inbox URL of recently-mentioned accounts' do
|
||||
expect(described_class.new(account).inboxes).to include(*[mentioned1, mentioned2, mentioned3].map(&:preferred_inbox_url))
|
||||
expect(described_class.new(account).inboxes).to include(*[ap_mentioned_with_shared, ap_mentioned_example_com, ap_mentioned_example_org].map(&:preferred_inbox_url))
|
||||
end
|
||||
|
||||
it 'does not include the inbox of unrelated users' do
|
||||
|
@ -533,19 +533,25 @@ RSpec.describe FeedManager do
|
||||
end
|
||||
|
||||
describe '#clear_from_home' do
|
||||
let(:account) { Fabricate(:account) }
|
||||
let(:account) { Fabricate(:account) }
|
||||
let(:followed_account) { Fabricate(:account) }
|
||||
let(:target_account) { Fabricate(:account) }
|
||||
let(:status_1) { Fabricate(:status, account: followed_account) }
|
||||
let(:status_2) { Fabricate(:status, account: target_account) }
|
||||
let(:status_3) { Fabricate(:status, account: followed_account, mentions: [Fabricate(:mention, account: target_account)]) }
|
||||
let(:status_4) { Fabricate(:status, mentions: [Fabricate(:mention, account: target_account)]) }
|
||||
let(:status_5) { Fabricate(:status, account: followed_account, reblog: status_4) }
|
||||
let(:status_6) { Fabricate(:status, account: followed_account, reblog: status_2) }
|
||||
let(:status_7) { Fabricate(:status, account: followed_account) }
|
||||
let(:target_account) { Fabricate(:account) }
|
||||
let(:status_from_followed_account_first) { Fabricate(:status, account: followed_account) }
|
||||
let(:status_from_target_account) { Fabricate(:status, account: target_account) }
|
||||
let(:status_from_followed_account_mentions_target_account) { Fabricate(:status, account: followed_account, mentions: [Fabricate(:mention, account: target_account)]) }
|
||||
let(:status_mentions_target_account) { Fabricate(:status, mentions: [Fabricate(:mention, account: target_account)]) }
|
||||
let(:status_from_followed_account_reblogs_status_mentions_target_account) { Fabricate(:status, account: followed_account, reblog: status_mentions_target_account) }
|
||||
let(:status_from_followed_account_reblogs_status_from_target_account) { Fabricate(:status, account: followed_account, reblog: status_from_target_account) }
|
||||
let(:status_from_followed_account_next) { Fabricate(:status, account: followed_account) }
|
||||
|
||||
before do
|
||||
[status_1, status_3, status_5, status_6, status_7].each do |status|
|
||||
[
|
||||
status_from_followed_account_first,
|
||||
status_from_followed_account_mentions_target_account,
|
||||
status_from_followed_account_reblogs_status_mentions_target_account,
|
||||
status_from_followed_account_reblogs_status_from_target_account,
|
||||
status_from_followed_account_next,
|
||||
].each do |status|
|
||||
redis.zadd("feed:home:#{account.id}", status.id, status.id)
|
||||
end
|
||||
end
|
||||
@ -553,7 +559,7 @@ RSpec.describe FeedManager do
|
||||
it 'correctly cleans the home timeline' do
|
||||
described_class.instance.clear_from_home(account, target_account)
|
||||
|
||||
expect(redis.zrange("feed:home:#{account.id}", 0, -1)).to eq [status_1.id.to_s, status_7.id.to_s]
|
||||
expect(redis.zrange("feed:home:#{account.id}", 0, -1)).to eq [status_from_followed_account_first.id.to_s, status_from_followed_account_next.id.to_s]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -189,22 +189,22 @@ describe Mastodon::CLI::IpBlocks do
|
||||
end
|
||||
|
||||
context 'with --force option' do
|
||||
let!(:block1) { IpBlock.create(ip: '192.168.0.0/24', severity: :no_access) }
|
||||
let!(:block2) { IpBlock.create(ip: '10.0.0.0/16', severity: :no_access) }
|
||||
let!(:block3) { IpBlock.create(ip: '172.16.0.0/20', severity: :no_access) }
|
||||
let!(:first_ip_range_block) { IpBlock.create(ip: '192.168.0.0/24', severity: :no_access) }
|
||||
let!(:second_ip_range_block) { IpBlock.create(ip: '10.0.0.0/16', severity: :no_access) }
|
||||
let!(:third_ip_range_block) { IpBlock.create(ip: '172.16.0.0/20', severity: :no_access) }
|
||||
let(:arguments) { ['192.168.0.5', '10.0.1.50'] }
|
||||
let(:options) { { force: true } }
|
||||
|
||||
it 'removes blocks for IP ranges that cover given IP(s)' do
|
||||
cli.invoke(:remove, arguments, options)
|
||||
|
||||
expect(IpBlock.where(id: [block1.id, block2.id])).to_not exist
|
||||
expect(IpBlock.where(id: [first_ip_range_block.id, second_ip_range_block.id])).to_not exist
|
||||
end
|
||||
|
||||
it 'does not remove other IP ranges' do
|
||||
cli.invoke(:remove, arguments, options)
|
||||
|
||||
expect(IpBlock.where(id: block3.id)).to exist
|
||||
expect(IpBlock.where(id: third_ip_range_block.id)).to exist
|
||||
end
|
||||
end
|
||||
|
||||
@ -251,22 +251,22 @@ describe Mastodon::CLI::IpBlocks do
|
||||
end
|
||||
|
||||
describe '#export' do
|
||||
let(:block1) { IpBlock.create(ip: '192.168.0.0/24', severity: :no_access) }
|
||||
let(:block2) { IpBlock.create(ip: '10.0.0.0/16', severity: :no_access) }
|
||||
let(:block3) { IpBlock.create(ip: '127.0.0.1', severity: :sign_up_block) }
|
||||
let(:first_ip_range_block) { IpBlock.create(ip: '192.168.0.0/24', severity: :no_access) }
|
||||
let(:second_ip_range_block) { IpBlock.create(ip: '10.0.0.0/16', severity: :no_access) }
|
||||
let(:third_ip_range_block) { IpBlock.create(ip: '127.0.0.1', severity: :sign_up_block) }
|
||||
|
||||
context 'when --format option is set to "plain"' do
|
||||
let(:options) { { format: 'plain' } }
|
||||
|
||||
it 'exports blocked IPs with "no_access" severity in plain format' do
|
||||
expect { cli.invoke(:export, nil, options) }.to output(
|
||||
a_string_including("#{block1.ip}/#{block1.ip.prefix}\n#{block2.ip}/#{block2.ip.prefix}")
|
||||
a_string_including("#{first_ip_range_block.ip}/#{first_ip_range_block.ip.prefix}\n#{second_ip_range_block.ip}/#{second_ip_range_block.ip.prefix}")
|
||||
).to_stdout
|
||||
end
|
||||
|
||||
it 'does not export bloked IPs with different severities' do
|
||||
expect { cli.invoke(:export, nil, options) }.to_not output(
|
||||
a_string_including("#{block3.ip}/#{block1.ip.prefix}")
|
||||
a_string_including("#{third_ip_range_block.ip}/#{first_ip_range_block.ip.prefix}")
|
||||
).to_stdout
|
||||
end
|
||||
end
|
||||
@ -276,13 +276,13 @@ describe Mastodon::CLI::IpBlocks do
|
||||
|
||||
it 'exports blocked IPs with "no_access" severity in plain format' do
|
||||
expect { cli.invoke(:export, nil, options) }.to output(
|
||||
a_string_including("deny #{block1.ip}/#{block1.ip.prefix};\ndeny #{block2.ip}/#{block2.ip.prefix};")
|
||||
a_string_including("deny #{first_ip_range_block.ip}/#{first_ip_range_block.ip.prefix};\ndeny #{second_ip_range_block.ip}/#{second_ip_range_block.ip.prefix};")
|
||||
).to_stdout
|
||||
end
|
||||
|
||||
it 'does not export bloked IPs with different severities' do
|
||||
expect { cli.invoke(:export, nil, options) }.to_not output(
|
||||
a_string_including("deny #{block3.ip}/#{block1.ip.prefix};")
|
||||
a_string_including("deny #{third_ip_range_block.ip}/#{first_ip_range_block.ip.prefix};")
|
||||
).to_stdout
|
||||
end
|
||||
end
|
||||
@ -290,7 +290,7 @@ describe Mastodon::CLI::IpBlocks do
|
||||
context 'when --format option is not provided' do
|
||||
it 'exports blocked IPs in plain format by default' do
|
||||
expect { cli.export }.to output(
|
||||
a_string_including("#{block1.ip}/#{block1.ip.prefix}\n#{block2.ip}/#{block2.ip.prefix}")
|
||||
a_string_including("#{first_ip_range_block.ip}/#{first_ip_range_block.ip.prefix}\n#{second_ip_range_block.ip}/#{second_ip_range_block.ip.prefix}")
|
||||
).to_stdout
|
||||
end
|
||||
end
|
||||
|
@ -266,10 +266,10 @@ RSpec.describe AccountStatusesCleanupPolicy do
|
||||
let!(:self_bookmarked) { Fabricate(:status, created_at: 1.year.ago, account: account) }
|
||||
let!(:status_with_poll) { Fabricate(:status, created_at: 1.year.ago, account: account, poll_attributes: { account: account, voters_count: 0, options: %w(a b), expires_in: 2.days }) }
|
||||
let!(:status_with_media) { Fabricate(:status, created_at: 1.year.ago, account: account) }
|
||||
let!(:faved4) { Fabricate(:status, created_at: 1.year.ago, account: account) }
|
||||
let!(:faved5) { Fabricate(:status, created_at: 1.year.ago, account: account) }
|
||||
let!(:reblogged4) { Fabricate(:status, created_at: 1.year.ago, account: account) }
|
||||
let!(:reblogged5) { Fabricate(:status, created_at: 1.year.ago, account: account) }
|
||||
let!(:faved_primary) { Fabricate(:status, created_at: 1.year.ago, account: account) }
|
||||
let!(:faved_secondary) { Fabricate(:status, created_at: 1.year.ago, account: account) }
|
||||
let!(:reblogged_primary) { Fabricate(:status, created_at: 1.year.ago, account: account) }
|
||||
let!(:reblogged_secondary) { Fabricate(:status, created_at: 1.year.ago, account: account) }
|
||||
let!(:recent_status) { Fabricate(:status, created_at: 2.days.ago, account: account) }
|
||||
|
||||
let!(:media_attachment) { Fabricate(:media_attachment, account: account, status: status_with_media) }
|
||||
@ -280,10 +280,10 @@ RSpec.describe AccountStatusesCleanupPolicy do
|
||||
let(:account_statuses_cleanup_policy) { Fabricate(:account_statuses_cleanup_policy, account: account) }
|
||||
|
||||
before do
|
||||
4.times { faved4.increment_count!(:favourites_count) }
|
||||
5.times { faved5.increment_count!(:favourites_count) }
|
||||
4.times { reblogged4.increment_count!(:reblogs_count) }
|
||||
5.times { reblogged5.increment_count!(:reblogs_count) }
|
||||
4.times { faved_primary.increment_count!(:favourites_count) }
|
||||
5.times { faved_secondary.increment_count!(:favourites_count) }
|
||||
4.times { reblogged_primary.increment_count!(:reblogs_count) }
|
||||
5.times { reblogged_secondary.increment_count!(:reblogs_count) }
|
||||
end
|
||||
|
||||
context 'when passed a max_id' do
|
||||
@ -359,7 +359,7 @@ RSpec.describe AccountStatusesCleanupPolicy do
|
||||
end
|
||||
|
||||
it 'returns every other old status for deletion' do
|
||||
expect(subject.pluck(:id)).to include(very_old_status.id, pinned_status.id, self_faved.id, self_bookmarked.id, status_with_poll.id, status_with_media.id, faved4.id, faved5.id, reblogged4.id, reblogged5.id)
|
||||
expect(subject.pluck(:id)).to include(very_old_status.id, pinned_status.id, self_faved.id, self_bookmarked.id, status_with_poll.id, status_with_media.id, faved_primary.id, faved_secondary.id, reblogged_primary.id, reblogged_secondary.id)
|
||||
end
|
||||
end
|
||||
|
||||
@ -378,7 +378,7 @@ RSpec.describe AccountStatusesCleanupPolicy do
|
||||
end
|
||||
|
||||
it 'returns every other old status for deletion' do
|
||||
expect(subject.pluck(:id)).to include(direct_message.id, very_old_status.id, pinned_status.id, self_faved.id, status_with_poll.id, status_with_media.id, faved4.id, faved5.id, reblogged4.id, reblogged5.id)
|
||||
expect(subject.pluck(:id)).to include(direct_message.id, very_old_status.id, pinned_status.id, self_faved.id, status_with_poll.id, status_with_media.id, faved_primary.id, faved_secondary.id, reblogged_primary.id, reblogged_secondary.id)
|
||||
end
|
||||
end
|
||||
|
||||
@ -397,7 +397,7 @@ RSpec.describe AccountStatusesCleanupPolicy do
|
||||
end
|
||||
|
||||
it 'returns every other old status for deletion' do
|
||||
expect(subject.pluck(:id)).to include(direct_message.id, very_old_status.id, pinned_status.id, self_bookmarked.id, status_with_poll.id, status_with_media.id, faved4.id, faved5.id, reblogged4.id, reblogged5.id)
|
||||
expect(subject.pluck(:id)).to include(direct_message.id, very_old_status.id, pinned_status.id, self_bookmarked.id, status_with_poll.id, status_with_media.id, faved_primary.id, faved_secondary.id, reblogged_primary.id, reblogged_secondary.id)
|
||||
end
|
||||
end
|
||||
|
||||
@ -416,7 +416,7 @@ RSpec.describe AccountStatusesCleanupPolicy do
|
||||
end
|
||||
|
||||
it 'returns every other old status for deletion' do
|
||||
expect(subject.pluck(:id)).to include(direct_message.id, very_old_status.id, pinned_status.id, self_faved.id, self_bookmarked.id, status_with_poll.id, faved4.id, faved5.id, reblogged4.id, reblogged5.id)
|
||||
expect(subject.pluck(:id)).to include(direct_message.id, very_old_status.id, pinned_status.id, self_faved.id, self_bookmarked.id, status_with_poll.id, faved_primary.id, faved_secondary.id, reblogged_primary.id, reblogged_secondary.id)
|
||||
end
|
||||
end
|
||||
|
||||
@ -435,7 +435,7 @@ RSpec.describe AccountStatusesCleanupPolicy do
|
||||
end
|
||||
|
||||
it 'returns every other old status for deletion' do
|
||||
expect(subject.pluck(:id)).to include(direct_message.id, very_old_status.id, pinned_status.id, self_faved.id, self_bookmarked.id, status_with_media.id, faved4.id, faved5.id, reblogged4.id, reblogged5.id)
|
||||
expect(subject.pluck(:id)).to include(direct_message.id, very_old_status.id, pinned_status.id, self_faved.id, self_bookmarked.id, status_with_media.id, faved_primary.id, faved_secondary.id, reblogged_primary.id, reblogged_secondary.id)
|
||||
end
|
||||
end
|
||||
|
||||
@ -454,7 +454,7 @@ RSpec.describe AccountStatusesCleanupPolicy do
|
||||
end
|
||||
|
||||
it 'returns every other old status for deletion' do
|
||||
expect(subject.pluck(:id)).to include(direct_message.id, very_old_status.id, self_faved.id, self_bookmarked.id, status_with_poll.id, status_with_media.id, faved4.id, faved5.id, reblogged4.id, reblogged5.id)
|
||||
expect(subject.pluck(:id)).to include(direct_message.id, very_old_status.id, self_faved.id, self_bookmarked.id, status_with_poll.id, status_with_media.id, faved_primary.id, faved_secondary.id, reblogged_primary.id, reblogged_secondary.id)
|
||||
end
|
||||
end
|
||||
|
||||
@ -477,7 +477,7 @@ RSpec.describe AccountStatusesCleanupPolicy do
|
||||
end
|
||||
|
||||
it 'returns every other old status for deletion' do
|
||||
expect(subject.pluck(:id)).to include(direct_message.id, very_old_status.id, pinned_status.id, self_faved.id, self_bookmarked.id, status_with_poll.id, status_with_media.id, faved4.id, faved5.id, reblogged4.id, reblogged5.id)
|
||||
expect(subject.pluck(:id)).to include(direct_message.id, very_old_status.id, pinned_status.id, self_faved.id, self_bookmarked.id, status_with_poll.id, status_with_media.id, faved_primary.id, faved_secondary.id, reblogged_primary.id, reblogged_secondary.id)
|
||||
end
|
||||
end
|
||||
|
||||
@ -496,7 +496,7 @@ RSpec.describe AccountStatusesCleanupPolicy do
|
||||
end
|
||||
|
||||
it 'returns only normal statuses for deletion' do
|
||||
expect(subject.pluck(:id)).to contain_exactly(very_old_status.id, faved4.id, faved5.id, reblogged4.id, reblogged5.id)
|
||||
expect(subject.pluck(:id)).to contain_exactly(very_old_status.id, faved_primary.id, faved_secondary.id, reblogged_primary.id, reblogged_secondary.id)
|
||||
end
|
||||
end
|
||||
|
||||
@ -510,7 +510,7 @@ RSpec.describe AccountStatusesCleanupPolicy do
|
||||
end
|
||||
|
||||
it 'does not return the toot reblogged 5 times' do
|
||||
expect(subject.pluck(:id)).to_not include(reblogged5.id)
|
||||
expect(subject.pluck(:id)).to_not include(reblogged_secondary.id)
|
||||
end
|
||||
|
||||
it 'does not return the unrelated toot' do
|
||||
@ -518,7 +518,7 @@ RSpec.describe AccountStatusesCleanupPolicy do
|
||||
end
|
||||
|
||||
it 'returns old statuses not reblogged as much' do
|
||||
expect(subject.pluck(:id)).to include(very_old_status.id, faved4.id, faved5.id, reblogged4.id)
|
||||
expect(subject.pluck(:id)).to include(very_old_status.id, faved_primary.id, faved_secondary.id, reblogged_primary.id)
|
||||
end
|
||||
end
|
||||
|
||||
@ -532,7 +532,7 @@ RSpec.describe AccountStatusesCleanupPolicy do
|
||||
end
|
||||
|
||||
it 'does not return the toot faved 5 times' do
|
||||
expect(subject.pluck(:id)).to_not include(faved5.id)
|
||||
expect(subject.pluck(:id)).to_not include(faved_secondary.id)
|
||||
end
|
||||
|
||||
it 'does not return the unrelated toot' do
|
||||
@ -540,7 +540,7 @@ RSpec.describe AccountStatusesCleanupPolicy do
|
||||
end
|
||||
|
||||
it 'returns old statuses not faved as much' do
|
||||
expect(subject.pluck(:id)).to include(very_old_status.id, faved4.id, reblogged4.id, reblogged5.id)
|
||||
expect(subject.pluck(:id)).to include(very_old_status.id, faved_primary.id, reblogged_primary.id, reblogged_secondary.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -55,6 +55,22 @@ RSpec.describe Admin::AccountAction do
|
||||
end
|
||||
end
|
||||
|
||||
context 'when type is invalid' do
|
||||
let(:type) { 'whatever' }
|
||||
|
||||
it 'raises an invalid record error' do
|
||||
expect { subject }.to raise_error(ActiveRecord::RecordInvalid)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when type is not given' do
|
||||
let(:type) { '' }
|
||||
|
||||
it 'raises an invalid record error' do
|
||||
expect { subject }.to raise_error(ActiveRecord::RecordInvalid)
|
||||
end
|
||||
end
|
||||
|
||||
it 'creates Admin::ActionLog' do
|
||||
expect do
|
||||
subject
|
||||
|
@ -567,17 +567,17 @@ describe AccountInteractions do
|
||||
|
||||
describe '#remote_followers_hash' do
|
||||
let(:me) { Fabricate(:account, username: 'Me') }
|
||||
let(:remote_1) { Fabricate(:account, username: 'alice', domain: 'example.org', uri: 'https://example.org/users/alice') }
|
||||
let(:remote_2) { Fabricate(:account, username: 'bob', domain: 'example.org', uri: 'https://example.org/users/bob') }
|
||||
let(:remote_3) { Fabricate(:account, username: 'instance-actor', domain: 'example.org', uri: 'https://example.org') }
|
||||
let(:remote_4) { Fabricate(:account, username: 'eve', domain: 'foo.org', uri: 'https://foo.org/users/eve') }
|
||||
let(:remote_alice) { Fabricate(:account, username: 'alice', domain: 'example.org', uri: 'https://example.org/users/alice') }
|
||||
let(:remote_bob) { Fabricate(:account, username: 'bob', domain: 'example.org', uri: 'https://example.org/users/bob') }
|
||||
let(:remote_instance_actor) { Fabricate(:account, username: 'instance-actor', domain: 'example.org', uri: 'https://example.org') }
|
||||
let(:remote_eve) { Fabricate(:account, username: 'eve', domain: 'foo.org', uri: 'https://foo.org/users/eve') }
|
||||
|
||||
before do
|
||||
remote_1.follow!(me)
|
||||
remote_2.follow!(me)
|
||||
remote_3.follow!(me)
|
||||
remote_4.follow!(me)
|
||||
me.follow!(remote_1)
|
||||
remote_alice.follow!(me)
|
||||
remote_bob.follow!(me)
|
||||
remote_instance_actor.follow!(me)
|
||||
remote_eve.follow!(me)
|
||||
me.follow!(remote_alice)
|
||||
end
|
||||
|
||||
it 'returns correct hash for remote domains' do
|
||||
@ -589,33 +589,33 @@ describe AccountInteractions do
|
||||
|
||||
it 'invalidates cache as needed when removing or adding followers' do
|
||||
expect(me.remote_followers_hash('https://example.org/')).to eq '20aecbe774b3d61c25094370baf370012b9271c5b172ecedb05caff8d79ef0c7'
|
||||
remote_3.unfollow!(me)
|
||||
remote_instance_actor.unfollow!(me)
|
||||
expect(me.remote_followers_hash('https://example.org/')).to eq '707962e297b7bd94468a21bc8e506a1bcea607a9142cd64e27c9b106b2a5f6ec'
|
||||
remote_1.unfollow!(me)
|
||||
remote_alice.unfollow!(me)
|
||||
expect(me.remote_followers_hash('https://example.org/')).to eq '241b00794ce9b46aa864f3220afadef128318da2659782985bac5ed5bd436bff'
|
||||
remote_1.follow!(me)
|
||||
remote_alice.follow!(me)
|
||||
expect(me.remote_followers_hash('https://example.org/')).to eq '707962e297b7bd94468a21bc8e506a1bcea607a9142cd64e27c9b106b2a5f6ec'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#local_followers_hash' do
|
||||
let(:me) { Fabricate(:account, username: 'Me') }
|
||||
let(:remote_1) { Fabricate(:account, username: 'alice', domain: 'example.org', uri: 'https://example.org/users/alice') }
|
||||
let(:remote_alice) { Fabricate(:account, username: 'alice', domain: 'example.org', uri: 'https://example.org/users/alice') }
|
||||
|
||||
before do
|
||||
me.follow!(remote_1)
|
||||
me.follow!(remote_alice)
|
||||
end
|
||||
|
||||
it 'returns correct hash for local users' do
|
||||
expect(remote_1.local_followers_hash).to eq Digest::SHA256.hexdigest(ActivityPub::TagManager.instance.uri_for(me))
|
||||
expect(remote_alice.local_followers_hash).to eq Digest::SHA256.hexdigest(ActivityPub::TagManager.instance.uri_for(me))
|
||||
end
|
||||
|
||||
it 'invalidates cache as needed when removing or adding followers' do
|
||||
expect(remote_1.local_followers_hash).to eq Digest::SHA256.hexdigest(ActivityPub::TagManager.instance.uri_for(me))
|
||||
me.unfollow!(remote_1)
|
||||
expect(remote_1.local_followers_hash).to eq '0000000000000000000000000000000000000000000000000000000000000000'
|
||||
me.follow!(remote_1)
|
||||
expect(remote_1.local_followers_hash).to eq Digest::SHA256.hexdigest(ActivityPub::TagManager.instance.uri_for(me))
|
||||
expect(remote_alice.local_followers_hash).to eq Digest::SHA256.hexdigest(ActivityPub::TagManager.instance.uri_for(me))
|
||||
me.unfollow!(remote_alice)
|
||||
expect(remote_alice.local_followers_hash).to eq '0000000000000000000000000000000000000000000000000000000000000000'
|
||||
me.follow!(remote_alice)
|
||||
expect(remote_alice.local_followers_hash).to eq Digest::SHA256.hexdigest(ActivityPub::TagManager.instance.uri_for(me))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -8,40 +8,40 @@ describe StatusThreadingConcern do
|
||||
let!(:bob) { Fabricate(:account, username: 'bob', domain: 'example.com') }
|
||||
let!(:jeff) { Fabricate(:account, username: 'jeff') }
|
||||
let!(:status) { Fabricate(:status, account: alice) }
|
||||
let!(:reply1) { Fabricate(:status, thread: status, account: jeff) }
|
||||
let!(:reply2) { Fabricate(:status, thread: reply1, account: bob) }
|
||||
let!(:reply3) { Fabricate(:status, thread: reply2, account: alice) }
|
||||
let!(:reply_to_status) { Fabricate(:status, thread: status, account: jeff) }
|
||||
let!(:reply_to_first_reply) { Fabricate(:status, thread: reply_to_status, account: bob) }
|
||||
let!(:reply_to_second_reply) { Fabricate(:status, thread: reply_to_first_reply, account: alice) }
|
||||
let!(:viewer) { Fabricate(:account, username: 'viewer') }
|
||||
|
||||
it 'returns conversation history' do
|
||||
expect(reply3.ancestors(4)).to include(status, reply1, reply2)
|
||||
expect(reply_to_second_reply.ancestors(4)).to include(status, reply_to_status, reply_to_first_reply)
|
||||
end
|
||||
|
||||
it 'does not return conversation history user is not allowed to see' do
|
||||
reply1.update(visibility: :private)
|
||||
reply_to_status.update(visibility: :private)
|
||||
status.update(visibility: :direct)
|
||||
|
||||
expect(reply3.ancestors(4, viewer)).to_not include(reply1, status)
|
||||
expect(reply_to_second_reply.ancestors(4, viewer)).to_not include(reply_to_status, status)
|
||||
end
|
||||
|
||||
it 'does not return conversation history from blocked users' do
|
||||
viewer.block!(jeff)
|
||||
expect(reply3.ancestors(4, viewer)).to_not include(reply1)
|
||||
expect(reply_to_second_reply.ancestors(4, viewer)).to_not include(reply_to_status)
|
||||
end
|
||||
|
||||
it 'does not return conversation history from muted users' do
|
||||
viewer.mute!(jeff)
|
||||
expect(reply3.ancestors(4, viewer)).to_not include(reply1)
|
||||
expect(reply_to_second_reply.ancestors(4, viewer)).to_not include(reply_to_status)
|
||||
end
|
||||
|
||||
it 'does not return conversation history from silenced and not followed users' do
|
||||
jeff.silence!
|
||||
expect(reply3.ancestors(4, viewer)).to_not include(reply1)
|
||||
expect(reply_to_second_reply.ancestors(4, viewer)).to_not include(reply_to_status)
|
||||
end
|
||||
|
||||
it 'does not return conversation history from blocked domains' do
|
||||
viewer.block_domain!('example.com')
|
||||
expect(reply3.ancestors(4, viewer)).to_not include(reply2)
|
||||
expect(reply_to_second_reply.ancestors(4, viewer)).to_not include(reply_to_first_reply)
|
||||
end
|
||||
|
||||
it 'ignores deleted records' do
|
||||
@ -83,40 +83,40 @@ describe StatusThreadingConcern do
|
||||
let!(:bob) { Fabricate(:account, username: 'bob', domain: 'example.com') }
|
||||
let!(:jeff) { Fabricate(:account, username: 'jeff') }
|
||||
let!(:status) { Fabricate(:status, account: alice) }
|
||||
let!(:reply1) { Fabricate(:status, thread: status, account: alice) }
|
||||
let!(:reply2) { Fabricate(:status, thread: status, account: bob) }
|
||||
let!(:reply3) { Fabricate(:status, thread: reply1, account: jeff) }
|
||||
let!(:reply_to_status_from_alice) { Fabricate(:status, thread: status, account: alice) }
|
||||
let!(:reply_to_status_from_bob) { Fabricate(:status, thread: status, account: bob) }
|
||||
let!(:reply_to_alice_reply_from_jeff) { Fabricate(:status, thread: reply_to_status_from_alice, account: jeff) }
|
||||
let!(:viewer) { Fabricate(:account, username: 'viewer') }
|
||||
|
||||
it 'returns replies' do
|
||||
expect(status.descendants(4)).to include(reply1, reply2, reply3)
|
||||
expect(status.descendants(4)).to include(reply_to_status_from_alice, reply_to_status_from_bob, reply_to_alice_reply_from_jeff)
|
||||
end
|
||||
|
||||
it 'does not return replies user is not allowed to see' do
|
||||
reply1.update(visibility: :private)
|
||||
reply3.update(visibility: :direct)
|
||||
reply_to_status_from_alice.update(visibility: :private)
|
||||
reply_to_alice_reply_from_jeff.update(visibility: :direct)
|
||||
|
||||
expect(status.descendants(4, viewer)).to_not include(reply1, reply3)
|
||||
expect(status.descendants(4, viewer)).to_not include(reply_to_status_from_alice, reply_to_alice_reply_from_jeff)
|
||||
end
|
||||
|
||||
it 'does not return replies from blocked users' do
|
||||
viewer.block!(jeff)
|
||||
expect(status.descendants(4, viewer)).to_not include(reply3)
|
||||
expect(status.descendants(4, viewer)).to_not include(reply_to_alice_reply_from_jeff)
|
||||
end
|
||||
|
||||
it 'does not return replies from muted users' do
|
||||
viewer.mute!(jeff)
|
||||
expect(status.descendants(4, viewer)).to_not include(reply3)
|
||||
expect(status.descendants(4, viewer)).to_not include(reply_to_alice_reply_from_jeff)
|
||||
end
|
||||
|
||||
it 'does not return replies from silenced and not followed users' do
|
||||
jeff.silence!
|
||||
expect(status.descendants(4, viewer)).to_not include(reply3)
|
||||
expect(status.descendants(4, viewer)).to_not include(reply_to_alice_reply_from_jeff)
|
||||
end
|
||||
|
||||
it 'does not return replies from blocked domains' do
|
||||
viewer.block_domain!('example.com')
|
||||
expect(status.descendants(4, viewer)).to_not include(reply2)
|
||||
expect(status.descendants(4, viewer)).to_not include(reply_to_status_from_bob)
|
||||
end
|
||||
|
||||
it 'promotes self-replies to the top while leaving the rest in order' do
|
||||
|
@ -6,9 +6,9 @@ RSpec.describe CustomEmojiFilter do
|
||||
describe '#results' do
|
||||
subject { described_class.new(params).results }
|
||||
|
||||
let!(:custom_emoji_0) { Fabricate(:custom_emoji, domain: 'a') }
|
||||
let!(:custom_emoji_1) { Fabricate(:custom_emoji, domain: 'b') }
|
||||
let!(:custom_emoji_2) { Fabricate(:custom_emoji, domain: nil, shortcode: 'hoge') }
|
||||
let!(:custom_emoji_domain_a) { Fabricate(:custom_emoji, domain: 'a') }
|
||||
let!(:custom_emoji_domain_b) { Fabricate(:custom_emoji, domain: 'b') }
|
||||
let!(:custom_emoji_domain_nil) { Fabricate(:custom_emoji, domain: nil, shortcode: 'hoge') }
|
||||
|
||||
context 'when params have values' do
|
||||
context 'when local' do
|
||||
@ -16,7 +16,7 @@ RSpec.describe CustomEmojiFilter do
|
||||
|
||||
it 'returns ActiveRecord::Relation' do
|
||||
expect(subject).to be_a(ActiveRecord::Relation)
|
||||
expect(subject).to contain_exactly(custom_emoji_2)
|
||||
expect(subject).to contain_exactly(custom_emoji_domain_nil)
|
||||
end
|
||||
end
|
||||
|
||||
@ -25,7 +25,7 @@ RSpec.describe CustomEmojiFilter do
|
||||
|
||||
it 'returns ActiveRecord::Relation' do
|
||||
expect(subject).to be_a(ActiveRecord::Relation)
|
||||
expect(subject).to contain_exactly(custom_emoji_0, custom_emoji_1)
|
||||
expect(subject).to contain_exactly(custom_emoji_domain_a, custom_emoji_domain_b)
|
||||
end
|
||||
end
|
||||
|
||||
@ -34,7 +34,7 @@ RSpec.describe CustomEmojiFilter do
|
||||
|
||||
it 'returns ActiveRecord::Relation' do
|
||||
expect(subject).to be_a(ActiveRecord::Relation)
|
||||
expect(subject).to contain_exactly(custom_emoji_0)
|
||||
expect(subject).to contain_exactly(custom_emoji_domain_a)
|
||||
end
|
||||
end
|
||||
|
||||
@ -43,7 +43,7 @@ RSpec.describe CustomEmojiFilter do
|
||||
|
||||
it 'returns ActiveRecord::Relation' do
|
||||
expect(subject).to be_a(ActiveRecord::Relation)
|
||||
expect(subject).to contain_exactly(custom_emoji_2)
|
||||
expect(subject).to contain_exactly(custom_emoji_domain_nil)
|
||||
end
|
||||
end
|
||||
|
||||
@ -63,7 +63,7 @@ RSpec.describe CustomEmojiFilter do
|
||||
|
||||
it 'returns ActiveRecord::Relation' do
|
||||
expect(subject).to be_a(ActiveRecord::Relation)
|
||||
expect(subject).to contain_exactly(custom_emoji_0, custom_emoji_1, custom_emoji_2)
|
||||
expect(subject).to contain_exactly(custom_emoji_domain_a, custom_emoji_domain_b, custom_emoji_domain_nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -341,82 +341,82 @@ RSpec.describe Status do
|
||||
end
|
||||
|
||||
describe '.tagged_with' do
|
||||
let(:tag1) { Fabricate(:tag) }
|
||||
let(:tag2) { Fabricate(:tag) }
|
||||
let(:tag3) { Fabricate(:tag) }
|
||||
let!(:status1) { Fabricate(:status, tags: [tag1]) }
|
||||
let!(:status2) { Fabricate(:status, tags: [tag2]) }
|
||||
let!(:status3) { Fabricate(:status, tags: [tag3]) }
|
||||
let!(:status4) { Fabricate(:status, tags: []) }
|
||||
let!(:status5) { Fabricate(:status, tags: [tag1, tag2, tag3]) }
|
||||
let(:tag_cats) { Fabricate(:tag, name: 'cats') }
|
||||
let(:tag_dogs) { Fabricate(:tag, name: 'dogs') }
|
||||
let(:tag_zebras) { Fabricate(:tag, name: 'zebras') }
|
||||
let!(:status_with_tag_cats) { Fabricate(:status, tags: [tag_cats]) }
|
||||
let!(:status_with_tag_dogs) { Fabricate(:status, tags: [tag_dogs]) }
|
||||
let!(:status_tagged_with_zebras) { Fabricate(:status, tags: [tag_zebras]) }
|
||||
let!(:status_without_tags) { Fabricate(:status, tags: []) }
|
||||
let!(:status_with_all_tags) { Fabricate(:status, tags: [tag_cats, tag_dogs, tag_zebras]) }
|
||||
|
||||
context 'when given one tag' do
|
||||
it 'returns the expected statuses' do
|
||||
expect(described_class.tagged_with([tag1.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status1.id, status5.id)
|
||||
expect(described_class.tagged_with([tag2.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status2.id, status5.id)
|
||||
expect(described_class.tagged_with([tag3.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status3.id, status5.id)
|
||||
expect(described_class.tagged_with([tag_cats.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_tag_cats.id, status_with_all_tags.id)
|
||||
expect(described_class.tagged_with([tag_dogs.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_tag_dogs.id, status_with_all_tags.id)
|
||||
expect(described_class.tagged_with([tag_zebras.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_tagged_with_zebras.id, status_with_all_tags.id)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when given multiple tags' do
|
||||
it 'returns the expected statuses' do
|
||||
expect(described_class.tagged_with([tag1.id, tag2.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status1.id, status2.id, status5.id)
|
||||
expect(described_class.tagged_with([tag1.id, tag3.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status1.id, status3.id, status5.id)
|
||||
expect(described_class.tagged_with([tag2.id, tag3.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status2.id, status3.id, status5.id)
|
||||
expect(described_class.tagged_with([tag_cats.id, tag_dogs.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_tag_cats.id, status_with_tag_dogs.id, status_with_all_tags.id)
|
||||
expect(described_class.tagged_with([tag_cats.id, tag_zebras.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_tag_cats.id, status_tagged_with_zebras.id, status_with_all_tags.id)
|
||||
expect(described_class.tagged_with([tag_dogs.id, tag_zebras.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_tag_dogs.id, status_tagged_with_zebras.id, status_with_all_tags.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.tagged_with_all' do
|
||||
let(:tag1) { Fabricate(:tag) }
|
||||
let(:tag2) { Fabricate(:tag) }
|
||||
let(:tag3) { Fabricate(:tag) }
|
||||
let!(:status1) { Fabricate(:status, tags: [tag1]) }
|
||||
let!(:status2) { Fabricate(:status, tags: [tag2]) }
|
||||
let!(:status3) { Fabricate(:status, tags: [tag3]) }
|
||||
let!(:status4) { Fabricate(:status, tags: []) }
|
||||
let!(:status5) { Fabricate(:status, tags: [tag1, tag2]) }
|
||||
let(:tag_cats) { Fabricate(:tag, name: 'cats') }
|
||||
let(:tag_dogs) { Fabricate(:tag, name: 'dogs') }
|
||||
let(:tag_zebras) { Fabricate(:tag, name: 'zebras') }
|
||||
let!(:status_with_tag_cats) { Fabricate(:status, tags: [tag_cats]) }
|
||||
let!(:status_with_tag_dogs) { Fabricate(:status, tags: [tag_dogs]) }
|
||||
let!(:status_tagged_with_zebras) { Fabricate(:status, tags: [tag_zebras]) }
|
||||
let!(:status_without_tags) { Fabricate(:status, tags: []) }
|
||||
let!(:status_with_all_tags) { Fabricate(:status, tags: [tag_cats, tag_dogs]) }
|
||||
|
||||
context 'when given one tag' do
|
||||
it 'returns the expected statuses' do
|
||||
expect(described_class.tagged_with_all([tag1.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status1.id, status5.id)
|
||||
expect(described_class.tagged_with_all([tag2.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status2.id, status5.id)
|
||||
expect(described_class.tagged_with_all([tag3.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status3.id)
|
||||
expect(described_class.tagged_with_all([tag_cats.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_tag_cats.id, status_with_all_tags.id)
|
||||
expect(described_class.tagged_with_all([tag_dogs.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_tag_dogs.id, status_with_all_tags.id)
|
||||
expect(described_class.tagged_with_all([tag_zebras.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_tagged_with_zebras.id)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when given multiple tags' do
|
||||
it 'returns the expected statuses' do
|
||||
expect(described_class.tagged_with_all([tag1.id, tag2.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status5.id)
|
||||
expect(described_class.tagged_with_all([tag1.id, tag3.id]).reorder(:id).pluck(:id).uniq).to eq []
|
||||
expect(described_class.tagged_with_all([tag2.id, tag3.id]).reorder(:id).pluck(:id).uniq).to eq []
|
||||
expect(described_class.tagged_with_all([tag_cats.id, tag_dogs.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_all_tags.id)
|
||||
expect(described_class.tagged_with_all([tag_cats.id, tag_zebras.id]).reorder(:id).pluck(:id).uniq).to eq []
|
||||
expect(described_class.tagged_with_all([tag_dogs.id, tag_zebras.id]).reorder(:id).pluck(:id).uniq).to eq []
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.tagged_with_none' do
|
||||
let(:tag1) { Fabricate(:tag) }
|
||||
let(:tag2) { Fabricate(:tag) }
|
||||
let(:tag3) { Fabricate(:tag) }
|
||||
let!(:status1) { Fabricate(:status, tags: [tag1]) }
|
||||
let!(:status2) { Fabricate(:status, tags: [tag2]) }
|
||||
let!(:status3) { Fabricate(:status, tags: [tag3]) }
|
||||
let!(:status4) { Fabricate(:status, tags: []) }
|
||||
let!(:status5) { Fabricate(:status, tags: [tag1, tag2, tag3]) }
|
||||
let(:tag_cats) { Fabricate(:tag, name: 'cats') }
|
||||
let(:tag_dogs) { Fabricate(:tag, name: 'dogs') }
|
||||
let(:tag_zebras) { Fabricate(:tag, name: 'zebras') }
|
||||
let!(:status_with_tag_cats) { Fabricate(:status, tags: [tag_cats]) }
|
||||
let!(:status_with_tag_dogs) { Fabricate(:status, tags: [tag_dogs]) }
|
||||
let!(:status_tagged_with_zebras) { Fabricate(:status, tags: [tag_zebras]) }
|
||||
let!(:status_without_tags) { Fabricate(:status, tags: []) }
|
||||
let!(:status_with_all_tags) { Fabricate(:status, tags: [tag_cats, tag_dogs, tag_zebras]) }
|
||||
|
||||
context 'when given one tag' do
|
||||
it 'returns the expected statuses' do
|
||||
expect(described_class.tagged_with_none([tag1.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status2.id, status3.id, status4.id)
|
||||
expect(described_class.tagged_with_none([tag2.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status1.id, status3.id, status4.id)
|
||||
expect(described_class.tagged_with_none([tag3.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status1.id, status2.id, status4.id)
|
||||
expect(described_class.tagged_with_none([tag_cats.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_tag_dogs.id, status_tagged_with_zebras.id, status_without_tags.id)
|
||||
expect(described_class.tagged_with_none([tag_dogs.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_tag_cats.id, status_tagged_with_zebras.id, status_without_tags.id)
|
||||
expect(described_class.tagged_with_none([tag_zebras.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_tag_cats.id, status_with_tag_dogs.id, status_without_tags.id)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when given multiple tags' do
|
||||
it 'returns the expected statuses' do
|
||||
expect(described_class.tagged_with_none([tag1.id, tag2.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status3.id, status4.id)
|
||||
expect(described_class.tagged_with_none([tag1.id, tag3.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status2.id, status4.id)
|
||||
expect(described_class.tagged_with_none([tag2.id, tag3.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status1.id, status4.id)
|
||||
expect(described_class.tagged_with_none([tag_cats.id, tag_dogs.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_tagged_with_zebras.id, status_without_tags.id)
|
||||
expect(described_class.tagged_with_none([tag_cats.id, tag_zebras.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_tag_dogs.id, status_without_tags.id)
|
||||
expect(described_class.tagged_with_none([tag_dogs.id, tag_zebras.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_tag_cats.id, status_without_tags.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -5,65 +5,65 @@ require 'rails_helper'
|
||||
describe TagFeed, type: :service do
|
||||
describe '#get' do
|
||||
let(:account) { Fabricate(:account) }
|
||||
let(:tag1) { Fabricate(:tag) }
|
||||
let(:tag2) { Fabricate(:tag) }
|
||||
let!(:status1) { Fabricate(:status, tags: [tag1]) }
|
||||
let!(:status2) { Fabricate(:status, tags: [tag2]) }
|
||||
let!(:both) { Fabricate(:status, tags: [tag1, tag2]) }
|
||||
let(:tag_cats) { Fabricate(:tag, name: 'cats') }
|
||||
let(:tag_dogs) { Fabricate(:tag, name: 'dogs') }
|
||||
let!(:status_tagged_with_cats) { Fabricate(:status, tags: [tag_cats]) }
|
||||
let!(:status_tagged_with_dogs) { Fabricate(:status, tags: [tag_dogs]) }
|
||||
let!(:both) { Fabricate(:status, tags: [tag_cats, tag_dogs]) }
|
||||
|
||||
it 'can add tags in "any" mode' do
|
||||
results = described_class.new(tag1, nil, any: [tag2.name]).get(20)
|
||||
expect(results).to include status1
|
||||
expect(results).to include status2
|
||||
results = described_class.new(tag_cats, nil, any: [tag_dogs.name]).get(20)
|
||||
expect(results).to include status_tagged_with_cats
|
||||
expect(results).to include status_tagged_with_dogs
|
||||
expect(results).to include both
|
||||
end
|
||||
|
||||
it 'can remove tags in "all" mode' do
|
||||
results = described_class.new(tag1, nil, all: [tag2.name]).get(20)
|
||||
expect(results).to_not include status1
|
||||
expect(results).to_not include status2
|
||||
results = described_class.new(tag_cats, nil, all: [tag_dogs.name]).get(20)
|
||||
expect(results).to_not include status_tagged_with_cats
|
||||
expect(results).to_not include status_tagged_with_dogs
|
||||
expect(results).to include both
|
||||
end
|
||||
|
||||
it 'can remove tags in "none" mode' do
|
||||
results = described_class.new(tag1, nil, none: [tag2.name]).get(20)
|
||||
expect(results).to include status1
|
||||
expect(results).to_not include status2
|
||||
results = described_class.new(tag_cats, nil, none: [tag_dogs.name]).get(20)
|
||||
expect(results).to include status_tagged_with_cats
|
||||
expect(results).to_not include status_tagged_with_dogs
|
||||
expect(results).to_not include both
|
||||
end
|
||||
|
||||
it 'ignores an invalid mode' do
|
||||
results = described_class.new(tag1, nil, wark: [tag2.name]).get(20)
|
||||
expect(results).to include status1
|
||||
expect(results).to_not include status2
|
||||
results = described_class.new(tag_cats, nil, wark: [tag_dogs.name]).get(20)
|
||||
expect(results).to include status_tagged_with_cats
|
||||
expect(results).to_not include status_tagged_with_dogs
|
||||
expect(results).to include both
|
||||
end
|
||||
|
||||
it 'handles being passed non existent tag names' do
|
||||
results = described_class.new(tag1, nil, any: ['wark']).get(20)
|
||||
expect(results).to include status1
|
||||
expect(results).to_not include status2
|
||||
results = described_class.new(tag_cats, nil, any: ['wark']).get(20)
|
||||
expect(results).to include status_tagged_with_cats
|
||||
expect(results).to_not include status_tagged_with_dogs
|
||||
expect(results).to include both
|
||||
end
|
||||
|
||||
it 'can restrict to an account' do
|
||||
BlockService.new.call(account, status1.account)
|
||||
results = described_class.new(tag1, account, none: [tag2.name]).get(20)
|
||||
expect(results).to_not include status1
|
||||
BlockService.new.call(account, status_tagged_with_cats.account)
|
||||
results = described_class.new(tag_cats, account, none: [tag_dogs.name]).get(20)
|
||||
expect(results).to_not include status_tagged_with_cats
|
||||
end
|
||||
|
||||
it 'can restrict to local' do
|
||||
status1.account.update(domain: 'example.com')
|
||||
status1.update(local: false, uri: 'example.com/toot')
|
||||
results = described_class.new(tag1, nil, any: [tag2.name], local: true).get(20)
|
||||
expect(results).to_not include status1
|
||||
status_tagged_with_cats.account.update(domain: 'example.com')
|
||||
status_tagged_with_cats.update(local: false, uri: 'example.com/toot')
|
||||
results = described_class.new(tag_cats, nil, any: [tag_dogs.name], local: true).get(20)
|
||||
expect(results).to_not include status_tagged_with_cats
|
||||
end
|
||||
|
||||
it 'allows replies to be included' do
|
||||
original = Fabricate(:status)
|
||||
status = Fabricate(:status, tags: [tag1], in_reply_to_id: original.id)
|
||||
status = Fabricate(:status, tags: [tag_cats], in_reply_to_id: original.id)
|
||||
|
||||
results = described_class.new(tag1, nil).get(20)
|
||||
results = described_class.new(tag_cats, nil).get(20)
|
||||
expect(results).to include(status)
|
||||
end
|
||||
|
||||
|
@ -11,12 +11,12 @@ RSpec.describe Trends::Statuses do
|
||||
let!(:query) { subject.query }
|
||||
let!(:today) { at_time }
|
||||
|
||||
let!(:status1) { Fabricate(:status, text: 'Foo', language: 'en', trendable: true, created_at: today) }
|
||||
let!(:status2) { Fabricate(:status, text: 'Bar', language: 'en', trendable: true, created_at: today) }
|
||||
let!(:status_foo) { Fabricate(:status, text: 'Foo', language: 'en', trendable: true, created_at: today) }
|
||||
let!(:status_bar) { Fabricate(:status, text: 'Bar', language: 'en', trendable: true, created_at: today) }
|
||||
|
||||
before do
|
||||
15.times { reblog(status1, today) }
|
||||
12.times { reblog(status2, today) }
|
||||
default_threshold_value.times { reblog(status_foo, today) }
|
||||
default_threshold_value.times { reblog(status_bar, today) }
|
||||
|
||||
subject.refresh(today)
|
||||
end
|
||||
@ -29,18 +29,18 @@ RSpec.describe Trends::Statuses do
|
||||
end
|
||||
|
||||
it 'filters out blocked accounts' do
|
||||
account.block!(status1.account)
|
||||
expect(query.filtered_for(account).to_a).to eq [status2]
|
||||
account.block!(status_foo.account)
|
||||
expect(query.filtered_for(account).to_a).to eq [status_bar]
|
||||
end
|
||||
|
||||
it 'filters out muted accounts' do
|
||||
account.mute!(status2.account)
|
||||
expect(query.filtered_for(account).to_a).to eq [status1]
|
||||
account.mute!(status_bar.account)
|
||||
expect(query.filtered_for(account).to_a).to eq [status_foo]
|
||||
end
|
||||
|
||||
it 'filters out blocked-by accounts' do
|
||||
status1.account.block!(account)
|
||||
expect(query.filtered_for(account).to_a).to eq [status2]
|
||||
status_foo.account.block!(account)
|
||||
expect(query.filtered_for(account).to_a).to eq [status_bar]
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -71,14 +71,14 @@ RSpec.describe Trends::Statuses do
|
||||
let!(:today) { at_time }
|
||||
let!(:yesterday) { today - 1.day }
|
||||
|
||||
let!(:status1) { Fabricate(:status, text: 'Foo', language: 'en', trendable: true, created_at: yesterday) }
|
||||
let!(:status2) { Fabricate(:status, text: 'Bar', language: 'en', trendable: true, created_at: today) }
|
||||
let!(:status3) { Fabricate(:status, text: 'Baz', language: 'en', trendable: true, created_at: today) }
|
||||
let!(:status_foo) { Fabricate(:status, text: 'Foo', language: 'en', trendable: true, created_at: yesterday) }
|
||||
let!(:status_bar) { Fabricate(:status, text: 'Bar', language: 'en', trendable: true, created_at: today) }
|
||||
let!(:status_baz) { Fabricate(:status, text: 'Baz', language: 'en', trendable: true, created_at: today) }
|
||||
|
||||
before do
|
||||
13.times { reblog(status1, today) }
|
||||
13.times { reblog(status2, today) }
|
||||
4.times { reblog(status3, today) }
|
||||
default_threshold_value.times { reblog(status_foo, today) }
|
||||
default_threshold_value.times { reblog(status_bar, today) }
|
||||
(default_threshold_value - 1).times { reblog(status_baz, today) }
|
||||
end
|
||||
|
||||
context 'when status trends are refreshed' do
|
||||
@ -86,21 +86,20 @@ RSpec.describe Trends::Statuses do
|
||||
subject.refresh(today)
|
||||
end
|
||||
|
||||
it 'calculates and re-calculates scores' do
|
||||
expect(subject.query.limit(10).to_a).to eq [status2, status1]
|
||||
end
|
||||
it 'returns correct statuses from query' do
|
||||
results = subject.query.limit(10).to_a
|
||||
|
||||
it 'omits statuses below threshold' do
|
||||
expect(subject.query.limit(10).to_a).to_not include(status3)
|
||||
expect(results).to eq [status_bar, status_foo]
|
||||
expect(results).to_not include(status_baz)
|
||||
end
|
||||
end
|
||||
|
||||
it 'decays scores' do
|
||||
subject.refresh(today)
|
||||
original_score = status2.trend.score
|
||||
original_score = status_bar.trend.score
|
||||
expect(original_score).to be_a Float
|
||||
subject.refresh(today + subject.options[:score_halflife])
|
||||
decayed_score = status2.trend.reload.score
|
||||
decayed_score = status_bar.trend.reload.score
|
||||
expect(decayed_score).to be <= original_score / 2
|
||||
end
|
||||
end
|
||||
@ -109,4 +108,8 @@ RSpec.describe Trends::Statuses do
|
||||
reblog = Fabricate(:status, reblog: status, created_at: at_time)
|
||||
subject.add(status, reblog.account_id, at_time)
|
||||
end
|
||||
|
||||
def default_threshold_value
|
||||
described_class.default_options[:threshold]
|
||||
end
|
||||
end
|
||||
|
@ -33,15 +33,15 @@ RSpec.describe Trends::Tags do
|
||||
let!(:today) { at_time }
|
||||
let!(:yesterday) { today - 1.day }
|
||||
|
||||
let!(:tag1) { Fabricate(:tag, name: 'Catstodon', trendable: true) }
|
||||
let!(:tag2) { Fabricate(:tag, name: 'DogsOfMastodon', trendable: true) }
|
||||
let!(:tag3) { Fabricate(:tag, name: 'OCs', trendable: true) }
|
||||
let!(:tag_cats) { Fabricate(:tag, name: 'Catstodon', trendable: true) }
|
||||
let!(:tag_dogs) { Fabricate(:tag, name: 'DogsOfMastodon', trendable: true) }
|
||||
let!(:tag_ocs) { Fabricate(:tag, name: 'OCs', trendable: true) }
|
||||
|
||||
before do
|
||||
2.times { |i| subject.add(tag1, i, yesterday) }
|
||||
13.times { |i| subject.add(tag3, i, yesterday) }
|
||||
16.times { |i| subject.add(tag1, i, today) }
|
||||
4.times { |i| subject.add(tag2, i, today) }
|
||||
2.times { |i| subject.add(tag_cats, i, yesterday) }
|
||||
13.times { |i| subject.add(tag_ocs, i, yesterday) }
|
||||
16.times { |i| subject.add(tag_cats, i, today) }
|
||||
4.times { |i| subject.add(tag_dogs, i, today) }
|
||||
end
|
||||
|
||||
context 'when tag trends are refreshed' do
|
||||
@ -51,20 +51,20 @@ RSpec.describe Trends::Tags do
|
||||
end
|
||||
|
||||
it 'calculates and re-calculates scores' do
|
||||
expect(subject.query.limit(10).to_a).to eq [tag1, tag3]
|
||||
expect(subject.query.limit(10).to_a).to eq [tag_cats, tag_ocs]
|
||||
end
|
||||
|
||||
it 'omits hashtags below threshold' do
|
||||
expect(subject.query.limit(10).to_a).to_not include(tag2)
|
||||
expect(subject.query.limit(10).to_a).to_not include(tag_dogs)
|
||||
end
|
||||
end
|
||||
|
||||
it 'decays scores' do
|
||||
subject.refresh(yesterday + 12.hours)
|
||||
original_score = subject.score(tag3.id)
|
||||
original_score = subject.score(tag_ocs.id)
|
||||
expect(original_score).to eq 144.0
|
||||
subject.refresh(yesterday + 12.hours + subject.options[:max_score_halflife])
|
||||
decayed_score = subject.score(tag3.id)
|
||||
decayed_score = subject.score(tag_ocs.id)
|
||||
expect(decayed_score).to be <= original_score / 2
|
||||
end
|
||||
end
|
||||
|
@ -9,26 +9,6 @@ RSpec.describe 'Canonical Email Blocks' do
|
||||
let(:scopes) { 'admin:read:canonical_email_blocks admin:write:canonical_email_blocks' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope|
|
||||
let(:scopes) { wrong_scope }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role|
|
||||
let(:role) { UserRole.find_by(name: wrong_role) }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v1/admin/canonical_email_blocks' do
|
||||
subject do
|
||||
get '/api/v1/admin/canonical_email_blocks', headers: headers, params: params
|
||||
|
@ -9,26 +9,6 @@ RSpec.describe 'Domain Allows' do
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope|
|
||||
let(:scopes) { wrong_scope }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role|
|
||||
let(:role) { UserRole.find_by(name: wrong_role) }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v1/admin/domain_allows' do
|
||||
subject do
|
||||
get '/api/v1/admin/domain_allows', headers: headers, params: params
|
||||
|
@ -9,26 +9,6 @@ RSpec.describe 'Domain Blocks' do
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope|
|
||||
let(:scopes) { wrong_scope }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role|
|
||||
let(:role) { UserRole.find_by(name: wrong_role) }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v1/admin/domain_blocks' do
|
||||
subject do
|
||||
get '/api/v1/admin/domain_blocks', headers: headers, params: params
|
||||
|
@ -10,26 +10,6 @@ RSpec.describe 'Email Domain Blocks' do
|
||||
let(:scopes) { 'admin:read:email_domain_blocks admin:write:email_domain_blocks' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope|
|
||||
let(:scopes) { wrong_scope }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role|
|
||||
let(:role) { UserRole.find_by(name: wrong_role) }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v1/admin/email_domain_blocks' do
|
||||
subject do
|
||||
get '/api/v1/admin/email_domain_blocks', headers: headers, params: params
|
||||
|
@ -9,26 +9,6 @@ RSpec.describe 'IP Blocks' do
|
||||
let(:scopes) { 'admin:read:ip_blocks admin:write:ip_blocks' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope|
|
||||
let(:scopes) { wrong_scope }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role|
|
||||
let(:role) { UserRole.find_by(name: wrong_role) }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v1/admin/ip_blocks' do
|
||||
subject do
|
||||
get '/api/v1/admin/ip_blocks', headers: headers, params: params
|
||||
|
@ -9,26 +9,6 @@ RSpec.describe 'Reports' do
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope|
|
||||
let(:scopes) { wrong_scope }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role|
|
||||
let(:role) { UserRole.find_by(name: wrong_role) }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v1/admin/reports' do
|
||||
subject do
|
||||
get '/api/v1/admin/reports', headers: headers, params: params
|
||||
|
44
spec/requests/api/v1/apps/credentials_spec.rb
Normal file
44
spec/requests/api/v1/apps/credentials_spec.rb
Normal file
@ -0,0 +1,44 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe 'Credentials' do
|
||||
describe 'GET /api/v1/apps/verify_credentials' do
|
||||
subject do
|
||||
get '/api/v1/apps/verify_credentials', headers: headers
|
||||
end
|
||||
|
||||
context 'with an oauth token' do
|
||||
let(:token) { Fabricate(:accessible_access_token, scopes: 'read', application: Fabricate(:application)) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the app information correctly' do
|
||||
subject
|
||||
|
||||
expect(body_as_json).to match(
|
||||
a_hash_including(
|
||||
name: token.application.name,
|
||||
website: token.application.website,
|
||||
vapid_key: Rails.configuration.x.vapid_public_key
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'without an oauth token' do
|
||||
let(:headers) { {} }
|
||||
|
||||
it 'returns http unauthorized' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(401)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -2,16 +2,18 @@
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Api::V1::AppsController do
|
||||
render_views
|
||||
RSpec.describe 'Apps' do
|
||||
describe 'POST /api/v1/apps' do
|
||||
subject do
|
||||
post '/api/v1/apps', params: params
|
||||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
let(:client_name) { 'Test app' }
|
||||
let(:scopes) { nil }
|
||||
let(:client_name) { 'Test app' }
|
||||
let(:scopes) { nil }
|
||||
let(:redirect_uris) { 'urn:ietf:wg:oauth:2.0:oob' }
|
||||
let(:website) { nil }
|
||||
let(:website) { nil }
|
||||
|
||||
let(:app_params) do
|
||||
let(:params) do
|
||||
{
|
||||
client_name: client_name,
|
||||
redirect_uris: redirect_uris,
|
||||
@ -20,24 +22,26 @@ RSpec.describe Api::V1::AppsController do
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
post :create, params: app_params
|
||||
end
|
||||
|
||||
context 'with valid params' do
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'creates an OAuth app' do
|
||||
expect(Doorkeeper::Application.find_by(name: client_name)).to_not be_nil
|
||||
subject
|
||||
|
||||
expect(Doorkeeper::Application.find_by(name: client_name)).to be_present
|
||||
end
|
||||
|
||||
it 'returns client ID and client secret' do
|
||||
json = body_as_json
|
||||
subject
|
||||
|
||||
expect(json[:client_id]).to_not be_blank
|
||||
expect(json[:client_secret]).to_not be_blank
|
||||
body = body_as_json
|
||||
|
||||
expect(body[:client_id]).to be_present
|
||||
expect(body[:client_secret]).to be_present
|
||||
end
|
||||
end
|
||||
|
||||
@ -45,6 +49,8 @@ RSpec.describe Api::V1::AppsController do
|
||||
let(:scopes) { 'hoge' }
|
||||
|
||||
it 'returns http unprocessable entity' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
end
|
||||
end
|
||||
@ -53,10 +59,14 @@ RSpec.describe Api::V1::AppsController do
|
||||
let(:scopes) { (%w(read) * 40).join(' ') }
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'only saves the scope once' do
|
||||
subject
|
||||
|
||||
expect(Doorkeeper::Application.find_by(name: client_name).scopes.to_s).to eq 'read'
|
||||
end
|
||||
end
|
||||
@ -65,6 +75,8 @@ RSpec.describe Api::V1::AppsController do
|
||||
let(:client_name) { 'hoge' * 20 }
|
||||
|
||||
it 'returns http unprocessable entity' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
end
|
||||
end
|
||||
@ -73,6 +85,8 @@ RSpec.describe Api::V1::AppsController do
|
||||
let(:website) { "https://foo.bar/#{'hoge' * 2_000}" }
|
||||
|
||||
it 'returns http unprocessable entity' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
end
|
||||
end
|
||||
@ -81,6 +95,19 @@ RSpec.describe Api::V1::AppsController do
|
||||
let(:redirect_uris) { "https://foo.bar/#{'hoge' * 2_000}" }
|
||||
|
||||
it 'returns http unprocessable entity' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
end
|
||||
end
|
||||
|
||||
context 'without required params' do
|
||||
let(:client_name) { '' }
|
||||
let(:redirect_uris) { '' }
|
||||
|
||||
it 'returns http unprocessable entity' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
end
|
||||
end
|
125
spec/requests/api/v1/domain_blocks_spec.rb
Normal file
125
spec/requests/api/v1/domain_blocks_spec.rb
Normal file
@ -0,0 +1,125 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Domain blocks' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:blocks write:blocks' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
describe 'GET /api/v1/domain_blocks' do
|
||||
subject do
|
||||
get '/api/v1/domain_blocks', headers: headers, params: params
|
||||
end
|
||||
|
||||
let(:blocked_domains) { ['example.com', 'example.net', 'example.org', 'example.com.br'] }
|
||||
let(:params) { {} }
|
||||
|
||||
before do
|
||||
blocked_domains.each { |domain| user.account.block_domain!(domain) }
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:blocks'
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the domains blocked by the requesting user' do
|
||||
subject
|
||||
|
||||
expect(body_as_json).to match_array(blocked_domains)
|
||||
end
|
||||
|
||||
context 'with limit param' do
|
||||
let(:params) { { limit: 2 } }
|
||||
|
||||
it 'returns only the requested number of blocked domains' do
|
||||
subject
|
||||
|
||||
expect(body_as_json.size).to eq(params[:limit])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/domain_blocks' do
|
||||
subject do
|
||||
post '/api/v1/domain_blocks', headers: headers, params: params
|
||||
end
|
||||
|
||||
let(:params) { { domain: 'example.com' } }
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:blocks'
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'creates a domain block' do
|
||||
subject
|
||||
|
||||
expect(user.account.domain_blocking?(params[:domain])).to be(true)
|
||||
end
|
||||
|
||||
context 'when no domain name is given' do
|
||||
let(:params) { { domain: '' } }
|
||||
|
||||
it 'returns http unprocessable entity' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the given domain name is invalid' do
|
||||
let(:params) { { domain: 'example com' } }
|
||||
|
||||
it 'returns unprocessable entity' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE /api/v1/domain_blocks' do
|
||||
subject do
|
||||
delete '/api/v1/domain_blocks/', headers: headers, params: params
|
||||
end
|
||||
|
||||
let(:params) { { domain: 'example.com' } }
|
||||
|
||||
before do
|
||||
user.account.block_domain!('example.com')
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:blocks'
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'deletes the specified domain block' do
|
||||
subject
|
||||
|
||||
expect(user.account.domain_blocking?('example.com')).to be(false)
|
||||
end
|
||||
|
||||
context 'when the given domain name is not blocked' do
|
||||
let(:params) { { domain: 'example.org' } }
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -8,14 +8,6 @@ RSpec.describe 'FeaturedTags' do
|
||||
let(:scopes) { 'read:accounts write:accounts' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope|
|
||||
let(:scopes) { wrong_scope }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v1/featured_tags' do
|
||||
context 'with wrong scope' do
|
||||
before do
|
||||
|
119
spec/requests/api/v1/follow_requests_spec.rb
Normal file
119
spec/requests/api/v1/follow_requests_spec.rb
Normal file
@ -0,0 +1,119 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Follow requests' do
|
||||
let(:user) { Fabricate(:user, account_attributes: { locked: true }) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:follows write:follows' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
describe 'GET /api/v1/follow_requests' do
|
||||
subject do
|
||||
get '/api/v1/follow_requests', headers: headers, params: params
|
||||
end
|
||||
|
||||
let(:accounts) { Fabricate.times(5, :account) }
|
||||
let(:params) { {} }
|
||||
|
||||
let(:expected_response) do
|
||||
accounts.map do |account|
|
||||
a_hash_including(
|
||||
id: account.id.to_s,
|
||||
username: account.username,
|
||||
acct: account.acct
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
accounts.each { |account| FollowService.new.call(account, user.account) }
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:follows'
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the expected content from accounts requesting to follow' do
|
||||
subject
|
||||
|
||||
expect(body_as_json).to match_array(expected_response)
|
||||
end
|
||||
|
||||
context 'with limit param' do
|
||||
let(:params) { { limit: 2 } }
|
||||
|
||||
it 'returns only the requested number of follow requests' do
|
||||
subject
|
||||
|
||||
expect(body_as_json.size).to eq(params[:limit])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/follow_requests/:account_id/authorize' do
|
||||
subject do
|
||||
post "/api/v1/follow_requests/#{follower.id}/authorize", headers: headers
|
||||
end
|
||||
|
||||
let(:follower) { Fabricate(:account) }
|
||||
|
||||
before do
|
||||
FollowService.new.call(follower, user.account)
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:follows'
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'allows the requesting follower to follow' do
|
||||
expect { subject }.to change { follower.following?(user.account) }.from(false).to(true)
|
||||
end
|
||||
|
||||
it 'returns JSON with followed_by set to true' do
|
||||
subject
|
||||
|
||||
expect(body_as_json[:followed_by]).to be true
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/follow_requests/:account_id/reject' do
|
||||
subject do
|
||||
post "/api/v1/follow_requests/#{follower.id}/reject", headers: headers
|
||||
end
|
||||
|
||||
let(:follower) { Fabricate(:account) }
|
||||
|
||||
before do
|
||||
FollowService.new.call(follower, user.account)
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:follows'
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'removes the follow request' do
|
||||
subject
|
||||
|
||||
expect(FollowRequest.where(target_account: user.account, account: follower)).to_not exist
|
||||
end
|
||||
|
||||
it 'returns JSON with followed_by set to false' do
|
||||
subject
|
||||
|
||||
expect(body_as_json[:followed_by]).to be false
|
||||
end
|
||||
end
|
||||
end
|
247
spec/requests/api/v1/lists_spec.rb
Normal file
247
spec/requests/api/v1/lists_spec.rb
Normal file
@ -0,0 +1,247 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Lists' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:lists write:lists' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
describe 'GET /api/v1/lists' do
|
||||
subject do
|
||||
get '/api/v1/lists', headers: headers
|
||||
end
|
||||
|
||||
let!(:lists) do
|
||||
[
|
||||
Fabricate(:list, account: user.account, title: 'first list', replies_policy: :followed),
|
||||
Fabricate(:list, account: user.account, title: 'second list', replies_policy: :list),
|
||||
Fabricate(:list, account: user.account, title: 'third list', replies_policy: :none),
|
||||
Fabricate(:list, account: user.account, title: 'fourth list', exclusive: true),
|
||||
]
|
||||
end
|
||||
|
||||
let(:expected_response) do
|
||||
lists.map do |list|
|
||||
{
|
||||
id: list.id.to_s,
|
||||
title: list.title,
|
||||
replies_policy: list.replies_policy,
|
||||
exclusive: list.exclusive,
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
Fabricate(:list)
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:lists'
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the expected lists' do
|
||||
subject
|
||||
|
||||
expect(body_as_json).to match_array(expected_response)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v1/lists/:id' do
|
||||
subject do
|
||||
get "/api/v1/lists/#{list.id}", headers: headers
|
||||
end
|
||||
|
||||
let(:list) { Fabricate(:list, account: user.account) }
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:lists'
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the requested list correctly' do
|
||||
subject
|
||||
|
||||
expect(body_as_json).to eq({
|
||||
id: list.id.to_s,
|
||||
title: list.title,
|
||||
replies_policy: list.replies_policy,
|
||||
exclusive: list.exclusive,
|
||||
})
|
||||
end
|
||||
|
||||
context 'when the list belongs to a different user' do
|
||||
let(:list) { Fabricate(:list) }
|
||||
|
||||
it 'returns http not found' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the list does not exist' do
|
||||
it 'returns http not found' do
|
||||
get '/api/v1/lists/-1', headers: headers
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/lists' do
|
||||
subject do
|
||||
post '/api/v1/lists', headers: headers, params: params
|
||||
end
|
||||
|
||||
let(:params) { { title: 'my list', replies_policy: 'none', exclusive: 'true' } }
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:lists'
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the new list' do
|
||||
subject
|
||||
|
||||
expect(body_as_json).to match(a_hash_including(title: 'my list', replies_policy: 'none', exclusive: true))
|
||||
end
|
||||
|
||||
it 'creates a list' do
|
||||
subject
|
||||
|
||||
expect(List.where(account: user.account).count).to eq(1)
|
||||
end
|
||||
|
||||
context 'when a title is not given' do
|
||||
let(:params) { { title: '' } }
|
||||
|
||||
it 'returns http unprocessable entity' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the given replies_policy is invalid' do
|
||||
let(:params) { { title: 'a list', replies_policy: 'whatever' } }
|
||||
|
||||
it 'returns http unprocessable entity' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT /api/v1/lists/:id' do
|
||||
subject do
|
||||
put "/api/v1/lists/#{list.id}", headers: headers, params: params
|
||||
end
|
||||
|
||||
let(:list) { Fabricate(:list, account: user.account, title: 'my list') }
|
||||
let(:params) { { title: 'list', replies_policy: 'followed', exclusive: 'true' } }
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:lists'
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the updated list' do
|
||||
subject
|
||||
|
||||
list.reload
|
||||
|
||||
expect(body_as_json).to eq({
|
||||
id: list.id.to_s,
|
||||
title: list.title,
|
||||
replies_policy: list.replies_policy,
|
||||
exclusive: list.exclusive,
|
||||
})
|
||||
end
|
||||
|
||||
it 'updates the list title' do
|
||||
expect { subject }.to change { list.reload.title }.from('my list').to('list')
|
||||
end
|
||||
|
||||
it 'updates the list replies_policy' do
|
||||
expect { subject }.to change { list.reload.replies_policy }.from('list').to('followed')
|
||||
end
|
||||
|
||||
it 'updates the list exclusive' do
|
||||
expect { subject }.to change { list.reload.exclusive }.from(false).to(true)
|
||||
end
|
||||
|
||||
context 'when the list does not exist' do
|
||||
it 'returns http not found' do
|
||||
put '/api/v1/lists/-1', headers: headers, params: params
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the list belongs to another user' do
|
||||
let(:list) { Fabricate(:list) }
|
||||
|
||||
it 'returns http not found' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE /api/v1/lists/:id' do
|
||||
subject do
|
||||
delete "/api/v1/lists/#{list.id}", headers: headers
|
||||
end
|
||||
|
||||
let(:list) { Fabricate(:list, account: user.account) }
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:lists'
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'deletes the list' do
|
||||
subject
|
||||
|
||||
expect(List.where(id: list.id)).to_not exist
|
||||
end
|
||||
|
||||
context 'when the list does not exist' do
|
||||
it 'returns http not found' do
|
||||
delete '/api/v1/lists/-1', headers: headers
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the list belongs to another user' do
|
||||
let(:list) { Fabricate(:list) }
|
||||
|
||||
it 'returns http not found' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -6,13 +6,13 @@ describe ActivityPub::NoteSerializer do
|
||||
subject { JSON.parse(@serialization.to_json) }
|
||||
|
||||
let!(:account) { Fabricate(:account) }
|
||||
let!(:other) { Fabricate(:account) }
|
||||
let!(:parent) { Fabricate(:status, account: account, visibility: :public) }
|
||||
let!(:reply1) { Fabricate(:status, account: account, thread: parent, visibility: :public) }
|
||||
let!(:reply2) { Fabricate(:status, account: account, thread: parent, visibility: :public) }
|
||||
let!(:reply3) { Fabricate(:status, account: other, thread: parent, visibility: :public) }
|
||||
let!(:reply4) { Fabricate(:status, account: account, thread: parent, visibility: :public) }
|
||||
let!(:reply5) { Fabricate(:status, account: account, thread: parent, visibility: :direct) }
|
||||
let!(:other) { Fabricate(:account) }
|
||||
let!(:parent) { Fabricate(:status, account: account, visibility: :public) }
|
||||
let!(:reply_by_account_first) { Fabricate(:status, account: account, thread: parent, visibility: :public) }
|
||||
let!(:reply_by_account_next) { Fabricate(:status, account: account, thread: parent, visibility: :public) }
|
||||
let!(:reply_by_other_first) { Fabricate(:status, account: other, thread: parent, visibility: :public) }
|
||||
let!(:reply_by_account_third) { Fabricate(:status, account: account, thread: parent, visibility: :public) }
|
||||
let!(:reply_by_account_visibility_direct) { Fabricate(:status, account: account, thread: parent, visibility: :direct) }
|
||||
|
||||
before(:each) do
|
||||
@serialization = ActiveModelSerializers::SerializableResource.new(parent, serializer: described_class, adapter: ActivityPub::Adapter)
|
||||
@ -31,14 +31,14 @@ describe ActivityPub::NoteSerializer do
|
||||
end
|
||||
|
||||
it 'includes public self-replies in its replies collection' do
|
||||
expect(subject['replies']['first']['items']).to include(reply1.uri, reply2.uri, reply4.uri)
|
||||
expect(subject['replies']['first']['items']).to include(reply_by_account_first.uri, reply_by_account_next.uri, reply_by_account_third.uri)
|
||||
end
|
||||
|
||||
it 'does not include replies from others in its replies collection' do
|
||||
expect(subject['replies']['first']['items']).to_not include(reply3.uri)
|
||||
expect(subject['replies']['first']['items']).to_not include(reply_by_other_first.uri)
|
||||
end
|
||||
|
||||
it 'does not include replies with direct visibility in its replies collection' do
|
||||
expect(subject['replies']['first']['items']).to_not include(reply5.uri)
|
||||
expect(subject['replies']['first']['items']).to_not include(reply_by_account_visibility_direct.uri)
|
||||
end
|
||||
end
|
||||
|
@ -9,33 +9,33 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
|
||||
|
||||
let!(:known_status) { Fabricate(:status, account: actor, uri: 'https://example.com/account/pinned/1') }
|
||||
|
||||
let(:status_json_1) do
|
||||
let(:status_json_pinned_known) do
|
||||
{
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
type: 'Note',
|
||||
id: 'https://example.com/account/pinned/1',
|
||||
id: 'https://example.com/account/pinned/known',
|
||||
content: 'foo',
|
||||
attributedTo: actor.uri,
|
||||
to: 'https://www.w3.org/ns/activitystreams#Public',
|
||||
}
|
||||
end
|
||||
|
||||
let(:status_json_2) do
|
||||
let(:status_json_pinned_unknown_inlined) do
|
||||
{
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
type: 'Note',
|
||||
id: 'https://example.com/account/pinned/2',
|
||||
id: 'https://example.com/account/pinned/unknown-inlined',
|
||||
content: 'foo',
|
||||
attributedTo: actor.uri,
|
||||
to: 'https://www.w3.org/ns/activitystreams#Public',
|
||||
}
|
||||
end
|
||||
|
||||
let(:status_json_4) do
|
||||
let(:status_json_pinned_unknown_unreachable) do
|
||||
{
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
type: 'Note',
|
||||
id: 'https://example.com/account/pinned/4',
|
||||
id: 'https://example.com/account/pinned/unknown-reachable',
|
||||
content: 'foo',
|
||||
attributedTo: actor.uri,
|
||||
to: 'https://www.w3.org/ns/activitystreams#Public',
|
||||
@ -44,10 +44,10 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
|
||||
|
||||
let(:items) do
|
||||
[
|
||||
'https://example.com/account/pinned/1', # known
|
||||
status_json_2, # unknown inlined
|
||||
'https://example.com/account/pinned/3', # unknown unreachable
|
||||
'https://example.com/account/pinned/4', # unknown reachable
|
||||
'https://example.com/account/pinned/known', # known
|
||||
status_json_pinned_unknown_inlined, # unknown inlined
|
||||
'https://example.com/account/pinned/unknown-unreachable', # unknown unreachable
|
||||
'https://example.com/account/pinned/unknown-reachable', # unknown reachable
|
||||
]
|
||||
end
|
||||
|
||||
@ -62,16 +62,20 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
|
||||
|
||||
shared_examples 'sets pinned posts' do
|
||||
before do
|
||||
stub_request(:get, 'https://example.com/account/pinned/1').to_return(status: 200, body: Oj.dump(status_json_1))
|
||||
stub_request(:get, 'https://example.com/account/pinned/2').to_return(status: 200, body: Oj.dump(status_json_2))
|
||||
stub_request(:get, 'https://example.com/account/pinned/3').to_return(status: 404)
|
||||
stub_request(:get, 'https://example.com/account/pinned/4').to_return(status: 200, body: Oj.dump(status_json_4))
|
||||
stub_request(:get, 'https://example.com/account/pinned/known').to_return(status: 200, body: Oj.dump(status_json_pinned_known))
|
||||
stub_request(:get, 'https://example.com/account/pinned/unknown-inlined').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_inlined))
|
||||
stub_request(:get, 'https://example.com/account/pinned/unknown-unreachable').to_return(status: 404)
|
||||
stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_unreachable))
|
||||
|
||||
subject.call(actor, note: true, hashtag: false)
|
||||
end
|
||||
|
||||
it 'sets expected posts as pinned posts' do
|
||||
expect(actor.pinned_statuses.pluck(:uri)).to contain_exactly('https://example.com/account/pinned/1', 'https://example.com/account/pinned/2', 'https://example.com/account/pinned/4')
|
||||
expect(actor.pinned_statuses.pluck(:uri)).to contain_exactly(
|
||||
'https://example.com/account/pinned/known',
|
||||
'https://example.com/account/pinned/unknown-inlined',
|
||||
'https://example.com/account/pinned/unknown-reachable'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -10,8 +10,8 @@ RSpec.describe BatchedRemoveStatusService, type: :service do
|
||||
let!(:jeff) { Fabricate(:account) }
|
||||
let!(:hank) { Fabricate(:account, username: 'hank', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') }
|
||||
|
||||
let(:status1) { PostStatusService.new.call(alice, text: 'Hello @bob@example.com') }
|
||||
let(:status2) { PostStatusService.new.call(alice, text: 'Another status') }
|
||||
let(:status_alice_hello) { PostStatusService.new.call(alice, text: 'Hello @bob@example.com') }
|
||||
let(:status_alice_other) { PostStatusService.new.call(alice, text: 'Another status') }
|
||||
|
||||
before do
|
||||
allow(redis).to receive_messages(publish: nil)
|
||||
@ -22,23 +22,23 @@ RSpec.describe BatchedRemoveStatusService, type: :service do
|
||||
jeff.follow!(alice)
|
||||
hank.follow!(alice)
|
||||
|
||||
status1
|
||||
status2
|
||||
status_alice_hello
|
||||
status_alice_other
|
||||
|
||||
subject.call([status1, status2])
|
||||
subject.call([status_alice_hello, status_alice_other])
|
||||
end
|
||||
|
||||
it 'removes statuses' do
|
||||
expect { Status.find(status1.id) }.to raise_error ActiveRecord::RecordNotFound
|
||||
expect { Status.find(status2.id) }.to raise_error ActiveRecord::RecordNotFound
|
||||
expect { Status.find(status_alice_hello.id) }.to raise_error ActiveRecord::RecordNotFound
|
||||
expect { Status.find(status_alice_other.id) }.to raise_error ActiveRecord::RecordNotFound
|
||||
end
|
||||
|
||||
it 'removes statuses from author\'s home feed' do
|
||||
expect(HomeFeed.new(alice).get(10)).to_not include([status1.id, status2.id])
|
||||
expect(HomeFeed.new(alice).get(10)).to_not include([status_alice_hello.id, status_alice_other.id])
|
||||
end
|
||||
|
||||
it 'removes statuses from local follower\'s home feed' do
|
||||
expect(HomeFeed.new(jeff).get(10)).to_not include([status1.id, status2.id])
|
||||
expect(HomeFeed.new(jeff).get(10)).to_not include([status_alice_hello.id, status_alice_other.id])
|
||||
end
|
||||
|
||||
it 'notifies streaming API of followers' do
|
||||
|
@ -6,9 +6,9 @@ RSpec.describe BlockDomainService, type: :service do
|
||||
subject { described_class.new }
|
||||
|
||||
let!(:bad_account) { Fabricate(:account, username: 'badguy666', domain: 'evil.org') }
|
||||
let!(:bad_status1) { Fabricate(:status, account: bad_account, text: 'You suck') }
|
||||
let!(:bad_status2) { Fabricate(:status, account: bad_account, text: 'Hahaha') }
|
||||
let!(:bad_attachment) { Fabricate(:media_attachment, account: bad_account, status: bad_status2, file: attachment_fixture('attachment.jpg')) }
|
||||
let!(:bad_status_plain) { Fabricate(:status, account: bad_account, text: 'You suck') }
|
||||
let!(:bad_status_with_attachment) { Fabricate(:status, account: bad_account, text: 'Hahaha') }
|
||||
let!(:bad_attachment) { Fabricate(:media_attachment, account: bad_account, status: bad_status_with_attachment, file: attachment_fixture('attachment.jpg')) }
|
||||
let!(:already_banned_account) { Fabricate(:account, username: 'badguy', domain: 'evil.org', suspended: true, silenced: true) }
|
||||
|
||||
describe 'for a suspension' do
|
||||
@ -37,8 +37,8 @@ RSpec.describe BlockDomainService, type: :service do
|
||||
end
|
||||
|
||||
it 'removes the remote accounts\'s statuses and media attachments' do
|
||||
expect { bad_status1.reload }.to raise_exception ActiveRecord::RecordNotFound
|
||||
expect { bad_status2.reload }.to raise_exception ActiveRecord::RecordNotFound
|
||||
expect { bad_status_plain.reload }.to raise_exception ActiveRecord::RecordNotFound
|
||||
expect { bad_status_with_attachment.reload }.to raise_exception ActiveRecord::RecordNotFound
|
||||
expect { bad_attachment.reload }.to raise_exception ActiveRecord::RecordNotFound
|
||||
end
|
||||
end
|
||||
@ -69,8 +69,8 @@ RSpec.describe BlockDomainService, type: :service do
|
||||
end
|
||||
|
||||
it 'leaves the domains status and attachments, but clears media' do
|
||||
expect { bad_status1.reload }.to_not raise_error
|
||||
expect { bad_status2.reload }.to_not raise_error
|
||||
expect { bad_status_plain.reload }.to_not raise_error
|
||||
expect { bad_status_with_attachment.reload }.to_not raise_error
|
||||
expect { bad_attachment.reload }.to_not raise_error
|
||||
expect(bad_attachment.file.exists?).to be false
|
||||
end
|
||||
|
@ -6,9 +6,9 @@ RSpec.describe ClearDomainMediaService, type: :service do
|
||||
subject { described_class.new }
|
||||
|
||||
let!(:bad_account) { Fabricate(:account, username: 'badguy666', domain: 'evil.org') }
|
||||
let!(:bad_status1) { Fabricate(:status, account: bad_account, text: 'You suck') }
|
||||
let!(:bad_status2) { Fabricate(:status, account: bad_account, text: 'Hahaha') }
|
||||
let!(:bad_attachment) { Fabricate(:media_attachment, account: bad_account, status: bad_status2, file: attachment_fixture('attachment.jpg')) }
|
||||
let!(:bad_status_plain) { Fabricate(:status, account: bad_account, text: 'You suck') }
|
||||
let!(:bad_status_with_attachment) { Fabricate(:status, account: bad_account, text: 'Hahaha') }
|
||||
let!(:bad_attachment) { Fabricate(:media_attachment, account: bad_account, status: bad_status_with_attachment, file: attachment_fixture('attachment.jpg')) }
|
||||
|
||||
describe 'for a silence with reject media' do
|
||||
before do
|
||||
@ -16,8 +16,8 @@ RSpec.describe ClearDomainMediaService, type: :service do
|
||||
end
|
||||
|
||||
it 'leaves the domains status and attachments, but clears media' do
|
||||
expect { bad_status1.reload }.to_not raise_error
|
||||
expect { bad_status2.reload }.to_not raise_error
|
||||
expect { bad_status_plain.reload }.to_not raise_error
|
||||
expect { bad_status_with_attachment.reload }.to_not raise_error
|
||||
expect { bad_attachment.reload }.to_not raise_error
|
||||
expect(bad_attachment.file.exists?).to be false
|
||||
end
|
||||
|
@ -6,9 +6,9 @@ RSpec.describe PurgeDomainService, type: :service do
|
||||
subject { described_class.new }
|
||||
|
||||
let!(:old_account) { Fabricate(:account, domain: 'obsolete.org') }
|
||||
let!(:old_status1) { Fabricate(:status, account: old_account) }
|
||||
let!(:old_status2) { Fabricate(:status, account: old_account) }
|
||||
let!(:old_attachment) { Fabricate(:media_attachment, account: old_account, status: old_status2, file: attachment_fixture('attachment.jpg')) }
|
||||
let!(:old_status_plain) { Fabricate(:status, account: old_account) }
|
||||
let!(:old_status_with_attachment) { Fabricate(:status, account: old_account) }
|
||||
let!(:old_attachment) { Fabricate(:media_attachment, account: old_account, status: old_status_with_attachment, file: attachment_fixture('attachment.jpg')) }
|
||||
|
||||
describe 'for a suspension' do
|
||||
before do
|
||||
@ -17,8 +17,8 @@ RSpec.describe PurgeDomainService, type: :service do
|
||||
|
||||
it 'removes the remote accounts\'s statuses and media attachments' do
|
||||
expect { old_account.reload }.to raise_exception ActiveRecord::RecordNotFound
|
||||
expect { old_status1.reload }.to raise_exception ActiveRecord::RecordNotFound
|
||||
expect { old_status2.reload }.to raise_exception ActiveRecord::RecordNotFound
|
||||
expect { old_status_plain.reload }.to raise_exception ActiveRecord::RecordNotFound
|
||||
expect { old_status_with_attachment.reload }.to raise_exception ActiveRecord::RecordNotFound
|
||||
expect { old_attachment.reload }.to raise_exception ActiveRecord::RecordNotFound
|
||||
end
|
||||
|
||||
|
@ -6,9 +6,9 @@ RSpec.describe UnallowDomainService, type: :service do
|
||||
subject { described_class.new }
|
||||
|
||||
let!(:bad_account) { Fabricate(:account, username: 'badguy666', domain: 'evil.org') }
|
||||
let!(:bad_status1) { Fabricate(:status, account: bad_account, text: 'You suck') }
|
||||
let!(:bad_status2) { Fabricate(:status, account: bad_account, text: 'Hahaha') }
|
||||
let!(:bad_attachment) { Fabricate(:media_attachment, account: bad_account, status: bad_status2, file: attachment_fixture('attachment.jpg')) }
|
||||
let!(:bad_status_harassment) { Fabricate(:status, account: bad_account, text: 'You suck') }
|
||||
let!(:bad_status_mean) { Fabricate(:status, account: bad_account, text: 'Hahaha') }
|
||||
let!(:bad_attachment) { Fabricate(:media_attachment, account: bad_account, status: bad_status_mean, file: attachment_fixture('attachment.jpg')) }
|
||||
let!(:already_banned_account) { Fabricate(:account, username: 'badguy', domain: 'evil.org', suspended: true, silenced: true) }
|
||||
let!(:domain_allow) { Fabricate(:domain_allow, domain: 'evil.org') }
|
||||
|
||||
@ -31,8 +31,8 @@ RSpec.describe UnallowDomainService, type: :service do
|
||||
end
|
||||
|
||||
it 'removes the remote accounts\'s statuses and media attachments' do
|
||||
expect { bad_status1.reload }.to raise_exception ActiveRecord::RecordNotFound
|
||||
expect { bad_status2.reload }.to raise_exception ActiveRecord::RecordNotFound
|
||||
expect { bad_status_harassment.reload }.to raise_exception ActiveRecord::RecordNotFound
|
||||
expect { bad_status_mean.reload }.to raise_exception ActiveRecord::RecordNotFound
|
||||
expect { bad_attachment.reload }.to raise_exception ActiveRecord::RecordNotFound
|
||||
end
|
||||
end
|
||||
@ -57,8 +57,8 @@ RSpec.describe UnallowDomainService, type: :service do
|
||||
end
|
||||
|
||||
it 'removes the remote accounts\'s statuses and media attachments' do
|
||||
expect { bad_status1.reload }.to_not raise_error
|
||||
expect { bad_status2.reload }.to_not raise_error
|
||||
expect { bad_status_harassment.reload }.to_not raise_error
|
||||
expect { bad_status_mean.reload }.to_not raise_error
|
||||
expect { bad_attachment.reload }.to_not raise_error
|
||||
end
|
||||
end
|
||||
|
@ -1,7 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
GC.disable
|
||||
|
||||
if ENV['DISABLE_SIMPLECOV'] != 'true'
|
||||
require 'simplecov'
|
||||
SimpleCov.start 'rails' do
|
||||
@ -13,8 +11,6 @@ if ENV['DISABLE_SIMPLECOV'] != 'true'
|
||||
end
|
||||
end
|
||||
|
||||
gc_counter = -1
|
||||
|
||||
RSpec.configure do |config|
|
||||
config.example_status_persistence_file_path = 'tmp/rspec/examples.txt'
|
||||
config.expect_with :rspec do |expectations|
|
||||
@ -37,21 +33,8 @@ RSpec.configure do |config|
|
||||
end
|
||||
|
||||
config.after :suite do
|
||||
gc_counter = 0
|
||||
FileUtils.rm_rf(Dir[Rails.root.join('spec', 'test_files')])
|
||||
end
|
||||
|
||||
config.after :each do
|
||||
gc_counter += 1
|
||||
|
||||
if gc_counter > 19
|
||||
GC.enable
|
||||
GC.start
|
||||
GC.disable
|
||||
|
||||
gc_counter = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def body_as_json
|
||||
|
23
spec/support/examples/api.rb
Normal file
23
spec/support/examples/api.rb
Normal file
@ -0,0 +1,23 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope|
|
||||
let(:scopes) { wrong_scope }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
# Some examples have a subject which needs to be called to make a request
|
||||
subject if request.nil?
|
||||
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role|
|
||||
let(:role) { UserRole.find_by(name: wrong_role) }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
# Some examples have a subject which needs to be called to make a request
|
||||
subject if request.nil?
|
||||
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
@ -5,17 +5,12 @@ require 'rails_helper'
|
||||
describe Scheduler::AccountsStatusesCleanupScheduler do
|
||||
subject { described_class.new }
|
||||
|
||||
let!(:account1) { Fabricate(:account, domain: nil) }
|
||||
let!(:account2) { Fabricate(:account, domain: nil) }
|
||||
let!(:account3) { Fabricate(:account, domain: nil) }
|
||||
let!(:account4) { Fabricate(:account, domain: nil) }
|
||||
let!(:account5) { Fabricate(:account, domain: nil) }
|
||||
let!(:remote) { Fabricate(:account) }
|
||||
|
||||
let!(:policy1) { Fabricate(:account_statuses_cleanup_policy, account: account1) }
|
||||
let!(:policy2) { Fabricate(:account_statuses_cleanup_policy, account: account3) }
|
||||
let!(:policy3) { Fabricate(:account_statuses_cleanup_policy, account: account4, enabled: false) }
|
||||
let!(:policy4) { Fabricate(:account_statuses_cleanup_policy, account: account5) }
|
||||
let!(:account_alice) { Fabricate(:account, domain: nil, username: 'alice') }
|
||||
let!(:account_bob) { Fabricate(:account, domain: nil, username: 'bob') }
|
||||
let!(:account_chris) { Fabricate(:account, domain: nil, username: 'chris') }
|
||||
let!(:account_dave) { Fabricate(:account, domain: nil, username: 'dave') }
|
||||
let!(:account_erin) { Fabricate(:account, domain: nil, username: 'erin') }
|
||||
let!(:remote) { Fabricate(:account) }
|
||||
|
||||
let(:queue_size) { 0 }
|
||||
let(:queue_latency) { 0 }
|
||||
@ -29,33 +24,12 @@ describe Scheduler::AccountsStatusesCleanupScheduler do
|
||||
end
|
||||
|
||||
before do
|
||||
queue_stub = double
|
||||
allow(queue_stub).to receive(:size).and_return(queue_size)
|
||||
allow(queue_stub).to receive(:latency).and_return(queue_latency)
|
||||
queue_stub = instance_double(Sidekiq::Queue, size: queue_size, latency: queue_latency)
|
||||
allow(Sidekiq::Queue).to receive(:new).and_return(queue_stub)
|
||||
allow(Sidekiq::ProcessSet).to receive(:new).and_return(process_set_stub)
|
||||
|
||||
sidekiq_stats_stub = double
|
||||
sidekiq_stats_stub = instance_double(Sidekiq::Stats)
|
||||
allow(Sidekiq::Stats).to receive(:new).and_return(sidekiq_stats_stub)
|
||||
|
||||
# Create a bunch of old statuses
|
||||
10.times do
|
||||
Fabricate(:status, account: account1, created_at: 3.years.ago)
|
||||
Fabricate(:status, account: account2, created_at: 3.years.ago)
|
||||
Fabricate(:status, account: account3, created_at: 3.years.ago)
|
||||
Fabricate(:status, account: account4, created_at: 3.years.ago)
|
||||
Fabricate(:status, account: account5, created_at: 3.years.ago)
|
||||
Fabricate(:status, account: remote, created_at: 3.years.ago)
|
||||
end
|
||||
|
||||
# Create a bunch of newer statuses
|
||||
5.times do
|
||||
Fabricate(:status, account: account1, created_at: 3.minutes.ago)
|
||||
Fabricate(:status, account: account2, created_at: 3.minutes.ago)
|
||||
Fabricate(:status, account: account3, created_at: 3.minutes.ago)
|
||||
Fabricate(:status, account: account4, created_at: 3.minutes.ago)
|
||||
Fabricate(:status, account: remote, created_at: 3.minutes.ago)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#under_load?' do
|
||||
@ -101,23 +75,45 @@ describe Scheduler::AccountsStatusesCleanupScheduler do
|
||||
end
|
||||
|
||||
describe '#perform' do
|
||||
before do
|
||||
# Policies for the accounts
|
||||
Fabricate(:account_statuses_cleanup_policy, account: account_alice)
|
||||
Fabricate(:account_statuses_cleanup_policy, account: account_chris)
|
||||
Fabricate(:account_statuses_cleanup_policy, account: account_dave, enabled: false)
|
||||
Fabricate(:account_statuses_cleanup_policy, account: account_erin)
|
||||
|
||||
# Create a bunch of old statuses
|
||||
4.times do
|
||||
Fabricate(:status, account: account_alice, created_at: 3.years.ago)
|
||||
Fabricate(:status, account: account_bob, created_at: 3.years.ago)
|
||||
Fabricate(:status, account: account_chris, created_at: 3.years.ago)
|
||||
Fabricate(:status, account: account_dave, created_at: 3.years.ago)
|
||||
Fabricate(:status, account: account_erin, created_at: 3.years.ago)
|
||||
Fabricate(:status, account: remote, created_at: 3.years.ago)
|
||||
end
|
||||
|
||||
# Create a bunch of newer statuses
|
||||
Fabricate(:status, account: account_alice, created_at: 3.minutes.ago)
|
||||
Fabricate(:status, account: account_bob, created_at: 3.minutes.ago)
|
||||
Fabricate(:status, account: account_chris, created_at: 3.minutes.ago)
|
||||
Fabricate(:status, account: account_dave, created_at: 3.minutes.ago)
|
||||
Fabricate(:status, account: remote, created_at: 3.minutes.ago)
|
||||
end
|
||||
|
||||
context 'when the budget is lower than the number of toots to delete' do
|
||||
it 'deletes as many statuses as the given budget' do
|
||||
expect { subject.perform }.to change(Status, :count).by(-subject.compute_budget)
|
||||
end
|
||||
it 'deletes the appropriate statuses' do
|
||||
expect(Status.count).to be > (subject.compute_budget) # Data check
|
||||
|
||||
it 'does not delete from accounts with no cleanup policy' do
|
||||
expect { subject.perform }.to_not change { account2.statuses.count }
|
||||
end
|
||||
|
||||
it 'does not delete from accounts with disabled cleanup policies' do
|
||||
expect { subject.perform }.to_not change { account4.statuses.count }
|
||||
expect { subject.perform }
|
||||
.to change(Status, :count).by(-subject.compute_budget) # Cleanable statuses
|
||||
.and (not_change { account_bob.statuses.count }) # No cleanup policy for account
|
||||
.and(not_change { account_dave.statuses.count }) # Disabled cleanup policy
|
||||
end
|
||||
|
||||
it 'eventually deletes every deletable toot given enough runs' do
|
||||
stub_const 'Scheduler::AccountsStatusesCleanupScheduler::MAX_BUDGET', 4
|
||||
|
||||
expect { 10.times { subject.perform } }.to change(Status, :count).by(-30)
|
||||
expect { 3.times { subject.perform } }.to change(Status, :count).by(-cleanable_statuses_count)
|
||||
end
|
||||
|
||||
it 'correctly round-trips between users across several runs' do
|
||||
@ -126,9 +122,9 @@ describe Scheduler::AccountsStatusesCleanupScheduler do
|
||||
|
||||
expect { 3.times { subject.perform } }
|
||||
.to change(Status, :count).by(-3 * 3)
|
||||
.and change { account1.statuses.count }
|
||||
.and change { account3.statuses.count }
|
||||
.and change { account5.statuses.count }
|
||||
.and change { account_alice.statuses.count }
|
||||
.and change { account_chris.statuses.count }
|
||||
.and(change { account_erin.statuses.count })
|
||||
end
|
||||
|
||||
context 'when given a big budget' do
|
||||
@ -140,7 +136,7 @@ describe Scheduler::AccountsStatusesCleanupScheduler do
|
||||
|
||||
it 'correctly handles looping in a single run' do
|
||||
expect(subject.compute_budget).to eq(400)
|
||||
expect { subject.perform }.to change(Status, :count).by(-30)
|
||||
expect { subject.perform }.to change(Status, :count).by(-cleanable_statuses_count)
|
||||
end
|
||||
end
|
||||
|
||||
@ -157,6 +153,13 @@ describe Scheduler::AccountsStatusesCleanupScheduler do
|
||||
expect { subject.perform }.to_not change(Status, :count)
|
||||
end
|
||||
end
|
||||
|
||||
def cleanable_statuses_count
|
||||
Status
|
||||
.where(account_id: [account_alice, account_chris, account_erin]) # Accounts with enabled policies
|
||||
.where('created_at < ?', 2.weeks.ago) # Policy defaults is 2.weeks
|
||||
.count
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Reference in New Issue
Block a user