diff options
author | Thibaut Girka <thib@sitedethib.com> | 2020-05-03 21:20:42 +0200 |
---|---|---|
committer | Thibaut Girka <thib@sitedethib.com> | 2020-05-03 21:23:49 +0200 |
commit | a22e6a368333f3563f8d8d56d8e98d02088e82dc (patch) | |
tree | 4146f9e8afe4257c6f33bc695a3cfbfb89aa81b6 /spec/controllers | |
parent | 9c61dadc0db7009853c6b2345a02c3b219022929 (diff) | |
parent | e223fd8c6190661237ea43e7773e47513c48fd46 (diff) |
Merge branch 'master' into glitch-soc/merge-upstream
Conflicts: - `app/controllers/statuses_controller.rb`: Upstream disabled the embed controller for reblogs. Not a real conflict, but glitch-soc has an extra line to deal with its theming system. Ported upstream changes. - `app/javascript/packs/public.js`: Upstream made changes to get rid of most inline CSS, this changes javascript for public pages, which in glitch are split between different files. Ported those changes. - `app/models/status.rb`: Upstream changed the block check in `Status#permitted_for` to include domain-block checks. Not a real conflict with glitch-soc, but our scope is slightly different, as our scope for unauthenticated access do not include instance-local toots. Ported upstream changes. - `app/serializers/rest/instance_serializer.rb`: Not a real conflict, upstream added a new field to the instance serializer, the conflict is one line above since we added more of that. Ported upstream changes. - `app/views/settings/profiles/show.html.haml`: Upstream got rid of most inline CSS and moved hidden elements to data attributes in the process, in fields were we have different values. Ported upstream changes while keeping our glitch-specific values. - `app/views/statuses/_simple_status.html.haml`: Upstream got rid of inline CSS on an HAML line we treat differently, stripping empty text nodes. Ported upstream changes to the style attribute, keeping the empty text node stripping behavior.
Diffstat (limited to 'spec/controllers')
-rw-r--r-- | spec/controllers/activitypub/collections_controller_spec.rb | 132 | ||||
-rw-r--r-- | spec/controllers/activitypub/inboxes_controller_spec.rb | 28 | ||||
-rw-r--r-- | spec/controllers/activitypub/outboxes_controller_spec.rb | 170 | ||||
-rw-r--r-- | spec/controllers/activitypub/replies_controller_spec.rb | 196 | ||||
-rw-r--r-- | spec/controllers/statuses_controller_spec.rb | 843 |
5 files changed, 1265 insertions, 104 deletions
diff --git a/spec/controllers/activitypub/collections_controller_spec.rb b/spec/controllers/activitypub/collections_controller_spec.rb index 34114cc85..56be49be3 100644 --- a/spec/controllers/activitypub/collections_controller_spec.rb +++ b/spec/controllers/activitypub/collections_controller_spec.rb @@ -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 diff --git a/spec/controllers/activitypub/inboxes_controller_spec.rb b/spec/controllers/activitypub/inboxes_controller_spec.rb index a9ee75490..f3bc23953 100644 --- a/spec/controllers/activitypub/inboxes_controller_spec.rb +++ b/spec/controllers/activitypub/inboxes_controller_spec.rb @@ -3,25 +3,31 @@ require 'rails_helper' RSpec.describe ActivityPub::InboxesController, type: :controller do + let(:remote_account) { nil } + + before do + allow(controller).to receive(:signed_request_account).and_return(remote_account) + end + 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 + 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 diff --git a/spec/controllers/activitypub/outboxes_controller_spec.rb b/spec/controllers/activitypub/outboxes_controller_spec.rb index 47460b22c..03490533d 100644 --- a/spec/controllers/activitypub/outboxes_controller_spec.rb +++ b/spec/controllers/activitypub/outboxes_controller_spec.rb @@ -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 } - end + 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 http success' do - expect(response).to have_http_status(200) + 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 application/activity+json' do - expect(response.content_type).to eq 'application/activity+json' + context 'with signature' do + let(:remote_account) { Fabricate(:account, domain: 'example.com') } + let(:page) { 'true' } + + 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 diff --git a/spec/controllers/activitypub/replies_controller_spec.rb b/spec/controllers/activitypub/replies_controller_spec.rb new file mode 100644 index 000000000..a5ed14180 --- /dev/null +++ b/spec/controllers/activitypub/replies_controller_spec.rb @@ -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 diff --git a/spec/controllers/statuses_controller_spec.rb b/spec/controllers/statuses_controller_spec.rb index 6905dae10..ba1f1370a 100644 --- a/spec/controllers/statuses_controller_spec.rb +++ b/spec/controllers/statuses_controller_spec.rb @@ -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 } + end - expect(response).to have_http_status(404) + it 'redirects to the original status' do + expect(response).to redirect_to(original_status.url) 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) + context 'when status is public' do + before do + get :show, params: { account_username: status.account.username, id: status.id, format: format } + end - get :show, params: { account_username: status.account.username, id: status.id } + context 'as HTML' do + let(:format) { 'html' } - expect(response).to redirect_to(original_status.url) + 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 + + 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 '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 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 @status' do - status = Fabricate(:status) - get :show, params: { account_username: status.account.username, id: status.id } - expect(assigns(:status)).to eq status + context 'as JSON' do + let(:format) { 'json' } + + it 'returns http not found' do + expect(response).to have_http_status(404) + 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 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 + + context 'when status is direct' do + let(:status) { Fabricate(:status, account: account, visibility: :direct) } - expect(assigns(:ancestors)).to eq [ancestor] + 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 + + context 'when signed-in' do + let(:user) { Fabricate(:user) } - expect(assigns(:descendant_threads)[0][:statuses].pluck(:id)).to eq [child.id, grandchild.id] + before do + sign_in(user) 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 '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 } + 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 - 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 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 - 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 'when status is private' do + let(:status) { Fabricate(:status, account: account, visibility: :private) } - get :show, params: { account_username: status.account.username, id: status.id } + 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 - expect(assigns(:descendant_threads)).to eq [] - expect(assigns(:max_descendant_thread_id)).to eq child.id + 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 - 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 status is direct' do + let(:status) { Fabricate(:status, account: account, visibility: :direct) } - get :show, params: { account_username: status.account.username, id: status.id } + 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' } - 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 + + 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 - it 'returns a success' do - status = Fabricate(:status) - get :show, params: { account_username: status.account.username, id: status.id } + 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 |