Merge tag 'v3.1.4' into hometown-dev
This commit is contained in:
@ -25,7 +25,7 @@ describe AccountFollowController do
|
||||
sign_in(user)
|
||||
subject
|
||||
|
||||
expect(service).to have_received(:call).with(user.account, 'alice')
|
||||
expect(service).to have_received(:call).with(user.account, alice, with_rate_limit: true)
|
||||
expect(response).to redirect_to(account_path(alice))
|
||||
end
|
||||
end
|
||||
|
||||
@ -3,108 +3,608 @@ require 'rails_helper'
|
||||
RSpec.describe AccountsController, type: :controller do
|
||||
render_views
|
||||
|
||||
let(:alice) { Fabricate(:account, username: 'alice', user: Fabricate(:user)) }
|
||||
let(:eve) { Fabricate(:user) }
|
||||
let(:account) { Fabricate(:user).account }
|
||||
|
||||
describe 'GET #show' do
|
||||
let!(:status1) { Status.create!(account: alice, text: 'Hello world') }
|
||||
let!(:status2) { Status.create!(account: alice, text: 'Boop', thread: status1) }
|
||||
let!(:status3) { Status.create!(account: alice, text: 'Picture!') }
|
||||
let!(:status4) { Status.create!(account: alice, text: 'Mentioning @alice') }
|
||||
let!(:status5) { Status.create!(account: alice, text: 'Kitsune') }
|
||||
let!(:status6) { Status.create!(account: alice, text: 'Neko') }
|
||||
let!(:status7) { Status.create!(account: alice, text: 'Tanuki') }
|
||||
let(:format) { 'html' }
|
||||
|
||||
let!(:status_pin1) { StatusPin.create!(account: alice, status: status5, created_at: 5.days.ago) }
|
||||
let!(:status_pin2) { StatusPin.create!(account: alice, status: status6, created_at: 2.years.ago) }
|
||||
let!(:status_pin3) { StatusPin.create!(account: alice, status: status7, created_at: 10.minutes.ago) }
|
||||
let!(:status) { Fabricate(:status, account: account) }
|
||||
let!(:status_reply) { Fabricate(:status, account: account, thread: Fabricate(:status)) }
|
||||
let!(:status_self_reply) { Fabricate(:status, account: account, thread: status) }
|
||||
let!(:status_media) { Fabricate(:status, account: account) }
|
||||
let!(:status_pinned) { Fabricate(:status, account: account) }
|
||||
let!(:status_private) { Fabricate(:status, account: account, visibility: :private) }
|
||||
let!(:status_direct) { Fabricate(:status, account: account, visibility: :direct) }
|
||||
let!(:status_reblog) { Fabricate(:status, account: account, reblog: Fabricate(:status)) }
|
||||
|
||||
before do
|
||||
alice.block!(eve.account)
|
||||
status3.media_attachments.create!(account: alice, file: fixture_file_upload('files/attachment.jpg', 'image/jpeg'))
|
||||
status_media.media_attachments << Fabricate(:media_attachment, account: account, type: :image)
|
||||
account.pinned_statuses << status_pinned
|
||||
end
|
||||
|
||||
shared_examples 'responses' do
|
||||
before do
|
||||
sign_in(current_user) if defined? current_user
|
||||
get :show, params: {
|
||||
username: alice.username,
|
||||
max_id: (max_id if defined? max_id),
|
||||
since_id: (since_id if defined? since_id),
|
||||
current_user: (current_user if defined? current_user),
|
||||
}, format: format
|
||||
shared_examples 'preliminary checks' do
|
||||
context 'when account is not approved' do
|
||||
before do
|
||||
account.user.update(approved: false)
|
||||
end
|
||||
|
||||
it 'returns http not found' do
|
||||
get :show, params: { username: account.username, format: format }
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
it 'assigns @account' do
|
||||
expect(assigns(:account)).to eq alice
|
||||
end
|
||||
context 'when account is suspended' do
|
||||
before do
|
||||
account.suspend!
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns correct format' do
|
||||
expect(response.content_type).to eq content_type
|
||||
it 'returns http gone' do
|
||||
get :show, params: { username: account.username, format: format }
|
||||
expect(response).to have_http_status(410)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'activitystreams2' do
|
||||
context 'as HTML' do
|
||||
let(:format) { 'html' }
|
||||
|
||||
it_behaves_like 'preliminary checks'
|
||||
|
||||
shared_examples 'common response characteristics' do
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns Link header' do
|
||||
expect(response.headers['Link'].to_s).to include ActivityPub::TagManager.instance.uri_for(account)
|
||||
end
|
||||
|
||||
it 'renders show template' do
|
||||
expect(response).to render_template(:show)
|
||||
end
|
||||
end
|
||||
|
||||
context do
|
||||
before do
|
||||
get :show, params: { username: account.username, format: format }
|
||||
end
|
||||
|
||||
it_behaves_like 'common response characteristics'
|
||||
|
||||
it 'renders public status' do
|
||||
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status))
|
||||
end
|
||||
|
||||
it 'renders self-reply' do
|
||||
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_self_reply))
|
||||
end
|
||||
|
||||
it 'renders status with media' do
|
||||
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_media))
|
||||
end
|
||||
|
||||
it 'renders reblog' do
|
||||
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_reblog.reblog))
|
||||
end
|
||||
|
||||
it 'renders pinned status' do
|
||||
expect(response.body).to include(I18n.t('stream_entries.pinned'))
|
||||
end
|
||||
|
||||
it 'does not render private status' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_private))
|
||||
end
|
||||
|
||||
it 'does not render direct status' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_direct))
|
||||
end
|
||||
|
||||
it 'does not render reply to someone else' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reply))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when signed-in' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
|
||||
before do
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
context 'when user follows account' do
|
||||
before do
|
||||
user.account.follow!(account)
|
||||
get :show, params: { username: account.username, format: format }
|
||||
end
|
||||
|
||||
it 'does not render private status' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_private))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is blocked' do
|
||||
before do
|
||||
account.block!(user.account)
|
||||
get :show, params: { username: account.username, format: format }
|
||||
end
|
||||
|
||||
it 'renders unavailable message' do
|
||||
expect(response.body).to include(I18n.t('accounts.unavailable'))
|
||||
end
|
||||
|
||||
it 'does not render public status' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status))
|
||||
end
|
||||
|
||||
it 'does not render self-reply' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_self_reply))
|
||||
end
|
||||
|
||||
it 'does not render status with media' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_media))
|
||||
end
|
||||
|
||||
it 'does not render reblog' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reblog.reblog))
|
||||
end
|
||||
|
||||
it 'does not render pinned status' do
|
||||
expect(response.body).to_not include(I18n.t('stream_entries.pinned'))
|
||||
end
|
||||
|
||||
it 'does not render private status' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_private))
|
||||
end
|
||||
|
||||
it 'does not render direct status' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_direct))
|
||||
end
|
||||
|
||||
it 'does not render reply to someone else' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reply))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with replies' do
|
||||
before do
|
||||
allow(controller).to receive(:replies_requested?).and_return(true)
|
||||
get :show, params: { username: account.username, format: format }
|
||||
end
|
||||
|
||||
it_behaves_like 'common response characteristics'
|
||||
|
||||
it 'renders public status' do
|
||||
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status))
|
||||
end
|
||||
|
||||
it 'renders self-reply' do
|
||||
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_self_reply))
|
||||
end
|
||||
|
||||
it 'renders status with media' do
|
||||
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_media))
|
||||
end
|
||||
|
||||
it 'renders reblog' do
|
||||
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_reblog.reblog))
|
||||
end
|
||||
|
||||
it 'does not render pinned status' do
|
||||
expect(response.body).to_not include(I18n.t('stream_entries.pinned'))
|
||||
end
|
||||
|
||||
it 'does not render private status' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_private))
|
||||
end
|
||||
|
||||
it 'does not render direct status' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_direct))
|
||||
end
|
||||
|
||||
it 'renders reply to someone else' do
|
||||
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_reply))
|
||||
end
|
||||
end
|
||||
|
||||
context 'with media' do
|
||||
before do
|
||||
allow(controller).to receive(:media_requested?).and_return(true)
|
||||
get :show, params: { username: account.username, format: format }
|
||||
end
|
||||
|
||||
it_behaves_like 'common response characteristics'
|
||||
|
||||
it 'does not render public status' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status))
|
||||
end
|
||||
|
||||
it 'does not render self-reply' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_self_reply))
|
||||
end
|
||||
|
||||
it 'renders status with media' do
|
||||
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_media))
|
||||
end
|
||||
|
||||
it 'does not render reblog' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reblog.reblog))
|
||||
end
|
||||
|
||||
it 'does not render pinned status' do
|
||||
expect(response.body).to_not include(I18n.t('stream_entries.pinned'))
|
||||
end
|
||||
|
||||
it 'does not render private status' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_private))
|
||||
end
|
||||
|
||||
it 'does not render direct status' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_direct))
|
||||
end
|
||||
|
||||
it 'does not render reply to someone else' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reply))
|
||||
end
|
||||
end
|
||||
|
||||
context 'with tag' do
|
||||
let(:tag) { Fabricate(:tag) }
|
||||
|
||||
let!(:status_tag) { Fabricate(:status, account: account) }
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:tag_requested?).and_return(true)
|
||||
status_tag.tags << tag
|
||||
get :show, params: { username: account.username, format: format, tag: tag.to_param }
|
||||
end
|
||||
|
||||
it_behaves_like 'common response characteristics'
|
||||
|
||||
it 'does not render public status' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status))
|
||||
end
|
||||
|
||||
it 'does not render self-reply' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_self_reply))
|
||||
end
|
||||
|
||||
it 'does not render status with media' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_media))
|
||||
end
|
||||
|
||||
it 'does not render reblog' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reblog.reblog))
|
||||
end
|
||||
|
||||
it 'does not render pinned status' do
|
||||
expect(response.body).to_not include(I18n.t('stream_entries.pinned'))
|
||||
end
|
||||
|
||||
it 'does not render private status' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_private))
|
||||
end
|
||||
|
||||
it 'does not render direct status' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_direct))
|
||||
end
|
||||
|
||||
it 'does not render reply to someone else' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reply))
|
||||
end
|
||||
|
||||
it 'renders status with tag' do
|
||||
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_tag))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'as JSON' do
|
||||
let(:authorized_fetch_mode) { false }
|
||||
let(:format) { 'json' }
|
||||
let(:content_type) { 'application/activity+json' }
|
||||
|
||||
include_examples 'responses'
|
||||
before do
|
||||
allow(controller).to receive(:authorized_fetch_mode?).and_return(authorized_fetch_mode)
|
||||
end
|
||||
|
||||
it_behaves_like 'preliminary checks'
|
||||
|
||||
context do
|
||||
before do
|
||||
get :show, params: { username: account.username, format: format }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns application/activity+json' do
|
||||
expect(response.content_type).to eq 'application/activity+json'
|
||||
end
|
||||
|
||||
it 'returns public Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to include 'public'
|
||||
end
|
||||
|
||||
it 'renders account' do
|
||||
json = body_as_json
|
||||
expect(json).to include(:id, :type, :preferredUsername, :inbox, :publicKey, :name, :summary)
|
||||
end
|
||||
|
||||
context 'in authorized fetch mode' do
|
||||
let(:authorized_fetch_mode) { true }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns application/activity+json' do
|
||||
expect(response.content_type).to eq 'application/activity+json'
|
||||
end
|
||||
|
||||
it 'returns public Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to include 'public'
|
||||
end
|
||||
|
||||
it 'returns Vary header with Signature' do
|
||||
expect(response.headers['Vary']).to include 'Signature'
|
||||
end
|
||||
|
||||
it 'renders bare minimum account' do
|
||||
json = body_as_json
|
||||
expect(json).to include(:id, :type, :preferredUsername, :inbox, :publicKey)
|
||||
expect(json).to_not include(:name, :summary)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when signed in' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
|
||||
before do
|
||||
sign_in(user)
|
||||
get :show, params: { username: account.username, format: format }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns application/activity+json' do
|
||||
expect(response.content_type).to eq 'application/activity+json'
|
||||
end
|
||||
|
||||
it 'returns public Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to include 'public'
|
||||
end
|
||||
|
||||
it 'renders account' do
|
||||
json = body_as_json
|
||||
expect(json).to include(:id, :type, :preferredUsername, :inbox, :publicKey, :name, :summary)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with signature' do
|
||||
let(:remote_account) { Fabricate(:account, domain: 'example.com') }
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:signed_request_account).and_return(remote_account)
|
||||
get :show, params: { username: account.username, format: format }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns application/activity+json' do
|
||||
expect(response.content_type).to eq 'application/activity+json'
|
||||
end
|
||||
|
||||
it 'returns public Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to include 'public'
|
||||
end
|
||||
|
||||
it 'renders account' do
|
||||
json = body_as_json
|
||||
expect(json).to include(:id, :type, :preferredUsername, :inbox, :publicKey, :name, :summary)
|
||||
end
|
||||
|
||||
context 'in authorized fetch mode' do
|
||||
let(:authorized_fetch_mode) { true }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns application/activity+json' do
|
||||
expect(response.content_type).to eq 'application/activity+json'
|
||||
end
|
||||
|
||||
it 'returns private Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to include 'private'
|
||||
end
|
||||
|
||||
it 'returns Vary header with Signature' do
|
||||
expect(response.headers['Vary']).to include 'Signature'
|
||||
end
|
||||
|
||||
it 'renders account' do
|
||||
json = body_as_json
|
||||
expect(json).to include(:id, :type, :preferredUsername, :inbox, :publicKey, :name, :summary)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'html' do
|
||||
let(:format) { nil }
|
||||
let(:content_type) { 'text/html' }
|
||||
context 'as RSS' do
|
||||
let(:format) { 'rss' }
|
||||
|
||||
shared_examples 'responsed statuses' do
|
||||
it 'assigns @pinned_statuses' do
|
||||
pinned_statuses = assigns(:pinned_statuses).to_a
|
||||
expect(pinned_statuses.size).to eq expected_pinned_statuses.size
|
||||
pinned_statuses.each.zip(expected_pinned_statuses.each) do |pinned_status, expected_pinned_status|
|
||||
expect(pinned_status).to eq expected_pinned_status
|
||||
end
|
||||
it_behaves_like 'preliminary checks'
|
||||
|
||||
shared_examples 'common response characteristics' do
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'assigns @statuses' do
|
||||
statuses = assigns(:statuses).to_a
|
||||
expect(statuses.size).to eq expected_statuses.size
|
||||
statuses.each.zip(expected_statuses.each) do |status, expected_status|
|
||||
expect(status).to eq expected_status
|
||||
end
|
||||
it 'returns public Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to include 'public'
|
||||
end
|
||||
end
|
||||
|
||||
include_examples 'responses'
|
||||
|
||||
context 'with anonymous visitor' do
|
||||
context 'without since_id nor max_id' do
|
||||
let(:expected_statuses) { [status7, status6, status5, status4, status3, status2, status1] }
|
||||
let(:expected_pinned_statuses) { [status7, status5, status6] }
|
||||
|
||||
include_examples 'responsed statuses'
|
||||
context do
|
||||
before do
|
||||
get :show, params: { username: account.username, format: format }
|
||||
end
|
||||
|
||||
context 'with since_id nor max_id' do
|
||||
let(:max_id) { status4.id }
|
||||
let(:since_id) { status1.id }
|
||||
let(:expected_statuses) { [status3, status2] }
|
||||
let(:expected_pinned_statuses) { [] }
|
||||
it_behaves_like 'common response characteristics'
|
||||
|
||||
include_examples 'responsed statuses'
|
||||
it 'renders public status' do
|
||||
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status))
|
||||
end
|
||||
|
||||
it 'renders self-reply' do
|
||||
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_self_reply))
|
||||
end
|
||||
|
||||
it 'renders status with media' do
|
||||
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_media))
|
||||
end
|
||||
|
||||
it 'does not render reblog' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reblog.reblog))
|
||||
end
|
||||
|
||||
it 'does not render private status' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_private))
|
||||
end
|
||||
|
||||
it 'does not render direct status' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_direct))
|
||||
end
|
||||
|
||||
it 'does not render reply to someone else' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reply))
|
||||
end
|
||||
end
|
||||
|
||||
context 'with blocked visitor' do
|
||||
let(:current_user) { eve }
|
||||
context 'with replies' do
|
||||
before do
|
||||
allow(controller).to receive(:replies_requested?).and_return(true)
|
||||
get :show, params: { username: account.username, format: format }
|
||||
end
|
||||
|
||||
context 'without since_id nor max_id' do
|
||||
let(:expected_statuses) { [] }
|
||||
let(:expected_pinned_statuses) { [] }
|
||||
it_behaves_like 'common response characteristics'
|
||||
|
||||
include_examples 'responsed statuses'
|
||||
it 'renders public status' do
|
||||
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status))
|
||||
end
|
||||
|
||||
it 'renders self-reply' do
|
||||
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_self_reply))
|
||||
end
|
||||
|
||||
it 'renders status with media' do
|
||||
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_media))
|
||||
end
|
||||
|
||||
it 'does not render reblog' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reblog.reblog))
|
||||
end
|
||||
|
||||
it 'does not render private status' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_private))
|
||||
end
|
||||
|
||||
it 'does not render direct status' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_direct))
|
||||
end
|
||||
|
||||
it 'renders reply to someone else' do
|
||||
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_reply))
|
||||
end
|
||||
end
|
||||
|
||||
context 'with media' do
|
||||
before do
|
||||
allow(controller).to receive(:media_requested?).and_return(true)
|
||||
get :show, params: { username: account.username, format: format }
|
||||
end
|
||||
|
||||
it_behaves_like 'common response characteristics'
|
||||
|
||||
it 'does not render public status' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status))
|
||||
end
|
||||
|
||||
it 'does not render self-reply' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_self_reply))
|
||||
end
|
||||
|
||||
it 'renders status with media' do
|
||||
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_media))
|
||||
end
|
||||
|
||||
it 'does not render reblog' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reblog.reblog))
|
||||
end
|
||||
|
||||
it 'does not render private status' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_private))
|
||||
end
|
||||
|
||||
it 'does not render direct status' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_direct))
|
||||
end
|
||||
|
||||
it 'does not render reply to someone else' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reply))
|
||||
end
|
||||
end
|
||||
|
||||
context 'with tag' do
|
||||
let(:tag) { Fabricate(:tag) }
|
||||
|
||||
let!(:status_tag) { Fabricate(:status, account: account) }
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:tag_requested?).and_return(true)
|
||||
status_tag.tags << tag
|
||||
get :show, params: { username: account.username, format: format, tag: tag.to_param }
|
||||
end
|
||||
|
||||
it_behaves_like 'common response characteristics'
|
||||
|
||||
it 'does not render public status' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status))
|
||||
end
|
||||
|
||||
it 'does not render self-reply' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_self_reply))
|
||||
end
|
||||
|
||||
it 'does not render status with media' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_media))
|
||||
end
|
||||
|
||||
it 'does not render reblog' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reblog.reblog))
|
||||
end
|
||||
|
||||
it 'does not render private status' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_private))
|
||||
end
|
||||
|
||||
it 'does not render direct status' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_direct))
|
||||
end
|
||||
|
||||
it 'does not render reply to someone else' do
|
||||
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reply))
|
||||
end
|
||||
|
||||
it 'renders status with tag' do
|
||||
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_tag))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -3,21 +3,133 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::CollectionsController, type: :controller do
|
||||
describe 'POST #show' do
|
||||
let(:account) { Fabricate(:account) }
|
||||
let!(:account) { Fabricate(:account) }
|
||||
let(:remote_account) { nil }
|
||||
|
||||
context 'id is "featured"' do
|
||||
it 'returns 200 with "application/activity+json"' do
|
||||
post :show, params: { id: 'featured', account_username: account.username }
|
||||
before do
|
||||
allow(controller).to receive(:signed_request_account).and_return(remote_account)
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(response.content_type).to eq 'application/activity+json'
|
||||
Fabricate(:status_pin, account: account)
|
||||
Fabricate(:status_pin, account: account)
|
||||
Fabricate(:status, account: account, visibility: :private)
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
context 'when id is "featured"' do
|
||||
context 'without signature' do
|
||||
let(:remote_account) { nil }
|
||||
|
||||
before do
|
||||
get :show, params: { id: 'featured', account_username: account.username }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns application/activity+json' do
|
||||
expect(response.content_type).to eq 'application/activity+json'
|
||||
end
|
||||
|
||||
it 'returns public Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to include 'public'
|
||||
end
|
||||
|
||||
it 'returns orderedItems with pinned statuses' do
|
||||
json = body_as_json
|
||||
expect(json[:orderedItems]).to be_an Array
|
||||
expect(json[:orderedItems].size).to eq 2
|
||||
end
|
||||
end
|
||||
|
||||
context 'with signature' do
|
||||
let(:remote_account) { Fabricate(:account, domain: 'example.com') }
|
||||
|
||||
context do
|
||||
before do
|
||||
get :show, params: { id: 'featured', account_username: account.username }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns application/activity+json' do
|
||||
expect(response.content_type).to eq 'application/activity+json'
|
||||
end
|
||||
|
||||
it 'returns public Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to include 'public'
|
||||
end
|
||||
|
||||
it 'returns orderedItems with pinned statuses' do
|
||||
json = body_as_json
|
||||
expect(json[:orderedItems]).to be_an Array
|
||||
expect(json[:orderedItems].size).to eq 2
|
||||
end
|
||||
end
|
||||
|
||||
context 'in authorized fetch mode' do
|
||||
before do
|
||||
allow(controller).to receive(:authorized_fetch_mode?).and_return(true)
|
||||
end
|
||||
|
||||
context 'when signed request account is blocked' do
|
||||
before do
|
||||
account.block!(remote_account)
|
||||
get :show, params: { id: 'featured', account_username: account.username }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns application/activity+json' do
|
||||
expect(response.content_type).to eq 'application/activity+json'
|
||||
end
|
||||
|
||||
it 'returns private Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to include 'private'
|
||||
end
|
||||
|
||||
it 'returns empty orderedItems' do
|
||||
json = body_as_json
|
||||
expect(json[:orderedItems]).to be_an Array
|
||||
expect(json[:orderedItems].size).to eq 0
|
||||
end
|
||||
end
|
||||
|
||||
context 'when signed request account is domain blocked' do
|
||||
before do
|
||||
account.block_domain!(remote_account.domain)
|
||||
get :show, params: { id: 'featured', account_username: account.username }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns application/activity+json' do
|
||||
expect(response.content_type).to eq 'application/activity+json'
|
||||
end
|
||||
|
||||
it 'returns private Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to include 'private'
|
||||
end
|
||||
|
||||
it 'returns empty orderedItems' do
|
||||
json = body_as_json
|
||||
expect(json[:orderedItems]).to be_an Array
|
||||
expect(json[:orderedItems].size).to eq 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'id is not "featured"' do
|
||||
it 'returns 404' do
|
||||
post :show, params: { id: 'hoge', account_username: account.username }
|
||||
context 'when id is not "featured"' do
|
||||
it 'returns http not found' do
|
||||
get :show, params: { id: 'hoge', account_username: account.username }
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
@ -3,25 +3,31 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::InboxesController, type: :controller do
|
||||
describe 'POST #create' do
|
||||
context 'with signed_request_account' do
|
||||
it 'returns 202' do
|
||||
allow(controller).to receive(:signed_request_account) do
|
||||
Fabricate(:account)
|
||||
end
|
||||
let(:remote_account) { nil }
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:signed_request_account).and_return(remote_account)
|
||||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
context 'with signature' do
|
||||
let(:remote_account) { Fabricate(:account, domain: 'example.com', protocol: :activitypub) }
|
||||
|
||||
before do
|
||||
post :create, body: '{}'
|
||||
end
|
||||
|
||||
it 'returns http accepted' do
|
||||
expect(response).to have_http_status(202)
|
||||
end
|
||||
end
|
||||
|
||||
context 'without signed_request_account' do
|
||||
it 'returns 401' do
|
||||
allow(controller).to receive(:signed_request_account) do
|
||||
false
|
||||
end
|
||||
|
||||
context 'without signature' do
|
||||
before do
|
||||
post :create, body: '{}'
|
||||
end
|
||||
|
||||
it 'returns http not authorized' do
|
||||
expect(response).to have_http_status(401)
|
||||
end
|
||||
end
|
||||
|
||||
@ -4,20 +4,174 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
|
||||
let!(:account) { Fabricate(:account) }
|
||||
|
||||
before do
|
||||
Fabricate(:status, account: account)
|
||||
Fabricate(:status, account: account, visibility: :public)
|
||||
Fabricate(:status, account: account, visibility: :unlisted)
|
||||
Fabricate(:status, account: account, visibility: :private)
|
||||
Fabricate(:status, account: account, visibility: :direct)
|
||||
Fabricate(:status, account: account, visibility: :limited)
|
||||
end
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:signed_request_account).and_return(remote_account)
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
before do
|
||||
get :show, params: { account_username: account.username }
|
||||
context 'without signature' do
|
||||
let(:remote_account) { nil }
|
||||
|
||||
before do
|
||||
get :show, params: { account_username: account.username, page: page }
|
||||
end
|
||||
|
||||
context 'with page not requested' do
|
||||
let(:page) { nil }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns application/activity+json' do
|
||||
expect(response.content_type).to eq 'application/activity+json'
|
||||
end
|
||||
|
||||
it 'returns totalItems' do
|
||||
json = body_as_json
|
||||
expect(json[:totalItems]).to eq 4
|
||||
end
|
||||
|
||||
it 'returns public Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to include 'public'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with page requested' do
|
||||
let(:page) { 'true' }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns application/activity+json' do
|
||||
expect(response.content_type).to eq 'application/activity+json'
|
||||
end
|
||||
|
||||
it 'returns orderedItems with public or unlisted statuses' do
|
||||
json = body_as_json
|
||||
expect(json[:orderedItems]).to be_an Array
|
||||
expect(json[:orderedItems].size).to eq 2
|
||||
expect(json[:orderedItems].all? { |item| item[:to].include?(ActivityPub::TagManager::COLLECTIONS[:public]) || item[:cc].include?(ActivityPub::TagManager::COLLECTIONS[:public]) }).to be true
|
||||
end
|
||||
|
||||
it 'returns public Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to include 'public'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
context 'with signature' do
|
||||
let(:remote_account) { Fabricate(:account, domain: 'example.com') }
|
||||
let(:page) { 'true' }
|
||||
|
||||
it 'returns application/activity+json' do
|
||||
expect(response.content_type).to eq 'application/activity+json'
|
||||
context 'when signed request account does not follow account' do
|
||||
before do
|
||||
get :show, params: { account_username: account.username, page: page }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns application/activity+json' do
|
||||
expect(response.content_type).to eq 'application/activity+json'
|
||||
end
|
||||
|
||||
it 'returns orderedItems with public or unlisted statuses' do
|
||||
json = body_as_json
|
||||
expect(json[:orderedItems]).to be_an Array
|
||||
expect(json[:orderedItems].size).to eq 2
|
||||
expect(json[:orderedItems].all? { |item| item[:to].include?(ActivityPub::TagManager::COLLECTIONS[:public]) || item[:cc].include?(ActivityPub::TagManager::COLLECTIONS[:public]) }).to be true
|
||||
end
|
||||
|
||||
it 'returns private Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to eq 'max-age=0, private'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when signed request account follows account' do
|
||||
before do
|
||||
remote_account.follow!(account)
|
||||
get :show, params: { account_username: account.username, page: page }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns application/activity+json' do
|
||||
expect(response.content_type).to eq 'application/activity+json'
|
||||
end
|
||||
|
||||
it 'returns orderedItems with private statuses' do
|
||||
json = body_as_json
|
||||
expect(json[:orderedItems]).to be_an Array
|
||||
expect(json[:orderedItems].size).to eq 3
|
||||
expect(json[:orderedItems].all? { |item| item[:to].include?(ActivityPub::TagManager::COLLECTIONS[:public]) || item[:cc].include?(ActivityPub::TagManager::COLLECTIONS[:public]) || item[:to].include?(account_followers_url(account, ActionMailer::Base.default_url_options)) }).to be true
|
||||
end
|
||||
|
||||
it 'returns private Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to eq 'max-age=0, private'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when signed request account is blocked' do
|
||||
before do
|
||||
account.block!(remote_account)
|
||||
get :show, params: { account_username: account.username, page: page }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns application/activity+json' do
|
||||
expect(response.content_type).to eq 'application/activity+json'
|
||||
end
|
||||
|
||||
it 'returns empty orderedItems' do
|
||||
json = body_as_json
|
||||
expect(json[:orderedItems]).to be_an Array
|
||||
expect(json[:orderedItems].size).to eq 0
|
||||
end
|
||||
|
||||
it 'returns private Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to eq 'max-age=0, private'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when signed request account is domain blocked' do
|
||||
before do
|
||||
account.block_domain!(remote_account.domain)
|
||||
get :show, params: { account_username: account.username, page: page }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns application/activity+json' do
|
||||
expect(response.content_type).to eq 'application/activity+json'
|
||||
end
|
||||
|
||||
it 'returns empty orderedItems' do
|
||||
json = body_as_json
|
||||
expect(json[:orderedItems]).to be_an Array
|
||||
expect(json[:orderedItems].size).to eq 0
|
||||
end
|
||||
|
||||
it 'returns private Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to eq 'max-age=0, private'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
196
spec/controllers/activitypub/replies_controller_spec.rb
Normal file
196
spec/controllers/activitypub/replies_controller_spec.rb
Normal file
@ -0,0 +1,196 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::RepliesController, type: :controller do
|
||||
let(:status) { Fabricate(:status, visibility: parent_visibility) }
|
||||
let(:remote_account) { nil }
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:signed_request_account).and_return(remote_account)
|
||||
|
||||
Fabricate(:status, thread: status, visibility: :public)
|
||||
Fabricate(:status, thread: status, visibility: :public)
|
||||
Fabricate(:status, thread: status, visibility: :private)
|
||||
Fabricate(:status, account: status.account, thread: status, visibility: :public)
|
||||
Fabricate(:status, account: status.account, thread: status, visibility: :private)
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
context 'with no signature' do
|
||||
before do
|
||||
get :index, params: { account_username: status.account.username, status_id: status.id }
|
||||
end
|
||||
|
||||
context 'when status is public' do
|
||||
let(:parent_visibility) { :public }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns application/activity+json' do
|
||||
expect(response.content_type).to eq 'application/activity+json'
|
||||
end
|
||||
|
||||
it 'returns public Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to include 'public'
|
||||
end
|
||||
|
||||
it 'returns items with account\'s own replies' do
|
||||
json = body_as_json
|
||||
|
||||
expect(json[:first]).to be_a Hash
|
||||
expect(json[:first][:items]).to be_an Array
|
||||
expect(json[:first][:items].size).to eq 1
|
||||
expect(json[:first][:items].all? { |item| item[:to].include?(ActivityPub::TagManager::COLLECTIONS[:public]) || item[:cc].include?(ActivityPub::TagManager::COLLECTIONS[:public]) }).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when status is private' do
|
||||
let(:parent_visibility) { :private }
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when status is direct' do
|
||||
let(:parent_visibility) { :direct }
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with signature' do
|
||||
let(:remote_account) { Fabricate(:account, domain: 'example.com') }
|
||||
let(:only_other_accounts) { nil }
|
||||
|
||||
context do
|
||||
before do
|
||||
get :index, params: { account_username: status.account.username, status_id: status.id, only_other_accounts: only_other_accounts }
|
||||
end
|
||||
|
||||
context 'when status is public' do
|
||||
let(:parent_visibility) { :public }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns application/activity+json' do
|
||||
expect(response.content_type).to eq 'application/activity+json'
|
||||
end
|
||||
|
||||
it 'returns public Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to include 'public'
|
||||
end
|
||||
|
||||
context 'without only_other_accounts' do
|
||||
it 'returns items with account\'s own replies' do
|
||||
json = body_as_json
|
||||
|
||||
expect(json[:first]).to be_a Hash
|
||||
expect(json[:first][:items]).to be_an Array
|
||||
expect(json[:first][:items].size).to eq 1
|
||||
expect(json[:first][:items].all? { |item| item[:to].include?(ActivityPub::TagManager::COLLECTIONS[:public]) || item[:cc].include?(ActivityPub::TagManager::COLLECTIONS[:public]) }).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'with only_other_accounts' do
|
||||
let(:only_other_accounts) { 'true' }
|
||||
|
||||
it 'returns items with other public or unlisted replies' do
|
||||
json = body_as_json
|
||||
|
||||
expect(json[:first]).to be_a Hash
|
||||
expect(json[:first][:items]).to be_an Array
|
||||
expect(json[:first][:items].size).to eq 2
|
||||
expect(json[:first][:items].all? { |item| item[:to].include?(ActivityPub::TagManager::COLLECTIONS[:public]) || item[:cc].include?(ActivityPub::TagManager::COLLECTIONS[:public]) }).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when status is private' do
|
||||
let(:parent_visibility) { :private }
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when status is direct' do
|
||||
let(:parent_visibility) { :direct }
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when signed request account is blocked' do
|
||||
before do
|
||||
status.account.block!(remote_account)
|
||||
get :index, params: { account_username: status.account.username, status_id: status.id }
|
||||
end
|
||||
|
||||
context 'when status is public' do
|
||||
let(:parent_visibility) { :public }
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when status is private' do
|
||||
let(:parent_visibility) { :private }
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when status is direct' do
|
||||
let(:parent_visibility) { :direct }
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when signed request account is domain blocked' do
|
||||
before do
|
||||
status.account.block_domain!(remote_account.domain)
|
||||
get :index, params: { account_username: status.account.username, status_id: status.id }
|
||||
end
|
||||
|
||||
context 'when status is public' do
|
||||
let(:parent_visibility) { :public }
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when status is private' do
|
||||
let(:parent_visibility) { :private }
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when status is direct' do
|
||||
let(:parent_visibility) { :direct }
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -46,6 +46,26 @@ describe Admin::ReportsController do
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #resolve' do
|
||||
it 'resolves the report' do
|
||||
report = Fabricate(:report)
|
||||
|
||||
put :resolve, params: { id: report }
|
||||
expect(response).to redirect_to(admin_reports_path)
|
||||
report.reload
|
||||
expect(report.action_taken_by_account).to eq user.account
|
||||
expect(report.action_taken).to eq true
|
||||
end
|
||||
|
||||
it 'sets trust level when the report is an antispam one' do
|
||||
report = Fabricate(:report, account: Account.representative)
|
||||
|
||||
put :resolve, params: { id: report }
|
||||
report.reload
|
||||
expect(report.target_account.trust_level).to eq Account::TRUST_LEVELS[:trusted]
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #reopen' do
|
||||
it 'reopens the report' do
|
||||
report = Fabricate(:report)
|
||||
|
||||
@ -36,5 +36,28 @@ describe Api::V1::Accounts::FollowerAccountsController do
|
||||
expect(body_as_json.size).to eq 1
|
||||
expect(body_as_json[0][:id]).to eq alice.id.to_s
|
||||
end
|
||||
|
||||
context 'when requesting user is blocked' do
|
||||
before do
|
||||
account.block!(user.account)
|
||||
end
|
||||
|
||||
it 'hides results' do
|
||||
get :index, params: { account_id: account.id, limit: 2 }
|
||||
expect(body_as_json.size).to eq 0
|
||||
end
|
||||
end
|
||||
|
||||
context 'when requesting user is the account owner' do
|
||||
let(:user) { Fabricate(:user, account: account) }
|
||||
|
||||
it 'returns all accounts, including muted accounts' do
|
||||
user.account.mute!(bob)
|
||||
get :index, params: { account_id: account.id, limit: 2 }
|
||||
|
||||
expect(body_as_json.size).to eq 2
|
||||
expect([body_as_json[0][:id], body_as_json[1][:id]]).to match_array([alice.id.to_s, bob.id.to_s])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -36,5 +36,28 @@ describe Api::V1::Accounts::FollowingAccountsController do
|
||||
expect(body_as_json.size).to eq 1
|
||||
expect(body_as_json[0][:id]).to eq alice.id.to_s
|
||||
end
|
||||
|
||||
context 'when requesting user is blocked' do
|
||||
before do
|
||||
account.block!(user.account)
|
||||
end
|
||||
|
||||
it 'hides results' do
|
||||
get :index, params: { account_id: account.id, limit: 2 }
|
||||
expect(body_as_json.size).to eq 0
|
||||
end
|
||||
end
|
||||
|
||||
context 'when requesting user is the account owner' do
|
||||
let(:user) { Fabricate(:user, account: account) }
|
||||
|
||||
it 'returns all accounts, including muted accounts' do
|
||||
user.account.mute!(bob)
|
||||
get :index, params: { account_id: account.id, limit: 2 }
|
||||
|
||||
expect(body_as_json.size).to eq 2
|
||||
expect([body_as_json[0][:id], body_as_json[1][:id]]).to match_array([alice.id.to_s, bob.id.to_s])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -21,7 +21,7 @@ RSpec.describe Api::V1::AccountsController, type: :controller do
|
||||
|
||||
describe 'POST #create' do
|
||||
let(:app) { Fabricate(:application) }
|
||||
let(:token) { Doorkeeper::AccessToken.find_or_create_for(app, nil, 'read write', nil, false) }
|
||||
let(:token) { Doorkeeper::AccessToken.find_or_create_for(application: app, resource_owner: nil, scopes: 'read write', use_refresh_token: false) }
|
||||
let(:agreement) { nil }
|
||||
|
||||
before do
|
||||
|
||||
@ -39,12 +39,50 @@ RSpec.describe Api::V1::StatusesController, type: :controller do
|
||||
describe 'POST #create' do
|
||||
let(:scopes) { 'write:statuses' }
|
||||
|
||||
before do
|
||||
post :create, params: { status: 'Hello world' }
|
||||
context do
|
||||
before do
|
||||
post :create, params: { status: 'Hello world' }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns rate limit headers' do
|
||||
expect(response.headers['X-RateLimit-Limit']).to eq RateLimiter::FAMILIES[:statuses][:limit].to_s
|
||||
expect(response.headers['X-RateLimit-Remaining']).to eq (RateLimiter::FAMILIES[:statuses][:limit] - 1).to_s
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
context 'with missing parameters' do
|
||||
before do
|
||||
post :create, params: {}
|
||||
end
|
||||
|
||||
it 'returns http unprocessable entity' do
|
||||
expect(response).to have_http_status(422)
|
||||
end
|
||||
|
||||
it 'returns rate limit headers' do
|
||||
expect(response.headers['X-RateLimit-Limit']).to eq RateLimiter::FAMILIES[:statuses][:limit].to_s
|
||||
end
|
||||
end
|
||||
|
||||
context 'when exceeding rate limit' do
|
||||
before do
|
||||
rate_limiter = RateLimiter.new(user.account, family: :statuses)
|
||||
300.times { rate_limiter.record! }
|
||||
post :create, params: { status: 'Hello world' }
|
||||
end
|
||||
|
||||
it 'returns http too many requests' do
|
||||
expect(response).to have_http_status(429)
|
||||
end
|
||||
|
||||
it 'returns rate limit headers' do
|
||||
expect(response.headers['X-RateLimit-Limit']).to eq RateLimiter::FAMILIES[:statuses][:limit].to_s
|
||||
expect(response.headers['X-RateLimit-Remaining']).to eq '0'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -16,10 +16,16 @@ describe ApplicationController, type: :controller do
|
||||
end
|
||||
|
||||
shared_examples 'default locale' do
|
||||
it 'sets available and preferred language' do
|
||||
request.headers['Accept-Language'] = 'sr-Latn'
|
||||
get 'success'
|
||||
expect(response.body).to eq 'sr-Latn'
|
||||
end
|
||||
|
||||
it 'sets available and preferred language' do
|
||||
request.headers['Accept-Language'] = 'ca-ES, fa'
|
||||
get 'success'
|
||||
expect(response.body).to eq 'fa'
|
||||
expect(response.body).to eq 'ca'
|
||||
end
|
||||
|
||||
it 'sets available and compatible language if none of available languages are preferred' do
|
||||
|
||||
@ -41,11 +41,11 @@ RSpec.describe Oauth::AuthorizationsController, type: :controller do
|
||||
context 'when app is already authorized' do
|
||||
before do
|
||||
Doorkeeper::AccessToken.find_or_create_for(
|
||||
app,
|
||||
user.id,
|
||||
app.scopes,
|
||||
Doorkeeper.configuration.access_token_expires_in,
|
||||
Doorkeeper.configuration.refresh_token_enabled?
|
||||
application: app,
|
||||
resource_owner: user.id,
|
||||
scopes: app.scopes,
|
||||
expires_in: Doorkeeper.configuration.access_token_expires_in,
|
||||
use_refresh_token: Doorkeeper.configuration.refresh_token_enabled?
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
@ -5,11 +5,12 @@ require 'rails_helper'
|
||||
RSpec.describe Oauth::TokensController, type: :controller do
|
||||
describe 'POST #revoke' do
|
||||
let!(:user) { Fabricate(:user) }
|
||||
let!(:access_token) { Fabricate(:accessible_access_token, resource_owner_id: user.id) }
|
||||
let!(:application) { Fabricate(:application, confidential: false) }
|
||||
let!(:access_token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: application) }
|
||||
let!(:web_push_subscription) { Fabricate(:web_push_subscription, user: user, access_token: access_token) }
|
||||
|
||||
before do
|
||||
post :revoke, params: { token: access_token.token }
|
||||
post :revoke, params: { client_id: application.uid, token: access_token.token }
|
||||
end
|
||||
|
||||
it 'revokes the token' do
|
||||
|
||||
@ -35,7 +35,7 @@ describe RemoteFollowController do
|
||||
context 'when webfinger values are wrong' do
|
||||
it 'renders new when redirect url is nil' do
|
||||
resource_with_nil_link = double(link: nil)
|
||||
allow(Goldfinger).to receive(:finger).with('acct:user@example.com').and_return(resource_with_nil_link)
|
||||
allow_any_instance_of(WebfingerHelper).to receive(:webfinger!).with('acct:user@example.com').and_return(resource_with_nil_link)
|
||||
post :create, params: { account_username: @account.to_param, remote_follow: { acct: 'user@example.com' } }
|
||||
|
||||
expect(response).to render_template(:new)
|
||||
@ -45,7 +45,7 @@ describe RemoteFollowController do
|
||||
it 'renders new when template is nil' do
|
||||
link_with_nil_template = double(template: nil)
|
||||
resource_with_link = double(link: link_with_nil_template)
|
||||
allow(Goldfinger).to receive(:finger).with('acct:user@example.com').and_return(resource_with_link)
|
||||
allow_any_instance_of(WebfingerHelper).to receive(:webfinger!).with('acct:user@example.com').and_return(resource_with_link)
|
||||
post :create, params: { account_username: @account.to_param, remote_follow: { acct: 'user@example.com' } }
|
||||
|
||||
expect(response).to render_template(:new)
|
||||
@ -57,7 +57,7 @@ describe RemoteFollowController do
|
||||
before do
|
||||
link_with_template = double(template: 'http://example.com/follow_me?acct={uri}')
|
||||
resource_with_link = double(link: link_with_template)
|
||||
allow(Goldfinger).to receive(:finger).with('acct:user@example.com').and_return(resource_with_link)
|
||||
allow_any_instance_of(WebfingerHelper).to receive(:webfinger!).with('acct:user@example.com').and_return(resource_with_link)
|
||||
post :create, params: { account_username: @account.to_param, remote_follow: { acct: 'user@example.com' } }
|
||||
end
|
||||
|
||||
@ -79,7 +79,7 @@ describe RemoteFollowController do
|
||||
end
|
||||
|
||||
it 'renders new with error when goldfinger fails' do
|
||||
allow(Goldfinger).to receive(:finger).with('acct:user@example.com').and_raise(Goldfinger::Error)
|
||||
allow_any_instance_of(WebfingerHelper).to receive(:webfinger!).with('acct:user@example.com').and_raise(Goldfinger::Error)
|
||||
post :create, params: { account_username: @account.to_param, remote_follow: { acct: 'user@example.com' } }
|
||||
|
||||
expect(response).to render_template(:new)
|
||||
@ -87,7 +87,7 @@ describe RemoteFollowController do
|
||||
end
|
||||
|
||||
it 'renders new when occur HTTP::ConnectionError' do
|
||||
allow(Goldfinger).to receive(:finger).with('acct:user@unknown').and_raise(HTTP::ConnectionError)
|
||||
allow_any_instance_of(WebfingerHelper).to receive(:webfinger!).with('acct:user@unknown').and_raise(HTTP::ConnectionError)
|
||||
post :create, params: { account_username: @account.to_param, remote_follow: { acct: 'user@unknown' } }
|
||||
|
||||
expect(response).to render_template(:new)
|
||||
|
||||
@ -151,7 +151,7 @@ describe Settings::IdentityProofsController do
|
||||
@proof1 = Fabricate(:account_identity_proof, account: user.account)
|
||||
@proof2 = Fabricate(:account_identity_proof, account: user.account)
|
||||
allow_any_instance_of(AccountIdentityProof).to receive(:badge) { double(avatar_url: '', profile_url: '', proof_url: '') }
|
||||
allow_any_instance_of(AccountIdentityProof).to receive(:refresh!) { }
|
||||
allow_any_instance_of(AccountIdentityProof).to receive(:refresh!) {}
|
||||
end
|
||||
|
||||
it 'has the first proof username on the page' do
|
||||
@ -165,4 +165,22 @@ describe Settings::IdentityProofsController do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE #destroy' do
|
||||
before do
|
||||
allow_any_instance_of(ProofProvider::Keybase::Verifier).to receive(:valid?) { true }
|
||||
@proof1 = Fabricate(:account_identity_proof, account: user.account)
|
||||
allow_any_instance_of(AccountIdentityProof).to receive(:badge) { double(avatar_url: '', profile_url: '', proof_url: '') }
|
||||
allow_any_instance_of(AccountIdentityProof).to receive(:refresh!) {}
|
||||
delete :destroy, params: { id: @proof1.id }
|
||||
end
|
||||
|
||||
it 'redirects to :index' do
|
||||
expect(response).to redirect_to settings_identity_proofs_path
|
||||
end
|
||||
|
||||
it 'removes the proof' do
|
||||
expect(AccountIdentityProof.where(id: @proof1.id).count).to eq 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -5,128 +5,821 @@ require 'rails_helper'
|
||||
describe StatusesController do
|
||||
render_views
|
||||
|
||||
describe '#show' do
|
||||
context 'account is suspended' do
|
||||
it 'returns gone' do
|
||||
account = Fabricate(:account, suspended: true)
|
||||
status = Fabricate(:status, account: account)
|
||||
describe 'GET #show' do
|
||||
let(:account) { Fabricate(:account) }
|
||||
let(:status) { Fabricate(:status, account: account) }
|
||||
|
||||
context 'when account is suspended' do
|
||||
let(:account) { Fabricate(:account, suspended: true) }
|
||||
|
||||
before do
|
||||
get :show, params: { account_username: account.username, id: status.id }
|
||||
end
|
||||
|
||||
it 'returns http gone' do
|
||||
expect(response).to have_http_status(410)
|
||||
end
|
||||
end
|
||||
|
||||
context 'status is not permitted' do
|
||||
it 'raises ActiveRecord::RecordNotFound' do
|
||||
user = Fabricate(:user)
|
||||
status = Fabricate(:status)
|
||||
status.account.block!(user.account)
|
||||
context 'when status is a reblog' do
|
||||
let(:original_account) { Fabricate(:account, domain: 'example.com') }
|
||||
let(:original_status) { Fabricate(:status, account: original_account, url: 'https://example.com/123') }
|
||||
let(:status) { Fabricate(:status, account: account, reblog: original_status) }
|
||||
|
||||
sign_in(user)
|
||||
before do
|
||||
get :show, params: { account_username: status.account.username, id: status.id }
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'status is a reblog' do
|
||||
it 'redirects to the original status' do
|
||||
original_account = Fabricate(:account, domain: 'example.com')
|
||||
original_status = Fabricate(:status, account: original_account, uri: 'tag:example.com,2017:foo', url: 'https://example.com/123')
|
||||
status = Fabricate(:status, reblog: original_status)
|
||||
|
||||
get :show, params: { account_username: status.account.username, id: status.id }
|
||||
|
||||
expect(response).to redirect_to(original_status.url)
|
||||
end
|
||||
end
|
||||
|
||||
context 'account is not suspended and status is permitted' do
|
||||
it 'assigns @account' do
|
||||
status = Fabricate(:status)
|
||||
get :show, params: { account_username: status.account.username, id: status.id }
|
||||
expect(assigns(:account)).to eq status.account
|
||||
context 'when status is public' do
|
||||
before do
|
||||
get :show, params: { account_username: status.account.username, id: status.id, format: format }
|
||||
end
|
||||
|
||||
it 'assigns @status' do
|
||||
status = Fabricate(:status)
|
||||
get :show, params: { account_username: status.account.username, id: status.id }
|
||||
expect(assigns(:status)).to eq status
|
||||
context 'as HTML' do
|
||||
let(:format) { 'html' }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns Link header' do
|
||||
expect(response.headers['Link'].to_s).to include 'activity+json'
|
||||
end
|
||||
|
||||
it 'returns Vary header' do
|
||||
expect(response.headers['Vary']).to eq 'Accept'
|
||||
end
|
||||
|
||||
it 'returns public Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to include 'public'
|
||||
end
|
||||
|
||||
it 'renders status' do
|
||||
expect(response).to render_template(:show)
|
||||
expect(response.body).to include status.text
|
||||
end
|
||||
end
|
||||
|
||||
it 'assigns @ancestors for ancestors of the status if it is a reply' do
|
||||
ancestor = Fabricate(:status)
|
||||
status = Fabricate(:status, in_reply_to_id: ancestor.id)
|
||||
context 'as JSON' do
|
||||
let(:format) { 'json' }
|
||||
|
||||
get :show, params: { account_username: status.account.username, id: status.id }
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
expect(assigns(:ancestors)).to eq [ancestor]
|
||||
it 'returns Link header' do
|
||||
expect(response.headers['Link'].to_s).to include 'activity+json'
|
||||
end
|
||||
|
||||
it 'returns Vary header' do
|
||||
expect(response.headers['Vary']).to eq 'Accept'
|
||||
end
|
||||
|
||||
it 'returns public Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to include 'public'
|
||||
end
|
||||
|
||||
it 'returns Content-Type header' do
|
||||
expect(response.headers['Content-Type']).to include 'application/activity+json'
|
||||
end
|
||||
|
||||
it 'renders ActivityPub Note object' do
|
||||
json = body_as_json
|
||||
expect(json[:content]).to include status.text
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when status is private' do
|
||||
let(:status) { Fabricate(:status, account: account, visibility: :private) }
|
||||
|
||||
before do
|
||||
get :show, params: { account_username: status.account.username, id: status.id, format: format }
|
||||
end
|
||||
|
||||
it 'assigns @ancestors for [] if it is not a reply' do
|
||||
status = Fabricate(:status)
|
||||
get :show, params: { account_username: status.account.username, id: status.id }
|
||||
expect(assigns(:ancestors)).to eq []
|
||||
context 'as JSON' do
|
||||
let(:format) { 'json' }
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
it 'assigns @descendant_threads for a thread with several statuses' do
|
||||
status = Fabricate(:status)
|
||||
child = Fabricate(:status, in_reply_to_id: status.id)
|
||||
grandchild = Fabricate(:status, in_reply_to_id: child.id)
|
||||
context 'as HTML' do
|
||||
let(:format) { 'html' }
|
||||
|
||||
get :show, params: { account_username: status.account.username, id: status.id }
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
expect(assigns(:descendant_threads)[0][:statuses].pluck(:id)).to eq [child.id, grandchild.id]
|
||||
context 'when status is direct' do
|
||||
let(:status) { Fabricate(:status, account: account, visibility: :direct) }
|
||||
|
||||
before do
|
||||
get :show, params: { account_username: status.account.username, id: status.id, format: format }
|
||||
end
|
||||
|
||||
it 'assigns @descendant_threads for several threads sharing the same descendant' do
|
||||
status = Fabricate(:status)
|
||||
child = Fabricate(:status, in_reply_to_id: status.id)
|
||||
grandchildren = 2.times.map { Fabricate(:status, in_reply_to_id: child.id) }
|
||||
context 'as JSON' do
|
||||
let(:format) { 'json' }
|
||||
|
||||
get :show, params: { account_username: status.account.username, id: status.id }
|
||||
|
||||
expect(assigns(:descendant_threads)[0][:statuses].pluck(:id)).to eq [child.id, grandchildren[0].id]
|
||||
expect(assigns(:descendant_threads)[1][:statuses].pluck(:id)).to eq [grandchildren[1].id]
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
it 'assigns @max_descendant_thread_id for the last thread if it is hitting the status limit' do
|
||||
stub_const 'StatusControllerConcern::DESCENDANTS_LIMIT', 1
|
||||
status = Fabricate(:status)
|
||||
child = Fabricate(:status, in_reply_to_id: status.id)
|
||||
context 'as HTML' do
|
||||
let(:format) { 'html' }
|
||||
|
||||
get :show, params: { account_username: status.account.username, id: status.id }
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
expect(assigns(:descendant_threads)).to eq []
|
||||
expect(assigns(:max_descendant_thread_id)).to eq child.id
|
||||
context 'when signed-in' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
|
||||
before do
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
it 'assigns @descendant_threads for threads with :next_status key if they are hitting the depth limit' do
|
||||
stub_const 'StatusControllerConcern::DESCENDANTS_DEPTH_LIMIT', 2
|
||||
status = Fabricate(:status)
|
||||
child0 = Fabricate(:status, in_reply_to_id: status.id)
|
||||
child1 = Fabricate(:status, in_reply_to_id: child0.id)
|
||||
child2 = Fabricate(:status, in_reply_to_id: child0.id)
|
||||
context 'when account blocks user' do
|
||||
before do
|
||||
account.block!(user.account)
|
||||
get :show, params: { account_username: status.account.username, id: status.id }
|
||||
end
|
||||
|
||||
get :show, params: { account_username: status.account.username, id: status.id }
|
||||
|
||||
expect(assigns(:descendant_threads)[0][:statuses].pluck(:id)).not_to include child1.id
|
||||
expect(assigns(:descendant_threads)[1][:statuses].pluck(:id)).not_to include child2.id
|
||||
expect(assigns(:descendant_threads)[0][:next_status].id).to eq child1.id
|
||||
expect(assigns(:descendant_threads)[1][:next_status].id).to eq child2.id
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns a success' do
|
||||
status = Fabricate(:status)
|
||||
get :show, params: { account_username: status.account.username, id: status.id }
|
||||
context 'when status is public' do
|
||||
before do
|
||||
get :show, params: { account_username: status.account.username, id: status.id, format: format }
|
||||
end
|
||||
|
||||
context 'as HTML' do
|
||||
let(:format) { 'html' }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns Link header' do
|
||||
expect(response.headers['Link'].to_s).to include 'activity+json'
|
||||
end
|
||||
|
||||
it 'returns Vary header' do
|
||||
expect(response.headers['Vary']).to eq 'Accept'
|
||||
end
|
||||
|
||||
it 'returns no Cache-Control header' do
|
||||
expect(response.headers).to_not include 'Cache-Control'
|
||||
end
|
||||
|
||||
it 'renders status' do
|
||||
expect(response).to render_template(:show)
|
||||
expect(response.body).to include status.text
|
||||
end
|
||||
end
|
||||
|
||||
context 'as JSON' do
|
||||
let(:format) { 'json' }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns Link header' do
|
||||
expect(response.headers['Link'].to_s).to include 'activity+json'
|
||||
end
|
||||
|
||||
it 'returns Vary header' do
|
||||
expect(response.headers['Vary']).to eq 'Accept'
|
||||
end
|
||||
|
||||
it 'returns public Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to include 'public'
|
||||
end
|
||||
|
||||
it 'returns Content-Type header' do
|
||||
expect(response.headers['Content-Type']).to include 'application/activity+json'
|
||||
end
|
||||
|
||||
it 'renders ActivityPub Note object' do
|
||||
json = body_as_json
|
||||
expect(json[:content]).to include status.text
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when status is private' do
|
||||
let(:status) { Fabricate(:status, account: account, visibility: :private) }
|
||||
|
||||
context 'when user is authorized to see it' do
|
||||
before do
|
||||
user.account.follow!(account)
|
||||
get :show, params: { account_username: status.account.username, id: status.id, format: format }
|
||||
end
|
||||
|
||||
context 'as HTML' do
|
||||
let(:format) { 'html' }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns Link header' do
|
||||
expect(response.headers['Link'].to_s).to include 'activity+json'
|
||||
end
|
||||
|
||||
it 'returns Vary header' do
|
||||
expect(response.headers['Vary']).to eq 'Accept'
|
||||
end
|
||||
|
||||
it 'returns no Cache-Control header' do
|
||||
expect(response.headers).to_not include 'Cache-Control'
|
||||
end
|
||||
|
||||
it 'renders status' do
|
||||
expect(response).to render_template(:show)
|
||||
expect(response.body).to include status.text
|
||||
end
|
||||
end
|
||||
|
||||
context 'as JSON' do
|
||||
let(:format) { 'json' }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns Link header' do
|
||||
expect(response.headers['Link'].to_s).to include 'activity+json'
|
||||
end
|
||||
|
||||
it 'returns Vary header' do
|
||||
expect(response.headers['Vary']).to eq 'Accept'
|
||||
end
|
||||
|
||||
it 'returns private Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to include 'private'
|
||||
end
|
||||
|
||||
it 'returns Content-Type header' do
|
||||
expect(response.headers['Content-Type']).to include 'application/activity+json'
|
||||
end
|
||||
|
||||
it 'renders ActivityPub Note object' do
|
||||
json = body_as_json
|
||||
expect(json[:content]).to include status.text
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is not authorized to see it' do
|
||||
before do
|
||||
get :show, params: { account_username: status.account.username, id: status.id, format: format }
|
||||
end
|
||||
|
||||
context 'as JSON' do
|
||||
let(:format) { 'json' }
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'as HTML' do
|
||||
let(:format) { 'html' }
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when status is direct' do
|
||||
let(:status) { Fabricate(:status, account: account, visibility: :direct) }
|
||||
|
||||
context 'when user is authorized to see it' do
|
||||
before do
|
||||
Fabricate(:mention, account: user.account, status: status)
|
||||
get :show, params: { account_username: status.account.username, id: status.id, format: format }
|
||||
end
|
||||
|
||||
context 'as HTML' do
|
||||
let(:format) { 'html' }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns Link header' do
|
||||
expect(response.headers['Link'].to_s).to include 'activity+json'
|
||||
end
|
||||
|
||||
it 'returns Vary header' do
|
||||
expect(response.headers['Vary']).to eq 'Accept'
|
||||
end
|
||||
|
||||
it 'returns no Cache-Control header' do
|
||||
expect(response.headers).to_not include 'Cache-Control'
|
||||
end
|
||||
|
||||
it 'renders status' do
|
||||
expect(response).to render_template(:show)
|
||||
expect(response.body).to include status.text
|
||||
end
|
||||
end
|
||||
|
||||
context 'as JSON' do
|
||||
let(:format) { 'json' }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns Link header' do
|
||||
expect(response.headers['Link'].to_s).to include 'activity+json'
|
||||
end
|
||||
|
||||
it 'returns Vary header' do
|
||||
expect(response.headers['Vary']).to eq 'Accept'
|
||||
end
|
||||
|
||||
it 'returns private Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to include 'private'
|
||||
end
|
||||
|
||||
it 'returns Content-Type header' do
|
||||
expect(response.headers['Content-Type']).to include 'application/activity+json'
|
||||
end
|
||||
|
||||
it 'renders ActivityPub Note object' do
|
||||
json = body_as_json
|
||||
expect(json[:content]).to include status.text
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is not authorized to see it' do
|
||||
before do
|
||||
get :show, params: { account_username: status.account.username, id: status.id, format: format }
|
||||
end
|
||||
|
||||
context 'as JSON' do
|
||||
let(:format) { 'json' }
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'as HTML' do
|
||||
let(:format) { 'html' }
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with signature' do
|
||||
let(:remote_account) { Fabricate(:account, domain: 'example.com') }
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:signed_request_account).and_return(remote_account)
|
||||
end
|
||||
|
||||
context 'when account blocks account' do
|
||||
before do
|
||||
account.block!(remote_account)
|
||||
get :show, params: { account_username: status.account.username, id: status.id }
|
||||
end
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when account domain blocks account' do
|
||||
before do
|
||||
account.block_domain!(remote_account.domain)
|
||||
get :show, params: { account_username: status.account.username, id: status.id }
|
||||
end
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when status is public' do
|
||||
before do
|
||||
get :show, params: { account_username: status.account.username, id: status.id, format: format }
|
||||
end
|
||||
|
||||
context 'as HTML' do
|
||||
let(:format) { 'html' }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns Link header' do
|
||||
expect(response.headers['Link'].to_s).to include 'activity+json'
|
||||
end
|
||||
|
||||
it 'returns Vary header' do
|
||||
expect(response.headers['Vary']).to eq 'Accept'
|
||||
end
|
||||
|
||||
it 'returns no Cache-Control header' do
|
||||
expect(response.headers).to_not include 'Cache-Control'
|
||||
end
|
||||
|
||||
it 'renders status' do
|
||||
expect(response).to render_template(:show)
|
||||
expect(response.body).to include status.text
|
||||
end
|
||||
end
|
||||
|
||||
context 'as JSON' do
|
||||
let(:format) { 'json' }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns Link header' do
|
||||
expect(response.headers['Link'].to_s).to include 'activity+json'
|
||||
end
|
||||
|
||||
it 'returns Vary header' do
|
||||
expect(response.headers['Vary']).to eq 'Accept'
|
||||
end
|
||||
|
||||
it 'returns public Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to include 'public'
|
||||
end
|
||||
|
||||
it 'returns Content-Type header' do
|
||||
expect(response.headers['Content-Type']).to include 'application/activity+json'
|
||||
end
|
||||
|
||||
it 'renders ActivityPub Note object' do
|
||||
json = body_as_json
|
||||
expect(json[:content]).to include status.text
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when status is private' do
|
||||
let(:status) { Fabricate(:status, account: account, visibility: :private) }
|
||||
|
||||
context 'when user is authorized to see it' do
|
||||
before do
|
||||
remote_account.follow!(account)
|
||||
get :show, params: { account_username: status.account.username, id: status.id, format: format }
|
||||
end
|
||||
|
||||
context 'as HTML' do
|
||||
let(:format) { 'html' }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns Link header' do
|
||||
expect(response.headers['Link'].to_s).to include 'activity+json'
|
||||
end
|
||||
|
||||
it 'returns Vary header' do
|
||||
expect(response.headers['Vary']).to eq 'Accept'
|
||||
end
|
||||
|
||||
it 'returns no Cache-Control header' do
|
||||
expect(response.headers).to_not include 'Cache-Control'
|
||||
end
|
||||
|
||||
it 'renders status' do
|
||||
expect(response).to render_template(:show)
|
||||
expect(response.body).to include status.text
|
||||
end
|
||||
end
|
||||
|
||||
context 'as JSON' do
|
||||
let(:format) { 'json' }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns Link header' do
|
||||
expect(response.headers['Link'].to_s).to include 'activity+json'
|
||||
end
|
||||
|
||||
it 'returns Vary header' do
|
||||
expect(response.headers['Vary']).to eq 'Accept'
|
||||
end
|
||||
|
||||
it 'returns private Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to include 'private'
|
||||
end
|
||||
|
||||
it 'returns Content-Type header' do
|
||||
expect(response.headers['Content-Type']).to include 'application/activity+json'
|
||||
end
|
||||
|
||||
it 'renders ActivityPub Note object' do
|
||||
json = body_as_json
|
||||
expect(json[:content]).to include status.text
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is not authorized to see it' do
|
||||
before do
|
||||
get :show, params: { account_username: status.account.username, id: status.id, format: format }
|
||||
end
|
||||
|
||||
context 'as JSON' do
|
||||
let(:format) { 'json' }
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'as HTML' do
|
||||
let(:format) { 'html' }
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when status is direct' do
|
||||
let(:status) { Fabricate(:status, account: account, visibility: :direct) }
|
||||
|
||||
context 'when user is authorized to see it' do
|
||||
before do
|
||||
Fabricate(:mention, account: remote_account, status: status)
|
||||
get :show, params: { account_username: status.account.username, id: status.id, format: format }
|
||||
end
|
||||
|
||||
context 'as HTML' do
|
||||
let(:format) { 'html' }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns Link header' do
|
||||
expect(response.headers['Link'].to_s).to include 'activity+json'
|
||||
end
|
||||
|
||||
it 'returns Vary header' do
|
||||
expect(response.headers['Vary']).to eq 'Accept'
|
||||
end
|
||||
|
||||
it 'returns no Cache-Control header' do
|
||||
expect(response.headers).to_not include 'Cache-Control'
|
||||
end
|
||||
|
||||
it 'renders status' do
|
||||
expect(response).to render_template(:show)
|
||||
expect(response.body).to include status.text
|
||||
end
|
||||
end
|
||||
|
||||
context 'as JSON' do
|
||||
let(:format) { 'json' }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns Link header' do
|
||||
expect(response.headers['Link'].to_s).to include 'activity+json'
|
||||
end
|
||||
|
||||
it 'returns Vary header' do
|
||||
expect(response.headers['Vary']).to eq 'Accept'
|
||||
end
|
||||
|
||||
it 'returns private Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to include 'private'
|
||||
end
|
||||
|
||||
it 'returns Content-Type header' do
|
||||
expect(response.headers['Content-Type']).to include 'application/activity+json'
|
||||
end
|
||||
|
||||
it 'renders ActivityPub Note object' do
|
||||
json = body_as_json
|
||||
expect(json[:content]).to include status.text
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is not authorized to see it' do
|
||||
before do
|
||||
get :show, params: { account_username: status.account.username, id: status.id, format: format }
|
||||
end
|
||||
|
||||
context 'as JSON' do
|
||||
let(:format) { 'json' }
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'as HTML' do
|
||||
let(:format) { 'html' }
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #activity' do
|
||||
let(:account) { Fabricate(:account) }
|
||||
let(:status) { Fabricate(:status, account: account) }
|
||||
|
||||
context 'when account is suspended' do
|
||||
let(:account) { Fabricate(:account, suspended: true) }
|
||||
|
||||
before do
|
||||
get :activity, params: { account_username: account.username, id: status.id }
|
||||
end
|
||||
|
||||
it 'returns http gone' do
|
||||
expect(response).to have_http_status(410)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when status is public' do
|
||||
pending
|
||||
end
|
||||
|
||||
context 'when status is private' do
|
||||
pending
|
||||
end
|
||||
|
||||
context 'when status is direct' do
|
||||
pending
|
||||
end
|
||||
|
||||
context 'when signed-in' do
|
||||
context 'when status is public' do
|
||||
pending
|
||||
end
|
||||
|
||||
context 'when status is private' do
|
||||
context 'when user is authorized to see it' do
|
||||
pending
|
||||
end
|
||||
|
||||
context 'when user is not authorized to see it' do
|
||||
pending
|
||||
end
|
||||
end
|
||||
|
||||
context 'when status is direct' do
|
||||
context 'when user is authorized to see it' do
|
||||
pending
|
||||
end
|
||||
|
||||
context 'when user is not authorized to see it' do
|
||||
pending
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with signature' do
|
||||
context 'when status is public' do
|
||||
pending
|
||||
end
|
||||
|
||||
context 'when status is private' do
|
||||
context 'when user is authorized to see it' do
|
||||
pending
|
||||
end
|
||||
|
||||
context 'when user is not authorized to see it' do
|
||||
pending
|
||||
end
|
||||
end
|
||||
|
||||
context 'when status is direct' do
|
||||
context 'when user is authorized to see it' do
|
||||
pending
|
||||
end
|
||||
|
||||
context 'when user is not authorized to see it' do
|
||||
pending
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #embed' do
|
||||
let(:account) { Fabricate(:account) }
|
||||
let(:status) { Fabricate(:status, account: account) }
|
||||
|
||||
context 'when account is suspended' do
|
||||
let(:account) { Fabricate(:account, suspended: true) }
|
||||
|
||||
before do
|
||||
get :embed, params: { account_username: account.username, id: status.id }
|
||||
end
|
||||
|
||||
it 'returns http gone' do
|
||||
expect(response).to have_http_status(410)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when status is a reblog' do
|
||||
let(:original_account) { Fabricate(:account, domain: 'example.com') }
|
||||
let(:original_status) { Fabricate(:status, account: original_account, url: 'https://example.com/123') }
|
||||
let(:status) { Fabricate(:status, account: account, reblog: original_status) }
|
||||
|
||||
before do
|
||||
get :embed, params: { account_username: status.account.username, id: status.id }
|
||||
end
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when status is public' do
|
||||
before do
|
||||
get :embed, params: { account_username: status.account.username, id: status.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'renders statuses/show' do
|
||||
status = Fabricate(:status)
|
||||
get :show, params: { account_username: status.account.username, id: status.id }
|
||||
expect(response).to render_template 'statuses/show'
|
||||
it 'returns Link header' do
|
||||
expect(response.headers['Link'].to_s).to include 'activity+json'
|
||||
end
|
||||
|
||||
it 'returns Vary header' do
|
||||
expect(response.headers['Vary']).to eq 'Accept'
|
||||
end
|
||||
|
||||
it 'returns public Cache-Control header' do
|
||||
expect(response.headers['Cache-Control']).to include 'public'
|
||||
end
|
||||
|
||||
it 'renders status' do
|
||||
expect(response).to render_template(:embed)
|
||||
expect(response.body).to include status.text
|
||||
end
|
||||
end
|
||||
|
||||
context 'when status is private' do
|
||||
let(:status) { Fabricate(:status, account: account, visibility: :private) }
|
||||
|
||||
before do
|
||||
get :embed, params: { account_username: status.account.username, id: status.id }
|
||||
end
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when status is direct' do
|
||||
let(:status) { Fabricate(:status, account: account, visibility: :direct) }
|
||||
|
||||
before do
|
||||
get :embed, params: { account_username: status.account.username, id: status.id }
|
||||
end
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
Fabricator(:status_pin) do
|
||||
account
|
||||
status
|
||||
status { |attrs| Fabricate(:status, account: attrs[:account], visibility: :public) }
|
||||
end
|
||||
|
||||
3
spec/fabricators/unavailable_domain_fabricator.rb
Normal file
3
spec/fabricators/unavailable_domain_fabricator.rb
Normal file
@ -0,0 +1,3 @@
|
||||
Fabricator(:unavailable_domain) do
|
||||
domain { Faker::Internet.domain }
|
||||
end
|
||||
@ -39,7 +39,7 @@ feature 'Profile' do
|
||||
visit settings_profile_path
|
||||
fill_in 'Display name', with: 'Bob'
|
||||
fill_in 'Bio', with: 'Bob is silent'
|
||||
click_on 'Save changes'
|
||||
first('.btn[type=submit]').click
|
||||
is_expected.to have_content 'Changes successfully saved!'
|
||||
|
||||
# View my own public profile and see the changes
|
||||
|
||||
@ -31,242 +31,4 @@ RSpec.describe Admin::ActionLogsHelper, type: :helper do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#relevant_log_changes' do
|
||||
let(:log) { double(target_type: target_type, action: log_action, recorded_changes: recorded_changes) }
|
||||
let(:recorded_changes) { double }
|
||||
|
||||
after do
|
||||
hoge.relevant_log_changes(log)
|
||||
end
|
||||
|
||||
context "log.target_type == 'CustomEmoji' && [:enable, :disable, :destroy].include?(log.action)" do
|
||||
let(:target_type) { 'CustomEmoji' }
|
||||
let(:log_action) { :enable }
|
||||
|
||||
it "calls log.recorded_changes.slice('domain')" do
|
||||
expect(recorded_changes).to receive(:slice).with('domain')
|
||||
end
|
||||
end
|
||||
|
||||
context "log.target_type == 'CustomEmoji' && log.action == :update" do
|
||||
let(:target_type) { 'CustomEmoji' }
|
||||
let(:log_action) { :update }
|
||||
|
||||
it "calls log.recorded_changes.slice('domain', 'visible_in_picker')" do
|
||||
expect(recorded_changes).to receive(:slice).with('domain', 'visible_in_picker')
|
||||
end
|
||||
end
|
||||
|
||||
context "log.target_type == 'User' && [:promote, :demote].include?(log.action)" do
|
||||
let(:target_type) { 'User' }
|
||||
let(:log_action) { :promote }
|
||||
|
||||
it "calls log.recorded_changes.slice('moderator', 'admin')" do
|
||||
expect(recorded_changes).to receive(:slice).with('moderator', 'admin')
|
||||
end
|
||||
end
|
||||
|
||||
context "log.target_type == 'User' && [:change_email].include?(log.action)" do
|
||||
let(:target_type) { 'User' }
|
||||
let(:log_action) { :change_email }
|
||||
|
||||
it "calls log.recorded_changes.slice('email', 'unconfirmed_email')" do
|
||||
expect(recorded_changes).to receive(:slice).with('email', 'unconfirmed_email')
|
||||
end
|
||||
end
|
||||
|
||||
context "log.target_type == 'DomainBlock'" do
|
||||
let(:target_type) { 'DomainBlock' }
|
||||
let(:log_action) { nil }
|
||||
|
||||
it "calls log.recorded_changes.slice('severity', 'reject_media')" do
|
||||
expect(recorded_changes).to receive(:slice).with('severity', 'reject_media')
|
||||
end
|
||||
end
|
||||
|
||||
context "log.target_type == 'Status' && log.action == :update" do
|
||||
let(:target_type) { 'Status' }
|
||||
let(:log_action) { :update }
|
||||
|
||||
it "log.recorded_changes.slice('sensitive')" do
|
||||
expect(recorded_changes).to receive(:slice).with('sensitive')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#log_extra_attributes' do
|
||||
after do
|
||||
hoge.log_extra_attributes(hoge: 'hoge')
|
||||
end
|
||||
|
||||
it "calls content_tag(:span, key, class: 'diff-key')" do
|
||||
allow(hoge).to receive(:log_change).with(anything)
|
||||
expect(hoge).to receive(:content_tag).with(:span, :hoge, class: 'diff-key')
|
||||
end
|
||||
|
||||
it 'calls safe_join twice' do
|
||||
expect(hoge).to receive(:safe_join).with(
|
||||
['<span class="diff-key">hoge</span>',
|
||||
'=',
|
||||
'<span class="diff-neutral">hoge</span>']
|
||||
)
|
||||
|
||||
expect(hoge).to receive(:safe_join).with([nil], ' ')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#log_change' do
|
||||
after do
|
||||
hoge.log_change(val)
|
||||
end
|
||||
|
||||
context '!val.is_a?(Array)' do
|
||||
let(:val) { 'hoge' }
|
||||
|
||||
it "calls content_tag(:span, val, class: 'diff-neutral')" do
|
||||
expect(hoge).to receive(:content_tag).with(:span, val, class: 'diff-neutral')
|
||||
end
|
||||
end
|
||||
|
||||
context 'val.is_a?(Array)' do
|
||||
let(:val) { %w(foo bar) }
|
||||
|
||||
it 'calls #content_tag twice and #safe_join' do
|
||||
expect(hoge).to receive(:content_tag).with(:span, 'foo', class: 'diff-old')
|
||||
expect(hoge).to receive(:content_tag).with(:span, 'bar', class: 'diff-new')
|
||||
expect(hoge).to receive(:safe_join).with([nil, nil], '→')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#icon_for_log' do
|
||||
subject { hoge.icon_for_log(log) }
|
||||
|
||||
context "log.target_type == 'Account'" do
|
||||
let(:log) { double(target_type: 'Account') }
|
||||
|
||||
it 'returns "user"' do
|
||||
expect(subject).to be 'user'
|
||||
end
|
||||
end
|
||||
|
||||
context "log.target_type == 'User'" do
|
||||
let(:log) { double(target_type: 'User') }
|
||||
|
||||
it 'returns "user"' do
|
||||
expect(subject).to be 'user'
|
||||
end
|
||||
end
|
||||
|
||||
context "log.target_type == 'CustomEmoji'" do
|
||||
let(:log) { double(target_type: 'CustomEmoji') }
|
||||
|
||||
it 'returns "file"' do
|
||||
expect(subject).to be 'file'
|
||||
end
|
||||
end
|
||||
|
||||
context "log.target_type == 'Report'" do
|
||||
let(:log) { double(target_type: 'Report') }
|
||||
|
||||
it 'returns "flag"' do
|
||||
expect(subject).to be 'flag'
|
||||
end
|
||||
end
|
||||
|
||||
context "log.target_type == 'DomainBlock'" do
|
||||
let(:log) { double(target_type: 'DomainBlock') }
|
||||
|
||||
it 'returns "lock"' do
|
||||
expect(subject).to be 'lock'
|
||||
end
|
||||
end
|
||||
|
||||
context "log.target_type == 'EmailDomainBlock'" do
|
||||
let(:log) { double(target_type: 'EmailDomainBlock') }
|
||||
|
||||
it 'returns "envelope"' do
|
||||
expect(subject).to be 'envelope'
|
||||
end
|
||||
end
|
||||
|
||||
context "log.target_type == 'Status'" do
|
||||
let(:log) { double(target_type: 'Status') }
|
||||
|
||||
it 'returns "pencil"' do
|
||||
expect(subject).to be 'pencil'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#class_for_log_icon' do
|
||||
subject { hoge.class_for_log_icon(log) }
|
||||
|
||||
%i(enable unsuspend unsilence confirm promote resolve).each do |action|
|
||||
context "log.action == #{action}" do
|
||||
let(:log) { double(action: action) }
|
||||
|
||||
it 'returns "positive"' do
|
||||
expect(subject).to be 'positive'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'log.action == :create' do
|
||||
context 'opposite_verbs?(log)' do
|
||||
let(:log) { double(action: :create, target_type: 'DomainBlock') }
|
||||
|
||||
it 'returns "negative"' do
|
||||
expect(subject).to be 'negative'
|
||||
end
|
||||
end
|
||||
|
||||
context '!opposite_verbs?(log)' do
|
||||
let(:log) { double(action: :create, target_type: '') }
|
||||
|
||||
it 'returns "positive"' do
|
||||
expect(subject).to be 'positive'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
%i(update reset_password disable_2fa memorialize change_email).each do |action|
|
||||
context "log.action == #{action}" do
|
||||
let(:log) { double(action: action) }
|
||||
|
||||
it 'returns "neutral"' do
|
||||
expect(subject).to be 'neutral'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
%i(demote silence disable suspend remove_avatar remove_header reopen).each do |action|
|
||||
context "log.action == #{action}" do
|
||||
let(:log) { double(action: action) }
|
||||
|
||||
it 'returns "negative"' do
|
||||
expect(subject).to be 'negative'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'log.action == :destroy' do
|
||||
context 'opposite_verbs?(log)' do
|
||||
let(:log) { double(action: :destroy, target_type: 'DomainBlock') }
|
||||
|
||||
it 'returns "positive"' do
|
||||
expect(subject).to be 'positive'
|
||||
end
|
||||
end
|
||||
|
||||
context '!opposite_verbs?(log)' do
|
||||
let(:log) { double(action: :destroy, target_type: '') }
|
||||
|
||||
it 'returns "negative"' do
|
||||
expect(subject).to be 'negative'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -22,11 +22,11 @@ describe DeliveryFailureTracker do
|
||||
|
||||
describe '#track_failure!' do
|
||||
it 'marks URL as unavailable after 7 days of being called' do
|
||||
6.times { |i| Redis.current.sadd('exhausted_deliveries:http://example.com/inbox', i) }
|
||||
6.times { |i| Redis.current.sadd('exhausted_deliveries:example.com', i) }
|
||||
subject.track_failure!
|
||||
|
||||
expect(subject.days).to eq 7
|
||||
expect(described_class.unavailable?('http://example.com/inbox')).to be true
|
||||
expect(described_class.available?('http://example.com/inbox')).to be false
|
||||
end
|
||||
|
||||
it 'repeated calls on the same day do not count' do
|
||||
@ -37,35 +37,27 @@ describe DeliveryFailureTracker do
|
||||
end
|
||||
end
|
||||
|
||||
describe '.filter' do
|
||||
describe '.without_unavailable' do
|
||||
before do
|
||||
Redis.current.sadd('unavailable_inboxes', 'http://example.com/unavailable/inbox')
|
||||
Fabricate(:unavailable_domain, domain: 'foo.bar')
|
||||
end
|
||||
|
||||
it 'removes URLs that are unavailable' do
|
||||
result = described_class.filter(['http://example.com/good/inbox', 'http://example.com/unavailable/inbox'])
|
||||
results = described_class.without_unavailable(['http://example.com/good/inbox', 'http://foo.bar/unavailable/inbox'])
|
||||
|
||||
expect(result).to include('http://example.com/good/inbox')
|
||||
expect(result).to_not include('http://example.com/unavailable/inbox')
|
||||
expect(results).to include('http://example.com/good/inbox')
|
||||
expect(results).to_not include('http://foo.bar/unavailable/inbox')
|
||||
end
|
||||
end
|
||||
|
||||
describe '.track_inverse_success!' do
|
||||
let(:from_account) { Fabricate(:account, inbox_url: 'http://example.com/inbox', shared_inbox_url: 'http://example.com/shared/inbox') }
|
||||
|
||||
describe '.reset!' do
|
||||
before do
|
||||
Redis.current.sadd('unavailable_inboxes', 'http://example.com/inbox')
|
||||
Redis.current.sadd('unavailable_inboxes', 'http://example.com/shared/inbox')
|
||||
|
||||
described_class.track_inverse_success!(from_account)
|
||||
Fabricate(:unavailable_domain, domain: 'foo.bar')
|
||||
described_class.reset!('https://foo.bar/inbox')
|
||||
end
|
||||
|
||||
it 'marks inbox URL as available again' do
|
||||
expect(described_class.available?('http://example.com/inbox')).to be true
|
||||
end
|
||||
|
||||
it 'marks shared inbox URL as available again' do
|
||||
expect(described_class.available?('http://example.com/shared/inbox')).to be true
|
||||
expect(described_class.available?('http://foo.bar/inbox')).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
63
spec/lib/rss/serializer_spec.rb
Normal file
63
spec/lib/rss/serializer_spec.rb
Normal file
@ -0,0 +1,63 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe RSS::Serializer do
|
||||
describe '#status_title' do
|
||||
let(:text) { 'This is a toot' }
|
||||
let(:spoiler) { '' }
|
||||
let(:sensitive) { false }
|
||||
let(:reblog) { nil }
|
||||
let(:account) { Fabricate(:account) }
|
||||
let(:status) { Fabricate(:status, account: account, text: text, spoiler_text: spoiler, sensitive: sensitive, reblog: reblog) }
|
||||
|
||||
subject { RSS::Serializer.new.send(:status_title, status) }
|
||||
|
||||
context 'if destroyed?' do
|
||||
it 'returns "#{account.acct} deleted status"' do
|
||||
status.destroy!
|
||||
expect(subject).to eq "#{account.acct} deleted status"
|
||||
end
|
||||
end
|
||||
|
||||
context 'on a toot with long text' do
|
||||
let(:text) { "This toot's text is longer than the allowed number of characters" }
|
||||
|
||||
it 'truncates toot text appropriately' do
|
||||
expect(subject).to eq "#{account.acct}: “This toot's text is longer tha…”"
|
||||
end
|
||||
end
|
||||
|
||||
context 'on a toot with long text with a newline' do
|
||||
let(:text) { "This toot's text is longer\nthan the allowed number of characters" }
|
||||
|
||||
it 'truncates toot text appropriately' do
|
||||
expect(subject).to eq "#{account.acct}: “This toot's text is longer…”"
|
||||
end
|
||||
end
|
||||
|
||||
context 'on a toot with a content warning' do
|
||||
let(:spoiler) { 'long toot' }
|
||||
|
||||
it 'displays spoiler text instead of toot content' do
|
||||
expect(subject).to eq "#{account.acct}: CW “long toot”"
|
||||
end
|
||||
end
|
||||
|
||||
context 'on a toot with sensitive media' do
|
||||
let(:sensitive) { true }
|
||||
|
||||
it 'displays that the media is sensitive' do
|
||||
expect(subject).to eq "#{account.acct}: “This is a toot” (sensitive)"
|
||||
end
|
||||
end
|
||||
|
||||
context 'on a reblog' do
|
||||
let(:reblog) { Fabricate(:status, text: 'This is a toot') }
|
||||
|
||||
it 'display that the toot is a reblog' do
|
||||
expect(subject).to eq "#{account.acct} boosted #{reblog.account.acct}: “This is a toot”"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
37
spec/models/relationship_filter_spec.rb
Normal file
37
spec/models/relationship_filter_spec.rb
Normal file
@ -0,0 +1,37 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe RelationshipFilter do
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
describe '#results' do
|
||||
context 'when default params are used' do
|
||||
let(:subject) do
|
||||
RelationshipFilter.new(account, 'order' => 'active').results
|
||||
end
|
||||
|
||||
before do
|
||||
add_following_account_with(last_status_at: 7.days.ago)
|
||||
add_following_account_with(last_status_at: 1.day.ago)
|
||||
add_following_account_with(last_status_at: 3.days.ago)
|
||||
end
|
||||
|
||||
it 'returns followings ordered by last activity' do
|
||||
expected_result = account.following.eager_load(:account_stat).reorder(nil).by_recent_status
|
||||
|
||||
expect(subject).to eq expected_result
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def add_following_account_with(last_status_at:)
|
||||
following_account = Fabricate(:account)
|
||||
Fabricate(:account_stat, account: following_account,
|
||||
last_status_at: last_status_at,
|
||||
statuses_count: 1,
|
||||
following_count: 0,
|
||||
followers_count: 0)
|
||||
Fabricate(:follow, account: account, target_account: following_account).account
|
||||
end
|
||||
end
|
||||
@ -82,39 +82,6 @@ RSpec.describe Status, type: :model do
|
||||
end
|
||||
end
|
||||
|
||||
describe '#title' do
|
||||
# rubocop:disable Style/InterpolationCheck
|
||||
|
||||
let(:account) { subject.account }
|
||||
|
||||
context 'if destroyed?' do
|
||||
it 'returns "#{account.acct} deleted status"' do
|
||||
subject.destroy!
|
||||
expect(subject.title).to eq "#{account.acct} deleted status"
|
||||
end
|
||||
end
|
||||
|
||||
context 'unless destroyed?' do
|
||||
context 'if reblog?' do
|
||||
it 'returns "#{account.acct} shared #{reblog.account.acct}\'s: #{preview}"' do
|
||||
reblog = subject.reblog = other
|
||||
preview = subject.text.slice(0, 10).split("\n")[0]
|
||||
expect(subject.title).to(
|
||||
eq "#{account.acct} shared #{reblog.account.acct}'s: #{preview}"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'unless reblog?' do
|
||||
it 'returns "#{account.acct}: #{preview}"' do
|
||||
subject.reblog = nil
|
||||
preview = subject.text.slice(0, 20).split("\n")[0]
|
||||
expect(subject.title).to eq "#{account.acct}: #{preview}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#hidden?' do
|
||||
context 'if private_visibility?' do
|
||||
it 'returns true' do
|
||||
@ -407,6 +374,33 @@ RSpec.describe Status, type: :model do
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a remote_only option set' do
|
||||
let!(:local_account) { Fabricate(:account, domain: nil) }
|
||||
let!(:remote_account) { Fabricate(:account, domain: 'test.com') }
|
||||
let!(:local_status) { Fabricate(:status, account: local_account) }
|
||||
let!(:remote_status) { Fabricate(:status, account: remote_account) }
|
||||
|
||||
subject { Status.as_public_timeline(viewer, :remote) }
|
||||
|
||||
context 'without a viewer' do
|
||||
let(:viewer) { nil }
|
||||
|
||||
it 'does not include local instances statuses' do
|
||||
expect(subject).not_to include(local_status)
|
||||
expect(subject).to include(remote_status)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a viewer' do
|
||||
let(:viewer) { Fabricate(:account, username: 'viewer') }
|
||||
|
||||
it 'does not include local instances statuses' do
|
||||
expect(subject).not_to include(local_status)
|
||||
expect(subject).to include(remote_status)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with an account passed in' do
|
||||
before do
|
||||
@account = Fabricate(:account)
|
||||
|
||||
4
spec/models/unavailable_domain_spec.rb
Normal file
4
spec/models/unavailable_domain_spec.rb
Normal file
@ -0,0 +1,4 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe UnavailableDomain, type: :model do
|
||||
end
|
||||
@ -15,7 +15,7 @@ ActiveRecord::Migration.maintain_test_schema!
|
||||
WebMock.disable_net_connect!(allow: Chewy.settings[:host])
|
||||
Redis.current = Redis::Namespace.new("mastodon_test#{ENV['TEST_ENV_NUMBER']}", redis: Redis.current)
|
||||
Sidekiq::Testing.inline!
|
||||
Sidekiq::Logging.logger = nil
|
||||
Sidekiq.logger = nil
|
||||
|
||||
Devise::Test::ControllerHelpers.module_eval do
|
||||
alias_method :original_sign_in, :sign_in
|
||||
|
||||
@ -21,7 +21,11 @@ RSpec.describe FetchResourceService, type: :service do
|
||||
|
||||
context 'when OpenSSL::SSL::SSLError is raised' do
|
||||
before do
|
||||
allow(Request).to receive_message_chain(:new, :add_headers, :on_behalf_of, :perform).and_raise(OpenSSL::SSL::SSLError)
|
||||
request = double()
|
||||
allow(Request).to receive(:new).and_return(request)
|
||||
allow(request).to receive(:add_headers)
|
||||
allow(request).to receive(:on_behalf_of)
|
||||
allow(request).to receive(:perform).and_raise(OpenSSL::SSL::SSLError)
|
||||
end
|
||||
|
||||
it { is_expected.to be_nil }
|
||||
@ -29,7 +33,11 @@ RSpec.describe FetchResourceService, type: :service do
|
||||
|
||||
context 'when HTTP::ConnectionError is raised' do
|
||||
before do
|
||||
allow(Request).to receive_message_chain(:new, :add_headers, :on_behalf_of, :perform).and_raise(HTTP::ConnectionError)
|
||||
request = double()
|
||||
allow(Request).to receive(:new).and_return(request)
|
||||
allow(request).to receive(:add_headers)
|
||||
allow(request).to receive(:on_behalf_of)
|
||||
allow(request).to receive(:perform).and_raise(HTTP::ConnectionError)
|
||||
end
|
||||
|
||||
it { is_expected.to be_nil }
|
||||
|
||||
@ -91,10 +91,6 @@ RSpec.describe ImportService, type: :service do
|
||||
|
||||
let(:csv) { attachment_fixture('mute-imports.txt') }
|
||||
|
||||
before do
|
||||
allow(NotificationWorker).to receive(:perform_async)
|
||||
end
|
||||
|
||||
describe 'when no accounts are followed' do
|
||||
let(:import) { Import.create(account: account, type: 'following', data: csv) }
|
||||
it 'follows the listed accounts, including boosts' do
|
||||
@ -135,10 +131,6 @@ RSpec.describe ImportService, type: :service do
|
||||
|
||||
let(:csv) { attachment_fixture('new-following-imports.txt') }
|
||||
|
||||
before do
|
||||
allow(NotificationWorker).to receive(:perform_async)
|
||||
end
|
||||
|
||||
describe 'when no accounts are followed' do
|
||||
let(:import) { Import.create(account: account, type: 'following', data: csv) }
|
||||
it 'follows the listed accounts, respecting boosts' do
|
||||
|
||||
@ -79,6 +79,13 @@ RSpec.describe PostStatusService, type: :service do
|
||||
expect(status.spoiler_text).to eq spoiler_text
|
||||
end
|
||||
|
||||
it 'creates a sensitive status when there is a CW but no text' do
|
||||
status = subject.call(Fabricate(:account), text: '', spoiler_text: 'foo')
|
||||
|
||||
expect(status).to be_persisted
|
||||
expect(status).to be_sensitive
|
||||
end
|
||||
|
||||
it 'creates a status with empty default spoiler text' do
|
||||
status = create_status_with_options(spoiler_text: nil)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user