Conflicts: - `spec/controllers/api/v1/timelines/tag_controller_spec.rb`: Glitch-soc had a few extra lines in this file to account for a different default setting. This file got replaced by `spec/requests/api/v1/timelines/tag_spec.rb`, into which the glitch-soc additions were moved too. Additional changes: - `spec/requests/api/v1/statuses/sources_spec.rb`: Add glitch-soc-only attribute `content_type`.local
commit
b867d4581e
89 changed files with 1735 additions and 2166 deletions
@ -0,0 +1,38 @@ |
||||
.strike-card |
||||
- unless strike.none_action? |
||||
%p= t "user_mailer.warning.explanation.#{strike.action}", instance: Rails.configuration.x.local_domain |
||||
- if strike.text.present? |
||||
= linkify(strike.text) |
||||
- if strike.report && !strike.report.other? |
||||
%p |
||||
%strong= t('user_mailer.warning.reason') |
||||
= t("user_mailer.warning.categories.#{strike.report.category}") |
||||
- if strike.report.violation? && strike.report.rule_ids.present? |
||||
%ul.strike-card__rules |
||||
- strike.report.rules.each do |rule| |
||||
%li |
||||
%span.strike-card__rules__text= rule.text |
||||
- if strike.status_ids.present? && !strike.status_ids.empty? |
||||
%p |
||||
%strong= t('user_mailer.warning.statuses') |
||||
.strike-card__statuses-list |
||||
- status_map = strike.statuses.includes(:application, :media_attachments).index_by(&:id) |
||||
- strike.status_ids.each do |status_id| |
||||
.strike-card__statuses-list__item |
||||
- if (status = status_map[status_id.to_i]) |
||||
.one-liner |
||||
.emojify= one_line_preview(status) |
||||
- status.ordered_media_attachments.each do |media_attachment| |
||||
%abbr{ title: media_attachment.description } |
||||
= fa_icon 'link' |
||||
= media_attachment.file_file_name |
||||
.strike-card__statuses-list__item__meta |
||||
= link_to ActivityPub::TagManager.instance.url_for(status), target: '_blank', rel: 'noopener noreferrer' do |
||||
%time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at) |
||||
- unless status.application.nil? |
||||
· |
||||
= status.application.name |
||||
- else |
||||
.one-liner= t('disputes.strikes.status', id: status_id) |
||||
.strike-card__statuses-list__item__meta |
||||
= t('disputes.strikes.status_removed') |
@ -1,198 +0,0 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
RSpec.describe Api::V1::Admin::AccountsController do |
||||
render_views |
||||
|
||||
let(:role) { UserRole.find_by(name: 'Moderator') } |
||||
let(:user) { Fabricate(:user, role: role) } |
||||
let(:scopes) { 'admin:read admin:write' } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } |
||||
let(:account) { Fabricate(:account) } |
||||
|
||||
before do |
||||
allow(controller).to receive(:doorkeeper_token) { token } |
||||
end |
||||
|
||||
describe 'GET #index' do |
||||
let!(:remote_account) { Fabricate(:account, domain: 'example.org') } |
||||
let!(:other_remote_account) { Fabricate(:account, domain: 'foo.bar') } |
||||
let!(:suspended_account) { Fabricate(:account, suspended: true) } |
||||
let!(:suspended_remote) { Fabricate(:account, domain: 'foo.bar', suspended: true) } |
||||
let!(:disabled_account) { Fabricate(:user, disabled: true).account } |
||||
let!(:pending_account) { Fabricate(:user, approved: false).account } |
||||
let!(:admin_account) { user.account } |
||||
|
||||
let(:params) { {} } |
||||
|
||||
before do |
||||
pending_account.user.update(approved: false) |
||||
get :index, params: params |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
[ |
||||
[{ active: 'true', local: 'true', staff: 'true' }, [:admin_account]], |
||||
[{ by_domain: 'example.org', remote: 'true' }, [:remote_account]], |
||||
[{ suspended: 'true' }, [:suspended_account]], |
||||
[{ disabled: 'true' }, [:disabled_account]], |
||||
[{ pending: 'true' }, [:pending_account]], |
||||
].each do |params, expected_results| |
||||
context "when called with #{params.inspect}" do |
||||
let(:params) { params } |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it "returns the correct accounts (#{expected_results.inspect})" do |
||||
json = body_as_json |
||||
|
||||
expect(json.map { |a| a[:id].to_i }).to eq(expected_results.map { |symbol| send(symbol).id }) |
||||
end |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'GET #show' do |
||||
before do |
||||
get :show, params: { id: account.id } |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
end |
||||
|
||||
describe 'POST #approve' do |
||||
before do |
||||
account.user.update(approved: false) |
||||
post :approve, params: { id: account.id } |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'approves user' do |
||||
expect(account.reload.user_approved?).to be true |
||||
end |
||||
|
||||
it 'logs action' do |
||||
log_item = Admin::ActionLog.last |
||||
|
||||
expect(log_item).to_not be_nil |
||||
expect(log_item.action).to eq :approve |
||||
expect(log_item.account_id).to eq user.account_id |
||||
expect(log_item.target_id).to eq account.user.id |
||||
end |
||||
end |
||||
|
||||
describe 'POST #reject' do |
||||
before do |
||||
account.user.update(approved: false) |
||||
post :reject, params: { id: account.id } |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'removes user' do |
||||
expect(User.where(id: account.user.id).count).to eq 0 |
||||
end |
||||
|
||||
it 'logs action' do |
||||
log_item = Admin::ActionLog.last |
||||
|
||||
expect(log_item).to_not be_nil |
||||
expect(log_item.action).to eq :reject |
||||
expect(log_item.account_id).to eq user.account_id |
||||
expect(log_item.target_id).to eq account.user.id |
||||
end |
||||
end |
||||
|
||||
describe 'POST #enable' do |
||||
before do |
||||
account.user.update(disabled: true) |
||||
post :enable, params: { id: account.id } |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'enables user' do |
||||
expect(account.reload.user_disabled?).to be false |
||||
end |
||||
end |
||||
|
||||
describe 'POST #unsuspend' do |
||||
before do |
||||
account.suspend! |
||||
post :unsuspend, params: { id: account.id } |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'unsuspends account' do |
||||
expect(account.reload.suspended?).to be false |
||||
end |
||||
end |
||||
|
||||
describe 'POST #unsensitive' do |
||||
before do |
||||
account.touch(:sensitized_at) |
||||
post :unsensitive, params: { id: account.id } |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'unsensitizes account' do |
||||
expect(account.reload.sensitized?).to be false |
||||
end |
||||
end |
||||
|
||||
describe 'POST #unsilence' do |
||||
before do |
||||
account.touch(:silenced_at) |
||||
post :unsilence, params: { id: account.id } |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'unsilences account' do |
||||
expect(account.reload.silenced?).to be false |
||||
end |
||||
end |
||||
end |
@ -1,52 +0,0 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
describe Api::V1::Admin::Trends::LinksController do |
||||
render_views |
||||
|
||||
let(:role) { UserRole.find_by(name: 'Admin') } |
||||
let(:user) { Fabricate(:user, role: role) } |
||||
let(:scopes) { 'admin:read admin:write' } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } |
||||
let(:account) { Fabricate(:account) } |
||||
let(:preview_card) { Fabricate(:preview_card) } |
||||
|
||||
before do |
||||
allow(controller).to receive(:doorkeeper_token) { token } |
||||
end |
||||
|
||||
describe 'GET #index' do |
||||
it 'returns http success' do |
||||
get :index, params: { account_id: account.id, limit: 2 } |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
end |
||||
|
||||
describe 'POST #approve' do |
||||
before do |
||||
post :approve, params: { id: preview_card.id } |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
end |
||||
|
||||
describe 'POST #reject' do |
||||
before do |
||||
post :reject, params: { id: preview_card.id } |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
end |
||||
end |
@ -1,65 +0,0 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
RSpec.describe Api::V1::BlocksController do |
||||
render_views |
||||
|
||||
let(:user) { Fabricate(:user) } |
||||
let(:scopes) { 'read:blocks' } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } |
||||
|
||||
before { allow(controller).to receive(:doorkeeper_token) { token } } |
||||
|
||||
describe 'GET #index' do |
||||
it 'limits according to limit parameter' do |
||||
Array.new(2) { Fabricate(:block, account: user.account) } |
||||
get :index, params: { limit: 1 } |
||||
expect(body_as_json.size).to eq 1 |
||||
end |
||||
|
||||
it 'queries blocks in range according to max_id' do |
||||
blocks = Array.new(2) { Fabricate(:block, account: user.account) } |
||||
|
||||
get :index, params: { max_id: blocks[1] } |
||||
|
||||
expect(body_as_json.size).to eq 1 |
||||
expect(body_as_json[0][:id]).to eq blocks[0].target_account_id.to_s |
||||
end |
||||
|
||||
it 'queries blocks in range according to since_id' do |
||||
blocks = Array.new(2) { Fabricate(:block, account: user.account) } |
||||
|
||||
get :index, params: { since_id: blocks[0] } |
||||
|
||||
expect(body_as_json.size).to eq 1 |
||||
expect(body_as_json[0][:id]).to eq blocks[1].target_account_id.to_s |
||||
end |
||||
|
||||
it 'sets pagination header for next path' do |
||||
blocks = Array.new(2) { Fabricate(:block, account: user.account) } |
||||
get :index, params: { limit: 1, since_id: blocks[0] } |
||||
expect(response.headers['Link'].find_link(%w(rel next)).href).to eq api_v1_blocks_url(limit: 1, max_id: blocks[1]) |
||||
end |
||||
|
||||
it 'sets pagination header for previous path' do |
||||
block = Fabricate(:block, account: user.account) |
||||
get :index |
||||
expect(response.headers['Link'].find_link(%w(rel prev)).href).to eq api_v1_blocks_url(since_id: block) |
||||
end |
||||
|
||||
it 'returns http success' do |
||||
get :index |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
context 'with wrong scopes' do |
||||
let(:scopes) { 'write:blocks' } |
||||
|
||||
it 'returns http forbidden' do |
||||
get :index |
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
end |
||||
end |
@ -1,80 +0,0 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
RSpec.describe Api::V1::FavouritesController do |
||||
render_views |
||||
|
||||
let(:user) { Fabricate(:user) } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') } |
||||
|
||||
describe 'GET #index' do |
||||
context 'without token' do |
||||
it 'returns http unauthorized' do |
||||
get :index |
||||
expect(response).to have_http_status 401 |
||||
end |
||||
end |
||||
|
||||
context 'with token' do |
||||
context 'without read scope' do |
||||
before do |
||||
allow(controller).to receive(:doorkeeper_token) do |
||||
Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: '') |
||||
end |
||||
end |
||||
|
||||
it 'returns http forbidden' do |
||||
get :index |
||||
expect(response).to have_http_status 403 |
||||
end |
||||
end |
||||
|
||||
context 'without valid resource owner' do |
||||
before do |
||||
token = Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') |
||||
user.destroy! |
||||
|
||||
allow(controller).to receive(:doorkeeper_token) { token } |
||||
end |
||||
|
||||
it 'returns http unprocessable entity' do |
||||
get :index |
||||
expect(response).to have_http_status 422 |
||||
end |
||||
end |
||||
|
||||
context 'with read scope and valid resource owner' do |
||||
before do |
||||
allow(controller).to receive(:doorkeeper_token) do |
||||
Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:favourites') |
||||
end |
||||
end |
||||
|
||||
it 'shows favourites owned by the user' do |
||||
favourite_by_user = Fabricate(:favourite, account: user.account) |
||||
favourite_by_others = Fabricate(:favourite) |
||||
|
||||
get :index |
||||
|
||||
expect(assigns(:statuses)).to contain_exactly(favourite_by_user.status) |
||||
end |
||||
|
||||
it 'adds pagination headers if necessary' do |
||||
favourite = Fabricate(:favourite, account: user.account) |
||||
|
||||
get :index, params: { limit: 1 } |
||||
|
||||
expect(response.headers['Link'].find_link(%w(rel next)).href).to eq "http://test.host/api/v1/favourites?limit=1&max_id=#{favourite.id}" |
||||
expect(response.headers['Link'].find_link(%w(rel prev)).href).to eq "http://test.host/api/v1/favourites?limit=1&min_id=#{favourite.id}" |
||||
end |
||||
|
||||
it 'does not add pagination headers if not necessary' do |
||||
get :index |
||||
|
||||
expect(response.headers['Link']).to be_nil |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
@ -1,25 +0,0 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
RSpec.describe Api::V1::FollowedTagsController do |
||||
render_views |
||||
|
||||
let(:user) { Fabricate(:user) } |
||||
let(:scopes) { 'read:follows' } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } |
||||
|
||||
before { allow(controller).to receive(:doorkeeper_token) { token } } |
||||
|
||||
describe 'GET #index' do |
||||
let!(:tag_follows) { Fabricate.times(5, :tag_follow, account: user.account) } |
||||
|
||||
before do |
||||
get :index, params: { limit: 1 } |
||||
end |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(:success) |
||||
end |
||||
end |
||||
end |
@ -1,92 +0,0 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
describe Api::V1::Lists::AccountsController do |
||||
render_views |
||||
|
||||
let(:user) { Fabricate(:user) } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } |
||||
let(:list) { Fabricate(:list, account: user.account) } |
||||
|
||||
before do |
||||
follow = Fabricate(:follow, account: user.account) |
||||
list.accounts << follow.target_account |
||||
allow(controller).to receive(:doorkeeper_token) { token } |
||||
end |
||||
|
||||
describe 'GET #index' do |
||||
let(:scopes) { 'read:lists' } |
||||
|
||||
it 'returns http success' do |
||||
get :show, params: { list_id: list.id } |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
end |
||||
|
||||
describe 'POST #create' do |
||||
let(:scopes) { 'write:lists' } |
||||
let(:bob) { Fabricate(:account, username: 'bob') } |
||||
|
||||
context 'when the added account is followed' do |
||||
before do |
||||
user.account.follow!(bob) |
||||
post :create, params: { list_id: list.id, account_ids: [bob.id] } |
||||
end |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'adds account to the list' do |
||||
expect(list.accounts.include?(bob)).to be true |
||||
end |
||||
end |
||||
|
||||
context 'when the added account has been sent a follow request' do |
||||
before do |
||||
user.account.follow_requests.create!(target_account: bob) |
||||
post :create, params: { list_id: list.id, account_ids: [bob.id] } |
||||
end |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'adds account to the list' do |
||||
expect(list.accounts.include?(bob)).to be true |
||||
end |
||||
end |
||||
|
||||
context 'when the added account is not followed' do |
||||
before do |
||||
post :create, params: { list_id: list.id, account_ids: [bob.id] } |
||||
end |
||||
|
||||
it 'returns http not found' do |
||||
expect(response).to have_http_status(404) |
||||
end |
||||
|
||||
it 'does not add the account to the list' do |
||||
expect(list.accounts.include?(bob)).to be false |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'DELETE #destroy' do |
||||
let(:scopes) { 'write:lists' } |
||||
|
||||
before do |
||||
delete :destroy, params: { list_id: list.id, account_ids: [list.accounts.first.id] } |
||||
end |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'removes account from the list' do |
||||
expect(list.accounts.count).to eq 0 |
||||
end |
||||
end |
||||
end |
@ -1,75 +0,0 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
RSpec.describe Api::V1::ReportsController do |
||||
render_views |
||||
|
||||
let(:user) { Fabricate(:user) } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } |
||||
|
||||
before do |
||||
allow(controller).to receive(:doorkeeper_token) { token } |
||||
end |
||||
|
||||
describe 'POST #create' do |
||||
let!(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) } |
||||
|
||||
let(:scopes) { 'write:reports' } |
||||
let(:status) { Fabricate(:status) } |
||||
let(:target_account) { status.account } |
||||
let(:category) { nil } |
||||
let(:forward) { nil } |
||||
let(:rule_ids) { nil } |
||||
|
||||
before do |
||||
post :create, params: { status_ids: [status.id], account_id: target_account.id, comment: 'reasons', category: category, rule_ids: rule_ids, forward: forward } |
||||
end |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'creates a report' do |
||||
expect(target_account.targeted_reports).to_not be_empty |
||||
end |
||||
|
||||
it 'saves comment' do |
||||
expect(target_account.targeted_reports.first.comment).to eq 'reasons' |
||||
end |
||||
|
||||
it 'sends e-mails to admins' do |
||||
expect(ActionMailer::Base.deliveries.first.to).to eq([admin.email]) |
||||
end |
||||
|
||||
context 'when a status does not belong to the reported account' do |
||||
let(:target_account) { Fabricate(:account) } |
||||
|
||||
it 'returns http not found' do |
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
|
||||
context 'when a category is chosen' do |
||||
let(:category) { 'spam' } |
||||
|
||||
it 'saves category' do |
||||
expect(target_account.targeted_reports.first.spam?).to be true |
||||
end |
||||
end |
||||
|
||||
context 'when violated rules are chosen' do |
||||
let(:rule) { Fabricate(:rule) } |
||||
let(:category) { 'violation' } |
||||
let(:rule_ids) { [rule.id] } |
||||
|
||||
it 'saves category' do |
||||
expect(target_account.targeted_reports.first.violation?).to be true |
||||
end |
||||
|
||||
it 'saves rule_ids' do |
||||
expect(target_account.targeted_reports.first.rule_ids).to contain_exactly(rule.id) |
||||
end |
||||
end |
||||
end |
||||
end |
@ -1,29 +0,0 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
describe Api::V1::Statuses::SourcesController do |
||||
render_views |
||||
|
||||
let(:user) { Fabricate(:user) } |
||||
let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses', application: app) } |
||||
|
||||
context 'with an oauth token' do |
||||
before do |
||||
allow(controller).to receive(:doorkeeper_token) { token } |
||||
end |
||||
|
||||
describe 'GET #show' do |
||||
let(:status) { Fabricate(:status, account: user.account) } |
||||
|
||||
before do |
||||
get :show, params: { status_id: status.id } |
||||
end |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
end |
||||
end |
||||
end |
@ -1,75 +0,0 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
describe Api::V1::Timelines::TagController do |
||||
render_views |
||||
|
||||
let(:user) { Fabricate(:user) } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses') } |
||||
|
||||
before do |
||||
allow(controller).to receive(:doorkeeper_token) { token } |
||||
end |
||||
|
||||
describe 'GET #show' do |
||||
subject do |
||||
get :show, params: { id: 'test' } |
||||
end |
||||
|
||||
before do |
||||
PostStatusService.new.call(user.account, text: 'It is a #test') |
||||
end |
||||
|
||||
context 'when the instance allows public preview' do |
||||
before do |
||||
Setting.timeline_preview = true |
||||
end |
||||
|
||||
context 'when the user is not authenticated' do |
||||
let(:token) { nil } |
||||
|
||||
it 'returns http success', :aggregate_failures do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
expect(response.headers['Link'].links.size).to eq(2) |
||||
end |
||||
end |
||||
|
||||
context 'when the user is authenticated' do |
||||
it 'returns http success', :aggregate_failures do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
expect(response.headers['Link'].links.size).to eq(2) |
||||
end |
||||
end |
||||
end |
||||
|
||||
context 'when the instance does not allow public preview' do |
||||
before do |
||||
Form::AdminSettings.new(timeline_preview: false).save |
||||
end |
||||
|
||||
context 'when the user is not authenticated' do |
||||
let(:token) { nil } |
||||
|
||||
it 'returns http unauthorized' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(401) |
||||
end |
||||
end |
||||
|
||||
context 'when the user is authenticated' do |
||||
it 'returns http success', :aggregate_failures do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
expect(response.headers['Link'].links.size).to eq(2) |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
@ -1,391 +0,0 @@ |
||||
HTTP/1.1 200 OK |
||||
Date: Tue, 01 May 2018 23:25:57 GMT |
||||
Content-Location: activitystreams.jsonld |
||||
Vary: negotiate,accept |
||||
TCN: choice |
||||
Last-Modified: Mon, 16 Apr 2018 00:28:23 GMT |
||||
ETag: "1eb0-569ec4caa97c0;d3-540ee27e0eec0" |
||||
Accept-Ranges: bytes |
||||
Content-Length: 7856 |
||||
Cache-Control: max-age=21600 |
||||
Expires: Wed, 02 May 2018 05:25:57 GMT |
||||
P3P: policyref="http://www.w3.org/2014/08/p3p.xml" |
||||
Access-Control-Allow-Origin: * |
||||
Content-Type: application/ld+json |
||||
Strict-Transport-Security: max-age=15552000; includeSubdomains; preload |
||||
Content-Security-Policy: upgrade-insecure-requests |
||||
|
||||
{ |
||||
"@context": { |
||||
"@vocab": "_:", |
||||
"xsd": "http://www.w3.org/2001/XMLSchema#", |
||||
"as": "https://www.w3.org/ns/activitystreams#", |
||||
"ldp": "http://www.w3.org/ns/ldp#", |
||||
"id": "@id", |
||||
"type": "@type", |
||||
"Accept": "as:Accept", |
||||
"Activity": "as:Activity", |
||||
"IntransitiveActivity": "as:IntransitiveActivity", |
||||
"Add": "as:Add", |
||||
"Announce": "as:Announce", |
||||
"Application": "as:Application", |
||||
"Arrive": "as:Arrive", |
||||
"Article": "as:Article", |
||||
"Audio": "as:Audio", |
||||
"Block": "as:Block", |
||||
"Collection": "as:Collection", |
||||
"CollectionPage": "as:CollectionPage", |
||||
"Relationship": "as:Relationship", |
||||
"Create": "as:Create", |
||||
"Delete": "as:Delete", |
||||
"Dislike": "as:Dislike", |
||||
"Document": "as:Document", |
||||
"Event": "as:Event", |
||||
"Follow": "as:Follow", |
||||
"Flag": "as:Flag", |
||||
"Group": "as:Group", |
||||
"Ignore": "as:Ignore", |
||||
"Image": "as:Image", |
||||
"Invite": "as:Invite", |
||||
"Join": "as:Join", |
||||
"Leave": "as:Leave", |
||||
"Like": "as:Like", |
||||
"Link": "as:Link", |
||||
"Mention": "as:Mention", |
||||
"Note": "as:Note", |
||||
"Object": "as:Object", |
||||
"Offer": "as:Offer", |
||||
"OrderedCollection": "as:OrderedCollection", |
||||
"OrderedCollectionPage": "as:OrderedCollectionPage", |
||||
"Organization": "as:Organization", |
||||
"Page": "as:Page", |
||||
"Person": "as:Person", |
||||
"Place": "as:Place", |
||||
"Profile": "as:Profile", |
||||
"Question": "as:Question", |
||||
"Reject": "as:Reject", |
||||
"Remove": "as:Remove", |
||||
"Service": "as:Service", |
||||
"TentativeAccept": "as:TentativeAccept", |
||||
"TentativeReject": "as:TentativeReject", |
||||
"Tombstone": "as:Tombstone", |
||||
"Undo": "as:Undo", |
||||
"Update": "as:Update", |
||||
"Video": "as:Video", |
||||
"View": "as:View", |
||||
"Listen": "as:Listen", |
||||
"Read": "as:Read", |
||||
"Move": "as:Move", |
||||
"Travel": "as:Travel", |
||||
"IsFollowing": "as:IsFollowing", |
||||
"IsFollowedBy": "as:IsFollowedBy", |
||||
"IsContact": "as:IsContact", |
||||
"IsMember": "as:IsMember", |
||||
"subject": { |
||||
"@id": "as:subject", |
||||
"@type": "@id" |
||||
}, |
||||
"relationship": { |
||||
"@id": "as:relationship", |
||||
"@type": "@id" |
||||
}, |
||||
"actor": { |
||||
"@id": "as:actor", |
||||
"@type": "@id" |
||||
}, |
||||
"attributedTo": { |
||||
"@id": "as:attributedTo", |
||||
"@type": "@id" |
||||
}, |
||||
"attachment": { |
||||
"@id": "as:attachment", |
||||
"@type": "@id" |
||||
}, |
||||
"bcc": { |
||||
"@id": "as:bcc", |
||||
"@type": "@id" |
||||
}, |
||||
"bto": { |
||||
"@id": "as:bto", |
||||
"@type": "@id" |
||||
}, |
||||
"cc": { |
||||
"@id": "as:cc", |
||||
"@type": "@id" |
||||
}, |
||||
"context": { |
||||
"@id": "as:context", |
||||
"@type": "@id" |
||||
}, |
||||
"current": { |
||||
"@id": "as:current", |
||||
"@type": "@id" |
||||
}, |
||||
"first": { |
||||
"@id": "as:first", |
||||
"@type": "@id" |
||||
}, |
||||
"generator": { |
||||
"@id": "as:generator", |
||||
"@type": "@id" |
||||
}, |
||||
"icon": { |
||||
"@id": "as:icon", |
||||
"@type": "@id" |
||||
}, |
||||
"image": { |
||||
"@id": "as:image", |
||||
"@type": "@id" |
||||
}, |
||||
"inReplyTo": { |
||||
"@id": "as:inReplyTo", |
||||
"@type": "@id" |
||||
}, |
||||
"items": { |
||||
"@id": "as:items", |
||||
"@type": "@id" |
||||
}, |
||||
"instrument": { |
||||
"@id": "as:instrument", |
||||
"@type": "@id" |
||||
}, |
||||
"orderedItems": { |
||||
"@id": "as:items", |
||||
"@type": "@id", |
||||
"@container": "@list" |
||||
}, |
||||
"last": { |
||||
"@id": "as:last", |
||||
"@type": "@id" |
||||
}, |
||||
"location": { |
||||
"@id": "as:location", |
||||
"@type": "@id" |
||||
}, |
||||
"next": { |
||||
"@id": "as:next", |
||||
"@type": "@id" |
||||
}, |
||||
"object": { |
||||
"@id": "as:object", |
||||
"@type": "@id" |
||||
}, |
||||
"oneOf": { |
||||
"@id": "as:oneOf", |
||||
"@type": "@id" |
||||
}, |
||||
"anyOf": { |
||||
"@id": "as:anyOf", |
||||
"@type": "@id" |
||||
}, |
||||
"closed": { |
||||
"@id": "as:closed", |
||||
"@type": "xsd:dateTime" |
||||
}, |
||||
"origin": { |
||||
"@id": "as:origin", |
||||
"@type": "@id" |
||||
}, |
||||
"accuracy": { |
||||
"@id": "as:accuracy", |
||||
"@type": "xsd:float" |
||||
}, |
||||
"prev": { |
||||
"@id": "as:prev", |
||||
"@type": "@id" |
||||
}, |
||||
"preview": { |
||||
"@id": "as:preview", |
||||
"@type": "@id" |
||||
}, |
||||
"replies": { |
||||
"@id": "as:replies", |
||||
"@type": "@id" |
||||
}, |
||||
"result": { |
||||
"@id": "as:result", |
||||
"@type": "@id" |
||||
}, |
||||
"audience": { |
||||
"@id": "as:audience", |
||||
"@type": "@id" |
||||
}, |
||||
"partOf": { |
||||
"@id": "as:partOf", |
||||
"@type": "@id" |
||||
}, |
||||
"tag": { |
||||
"@id": "as:tag", |
||||
"@type": "@id" |
||||
}, |
||||
"target": { |
||||
"@id": "as:target", |
||||
"@type": "@id" |
||||
}, |
||||
"to": { |
||||
"@id": "as:to", |
||||
"@type": "@id" |
||||
}, |
||||
"url": { |
||||
"@id": "as:url", |
||||
"@type": "@id" |
||||
}, |
||||
"altitude": { |
||||
"@id": "as:altitude", |
||||
"@type": "xsd:float" |
||||
}, |
||||
"content": "as:content", |
||||
"contentMap": { |
||||
"@id": "as:content", |
||||
"@container": "@language" |
||||
}, |
||||
"name": "as:name", |
||||
"nameMap": { |
||||
"@id": "as:name", |
||||
"@container": "@language" |
||||
}, |
||||
"duration": { |
||||
"@id": "as:duration", |
||||
"@type": "xsd:duration" |
||||
}, |
||||
"endTime": { |
||||
"@id": "as:endTime", |
||||
"@type": "xsd:dateTime" |
||||
}, |
||||
"height": { |
||||
"@id": "as:height", |
||||
"@type": "xsd:nonNegativeInteger" |
||||
}, |
||||
"href": { |
||||
"@id": "as:href", |
||||
"@type": "@id" |
||||
}, |
||||
"hreflang": "as:hreflang", |
||||
"latitude": { |
||||
"@id": "as:latitude", |
||||
"@type": "xsd:float" |
||||
}, |
||||
"longitude": { |
||||
"@id": "as:longitude", |
||||
"@type": "xsd:float" |
||||
}, |
||||
"mediaType": "as:mediaType", |
||||
"published": { |
||||
"@id": "as:published", |
||||
"@type": "xsd:dateTime" |
||||
}, |
||||
"radius": { |
||||
"@id": "as:radius", |
||||
"@type": "xsd:float" |
||||
}, |
||||
"rel": "as:rel", |
||||
"startIndex": { |
||||
"@id": "as:startIndex", |
||||
"@type": "xsd:nonNegativeInteger" |
||||
}, |
||||
"startTime": { |
||||
"@id": "as:startTime", |
||||
"@type": "xsd:dateTime" |
||||
}, |
||||
"summary": "as:summary", |
||||
"summaryMap": { |
||||
"@id": "as:summary", |
||||
"@container": "@language" |
||||
}, |
||||
"totalItems": { |
||||
"@id": "as:totalItems", |
||||
"@type": "xsd:nonNegativeInteger" |
||||
}, |
||||
"units": "as:units", |
||||
"updated": { |
||||
"@id": "as:updated", |
||||
"@type": "xsd:dateTime" |
||||
}, |
||||
"width": { |
||||
"@id": "as:width", |
||||
"@type": "xsd:nonNegativeInteger" |
||||
}, |
||||
"describes": { |
||||
"@id": "as:describes", |
||||
"@type": "@id" |
||||
}, |
||||
"formerType": { |
||||
"@id": "as:formerType", |
||||
"@type": "@id" |
||||
}, |
||||
"deleted": { |
||||
"@id": "as:deleted", |
||||
"@type": "xsd:dateTime" |
||||
}, |
||||
"inbox": { |
||||
"@id": "ldp:inbox", |
||||
"@type": "@id" |
||||
}, |
||||
"outbox": { |
||||
"@id": "as:outbox", |
||||
"@type": "@id" |
||||
}, |
||||
"following": { |
||||
"@id": "as:following", |
||||
"@type": "@id" |
||||
}, |
||||
"followers": { |
||||
"@id": "as:followers", |
||||
"@type": "@id" |
||||
}, |
||||
"streams": { |
||||
"@id": "as:streams", |
||||
"@type": "@id" |
||||
}, |
||||
"preferredUsername": "as:preferredUsername", |
||||
"endpoints": { |
||||
"@id": "as:endpoints", |
||||
"@type": "@id" |
||||
}, |
||||
"uploadMedia": { |
||||
"@id": "as:uploadMedia", |
||||
"@type": "@id" |
||||
}, |
||||
"proxyUrl": { |
||||
"@id": "as:proxyUrl", |
||||
"@type": "@id" |
||||
}, |
||||
"liked": { |
||||
"@id": "as:liked", |
||||
"@type": "@id" |
||||
}, |
||||
"oauthAuthorizationEndpoint": { |
||||
"@id": "as:oauthAuthorizationEndpoint", |
||||
"@type": "@id" |
||||
}, |
||||
"oauthTokenEndpoint": { |
||||
"@id": "as:oauthTokenEndpoint", |
||||
"@type": "@id" |
||||
}, |
||||
"provideClientKey": { |
||||
"@id": "as:provideClientKey", |
||||
"@type": "@id" |
||||
}, |
||||
"signClientKey": { |
||||
"@id": "as:signClientKey", |
||||
"@type": "@id" |
||||
}, |
||||
"sharedInbox": { |
||||
"@id": "as:sharedInbox", |
||||
"@type": "@id" |
||||
}, |
||||
"Public": { |
||||
"@id": "as:Public", |
||||
"@type": "@id" |
||||
}, |
||||
"source": "as:source", |
||||
"likes": { |
||||
"@id": "as:likes", |
||||
"@type": "@id" |
||||
}, |
||||
"shares": { |
||||
"@id": "as:shares", |
||||
"@type": "@id" |
||||
} |
||||
} |
||||
} |
@ -1,100 +0,0 @@ |
||||
HTTP/1.1 200 OK |
||||
Accept-Ranges: bytes |
||||
Access-Control-Allow-Headers: DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Accept-Encoding |
||||
Access-Control-Allow-Origin: * |
||||
Content-Type: application/ld+json |
||||
Date: Tue, 01 May 2018 23:28:21 GMT |
||||
Etag: "e26-547a6fc75b04a-gzip" |
||||
Last-Modified: Fri, 03 Feb 2017 21:30:09 GMT |
||||
Server: Apache/2.4.7 (Ubuntu) |
||||
Vary: Accept-Encoding |
||||
Transfer-Encoding: chunked |
||||
|
||||
{ |
||||
"@context": { |
||||
"id": "@id", |
||||
"type": "@type", |
||||
|
||||
"cred": "https://w3id.org/credentials#", |
||||
"dc": "http://purl.org/dc/terms/", |
||||
"identity": "https://w3id.org/identity#", |
||||
"perm": "https://w3id.org/permissions#", |
||||
"ps": "https://w3id.org/payswarm#", |
||||
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", |
||||
"rdfs": "http://www.w3.org/2000/01/rdf-schema#", |
||||
"sec": "https://w3id.org/security#", |
||||
"schema": "http://schema.org/", |
||||
"xsd": "http://www.w3.org/2001/XMLSchema#", |
||||
|
||||
"Group": "https://www.w3.org/ns/activitystreams#Group", |
||||
|
||||
"claim": {"@id": "cred:claim", "@type": "@id"}, |
||||
"credential": {"@id": "cred:credential", "@type": "@id"}, |
||||
"issued": {"@id": "cred:issued", "@type": "xsd:dateTime"}, |
||||
"issuer": {"@id": "cred:issuer", "@type": "@id"}, |
||||
"recipient": {"@id": "cred:recipient", "@type": "@id"}, |
||||
"Credential": "cred:Credential", |
||||
"CryptographicKeyCredential": "cred:CryptographicKeyCredential", |
||||
|
||||
"about": {"@id": "schema:about", "@type": "@id"}, |
||||
"address": {"@id": "schema:address", "@type": "@id"}, |
||||
"addressCountry": "schema:addressCountry", |
||||
"addressLocality": "schema:addressLocality", |
||||
"addressRegion": "schema:addressRegion", |
||||
"comment": "rdfs:comment", |
||||
"created": {"@id": "dc:created", "@type": "xsd:dateTime"}, |
||||
"creator": {"@id": "dc:creator", "@type": "@id"}, |
||||
"description": "schema:description", |
||||
"email": "schema:email", |
||||
"familyName": "schema:familyName", |
||||
"givenName": "schema:givenName", |
||||
"image": {"@id": "schema:image", "@type": "@id"}, |
||||
"label": "rdfs:label", |
||||
"name": "schema:name", |
||||
"postalCode": "schema:postalCode", |
||||
"streetAddress": "schema:streetAddress", |
||||
"title": "dc:title", |
||||
"url": {"@id": "schema:url", "@type": "@id"}, |
||||
"Person": "schema:Person", |
||||
"PostalAddress": "schema:PostalAddress", |
||||
"Organization": "schema:Organization", |
||||
|
||||
"identityService": {"@id": "identity:identityService", "@type": "@id"}, |
||||
"idp": {"@id": "identity:idp", "@type": "@id"}, |
||||
"Identity": "identity:Identity", |
||||
|
||||
"paymentProcessor": "ps:processor", |
||||
"preferences": {"@id": "ps:preferences", "@type": "@vocab"}, |
||||
|
||||
"cipherAlgorithm": "sec:cipherAlgorithm", |
||||
"cipherData": "sec:cipherData", |
||||
"cipherKey": "sec:cipherKey", |
||||
"digestAlgorithm": "sec:digestAlgorithm", |
||||
"digestValue": "sec:digestValue", |
||||
"domain": "sec:domain", |
||||
"expires": {"@id": "sec:expiration", "@type": "xsd:dateTime"}, |
||||
"initializationVector": "sec:initializationVector", |
||||
"member": {"@id": "schema:member", "@type": "@id"}, |
||||
"memberOf": {"@id": "schema:memberOf", "@type": "@id"}, |
||||
"nonce": "sec:nonce", |
||||
"normalizationAlgorithm": "sec:normalizationAlgorithm", |
||||
"owner": {"@id": "sec:owner", "@type": "@id"}, |
||||
"password": "sec:password", |
||||
"privateKey": {"@id": "sec:privateKey", "@type": "@id"}, |
||||
"privateKeyPem": "sec:privateKeyPem", |
||||
"publicKey": {"@id": "sec:publicKey", "@type": "@id"}, |
||||
"publicKeyPem": "sec:publicKeyPem", |
||||
"publicKeyService": {"@id": "sec:publicKeyService", "@type": "@id"}, |
||||
"revoked": {"@id": "sec:revoked", "@type": "xsd:dateTime"}, |
||||
"signature": "sec:signature", |
||||
"signatureAlgorithm": "sec:signatureAlgorithm", |
||||
"signatureValue": "sec:signatureValue", |
||||
"CryptographicKey": "sec:Key", |
||||
"EncryptedMessage": "sec:EncryptedMessage", |
||||
"GraphSignature2012": "sec:GraphSignature2012", |
||||
"LinkedDataSignature2015": "sec:LinkedDataSignature2015", |
||||
|
||||
"accessControl": {"@id": "perm:accessControl", "@type": "@id"}, |
||||
"writePermission": {"@id": "perm:writePermission", "@type": "@id"} |
||||
} |
||||
} |
@ -1,61 +0,0 @@ |
||||
HTTP/1.1 200 OK |
||||
Accept-Ranges: bytes |
||||
Access-Control-Allow-Headers: DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Accept-Encoding |
||||
Access-Control-Allow-Origin: * |
||||
Content-Type: application/ld+json |
||||
Date: Wed, 02 May 2018 16:25:32 GMT |
||||
Etag: "7e3-5651ec0f7c5ed-gzip" |
||||
Last-Modified: Tue, 13 Feb 2018 21:34:04 GMT |
||||
Server: Apache/2.4.7 (Ubuntu) |
||||
Vary: Accept-Encoding |
||||
Content-Length: 2019 |
||||
|
||||
{ |
||||
"@context": { |
||||
"id": "@id", |
||||
"type": "@type", |
||||
|
||||
"dc": "http://purl.org/dc/terms/", |
||||
"sec": "https://w3id.org/security#", |
||||
"xsd": "http://www.w3.org/2001/XMLSchema#", |
||||
|
||||
"EcdsaKoblitzSignature2016": "sec:EcdsaKoblitzSignature2016", |
||||
"Ed25519Signature2018": "sec:Ed25519Signature2018", |
||||
"EncryptedMessage": "sec:EncryptedMessage", |
||||
"GraphSignature2012": "sec:GraphSignature2012", |
||||
"LinkedDataSignature2015": "sec:LinkedDataSignature2015", |
||||
"LinkedDataSignature2016": "sec:LinkedDataSignature2016", |
||||
"CryptographicKey": "sec:Key", |
||||
|
||||
"authenticationTag": "sec:authenticationTag", |
||||
"canonicalizationAlgorithm": "sec:canonicalizationAlgorithm", |
||||
"cipherAlgorithm": "sec:cipherAlgorithm", |
||||
"cipherData": "sec:cipherData", |
||||
"cipherKey": "sec:cipherKey", |
||||
"created": {"@id": "dc:created", "@type": "xsd:dateTime"}, |
||||
"creator": {"@id": "dc:creator", "@type": "@id"}, |
||||
"digestAlgorithm": "sec:digestAlgorithm", |
||||
"digestValue": "sec:digestValue", |
||||
"domain": "sec:domain", |
||||
"encryptionKey": "sec:encryptionKey", |
||||
"expiration": {"@id": "sec:expiration", "@type": "xsd:dateTime"}, |
||||
"expires": {"@id": "sec:expiration", "@type": "xsd:dateTime"}, |
||||
"initializationVector": "sec:initializationVector", |
||||
"iterationCount": "sec:iterationCount", |
||||
"nonce": "sec:nonce", |
||||
"normalizationAlgorithm": "sec:normalizationAlgorithm", |
||||
"owner": {"@id": "sec:owner", "@type": "@id"}, |
||||
"password": "sec:password", |
||||
"privateKey": {"@id": "sec:privateKey", "@type": "@id"}, |
||||
"privateKeyPem": "sec:privateKeyPem", |
||||
"publicKey": {"@id": "sec:publicKey", "@type": "@id"}, |
||||
"publicKeyBase58": "sec:publicKeyBase58", |
||||
"publicKeyPem": "sec:publicKeyPem", |
||||
"publicKeyService": {"@id": "sec:publicKeyService", "@type": "@id"}, |
||||
"revoked": {"@id": "sec:revoked", "@type": "xsd:dateTime"}, |
||||
"salt": "sec:salt", |
||||
"signature": "sec:signature", |
||||
"signatureAlgorithm": "sec:signingAlgorithm", |
||||
"signatureValue": "sec:signatureValue" |
||||
} |
||||
} |
@ -0,0 +1,401 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
RSpec.describe 'Accounts' do |
||||
let(:role) { UserRole.find_by(name: 'Admin') } |
||||
let(:user) { Fabricate(:user, role: role) } |
||||
let(:scopes) { 'admin:read:accounts admin:write:accounts' } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } |
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } |
||||
|
||||
describe 'GET /api/v1/admin/accounts' do |
||||
subject do |
||||
get '/api/v1/admin/accounts', headers: headers, params: params |
||||
end |
||||
|
||||
shared_examples 'a successful request' do |
||||
it 'returns the correct accounts', :aggregate_failures do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
expect(body_as_json.pluck(:id)).to match_array(expected_results.map { |a| a.id.to_s }) |
||||
end |
||||
end |
||||
|
||||
let!(:remote_account) { Fabricate(:account, domain: 'example.org') } |
||||
let!(:suspended_account) { Fabricate(:account, suspended: true) } |
||||
let!(:disabled_account) { Fabricate(:user, disabled: true).account } |
||||
let!(:pending_account) { Fabricate(:user, approved: false).account } |
||||
let!(:admin_account) { user.account } |
||||
let(:params) { {} } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:accounts admin:write admin:write:accounts' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
context 'when requesting active local staff accounts' do |
||||
let(:expected_results) { [admin_account] } |
||||
let(:params) { { active: 'true', local: 'true', staff: 'true' } } |
||||
|
||||
it_behaves_like 'a successful request' |
||||
end |
||||
|
||||
context 'when requesting remote accounts from a specified domain' do |
||||
let(:expected_results) { [remote_account] } |
||||
let(:params) { { by_domain: 'example.org', remote: 'true' } } |
||||
|
||||
before do |
||||
Fabricate(:account, domain: 'foo.bar') |
||||
end |
||||
|
||||
it_behaves_like 'a successful request' |
||||
end |
||||
|
||||
context 'when requesting suspended accounts' do |
||||
let(:expected_results) { [suspended_account] } |
||||
let(:params) { { suspended: 'true' } } |
||||
|
||||
before do |
||||
Fabricate(:account, domain: 'foo.bar', suspended: true) |
||||
end |
||||
|
||||
it_behaves_like 'a successful request' |
||||
end |
||||
|
||||
context 'when requesting disabled accounts' do |
||||
let(:expected_results) { [disabled_account] } |
||||
let(:params) { { disabled: 'true' } } |
||||
|
||||
it_behaves_like 'a successful request' |
||||
end |
||||
|
||||
context 'when requesting pending accounts' do |
||||
let(:expected_results) { [pending_account] } |
||||
let(:params) { { pending: 'true' } } |
||||
|
||||
before do |
||||
pending_account.user.update(approved: false) |
||||
end |
||||
|
||||
it_behaves_like 'a successful request' |
||||
end |
||||
|
||||
context 'when no parameter is given' do |
||||
let(:expected_results) { [disabled_account, pending_account, admin_account] } |
||||
|
||||
it_behaves_like 'a successful request' |
||||
end |
||||
|
||||
context 'with limit param' do |
||||
let(:params) { { limit: 2 } } |
||||
|
||||
it 'returns only the requested number of accounts', :aggregate_failures do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
expect(body_as_json.size).to eq(params[:limit]) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'GET /api/v1/admin/accounts/:id' do |
||||
subject do |
||||
get "/api/v1/admin/accounts/#{account.id}", headers: headers |
||||
end |
||||
|
||||
let(:account) { Fabricate(:account) } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:accounts admin:write admin:write:accounts' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'returns the requested account successfully', :aggregate_failures do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
expect(body_as_json).to match( |
||||
a_hash_including(id: account.id.to_s, username: account.username, email: account.user.email) |
||||
) |
||||
end |
||||
|
||||
context 'when the account is not found' do |
||||
it 'returns http not found' do |
||||
get '/api/v1/admin/accounts/-1', headers: headers |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'POST /api/v1/admin/accounts/:id/approve' do |
||||
subject do |
||||
post "/api/v1/admin/accounts/#{account.id}/approve", headers: headers |
||||
end |
||||
|
||||
let(:account) { Fabricate(:account) } |
||||
|
||||
context 'when the account is pending' do |
||||
before do |
||||
account.user.update(approved: false) |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'approves the user successfully', :aggregate_failures do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
expect(account.reload.user_approved?).to be(true) |
||||
end |
||||
|
||||
it 'logs action', :aggregate_failures do |
||||
subject |
||||
|
||||
log_item = Admin::ActionLog.last |
||||
|
||||
expect(log_item).to be_present |
||||
expect(log_item.action).to eq :approve |
||||
expect(log_item.account_id).to eq user.account_id |
||||
expect(log_item.target_id).to eq account.user.id |
||||
end |
||||
end |
||||
|
||||
context 'when the account is already approved' do |
||||
it 'returns http forbidden' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
|
||||
context 'when the account is not found' do |
||||
it 'returns http not found' do |
||||
post '/api/v1/admin/accounts/-1/approve', headers: headers |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'POST /api/v1/admin/accounts/:id/reject' do |
||||
subject do |
||||
post "/api/v1/admin/accounts/#{account.id}/reject", headers: headers |
||||
end |
||||
|
||||
let(:account) { Fabricate(:account) } |
||||
|
||||
context 'when the account is pending' do |
||||
before do |
||||
account.user.update(approved: false) |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'removes the user successfully', :aggregate_failures do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
expect(User.where(id: account.user.id)).to_not exist |
||||
end |
||||
|
||||
it 'logs action', :aggregate_failures do |
||||
subject |
||||
|
||||
log_item = Admin::ActionLog.last |
||||
|
||||
expect(log_item).to be_present |
||||
expect(log_item.action).to eq :reject |
||||
expect(log_item.account_id).to eq user.account_id |
||||
expect(log_item.target_id).to eq account.user.id |
||||
end |
||||
end |
||||
|
||||
context 'when account is already approved' do |
||||
it 'returns http forbidden' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
|
||||
context 'when the account is not found' do |
||||
it 'returns http not found' do |
||||
post '/api/v1/admin/accounts/-1/reject', headers: headers |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'POST /api/v1/admin/accounts/:id/enable' do |
||||
subject do |
||||
post "/api/v1/admin/accounts/#{account.id}/enable", headers: headers |
||||
end |
||||
|
||||
let(:account) { Fabricate(:account) } |
||||
|
||||
before do |
||||
account.user.update(disabled: true) |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'enables the user successfully', :aggregate_failures do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
expect(account.reload.user_disabled?).to be false |
||||
end |
||||
|
||||
context 'when the account is not found' do |
||||
it 'returns http not found' do |
||||
post '/api/v1/admin/accounts/-1/enable', headers: headers |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'POST /api/v1/admin/accounts/:id/unsuspend' do |
||||
subject do |
||||
post "/api/v1/admin/accounts/#{account.id}/unsuspend", headers: headers |
||||
end |
||||
|
||||
let(:account) { Fabricate(:account) } |
||||
|
||||
context 'when the account is suspended' do |
||||
before do |
||||
account.suspend! |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'unsuspends the account successfully', :aggregate_failures do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
expect(account.reload.suspended?).to be false |
||||
end |
||||
end |
||||
|
||||
context 'when the account is not suspended' do |
||||
it 'returns http forbidden' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
|
||||
context 'when the account is not found' do |
||||
it 'returns http not found' do |
||||
post '/api/v1/admin/accounts/-1/unsuspend', headers: headers |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'POST /api/v1/admin/accounts/:id/unsensitive' do |
||||
subject do |
||||
post "/api/v1/admin/accounts/#{account.id}/unsensitive", headers: headers |
||||
end |
||||
|
||||
let(:account) { Fabricate(:account) } |
||||
|
||||
before do |
||||
account.update(sensitized_at: 10.days.ago) |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'unsensitizes the account successfully', :aggregate_failures do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
expect(account.reload.sensitized?).to be false |
||||
end |
||||
|
||||
context 'when the account is not found' do |
||||
it 'returns http not found' do |
||||
post '/api/v1/admin/accounts/-1/unsensitive', headers: headers |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'POST /api/v1/admin/accounts/:id/unsilence' do |
||||
subject do |
||||
post "/api/v1/admin/accounts/#{account.id}/unsilence", headers: headers |
||||
end |
||||
|
||||
let(:account) { Fabricate(:account) } |
||||
|
||||
before do |
||||
account.update(silenced_at: 3.days.ago) |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'unsilences the account successfully', :aggregate_failures do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
expect(account.reload.silenced?).to be false |
||||
end |
||||
|
||||
context 'when the account is not found' do |
||||
it 'returns http not found' do |
||||
post '/api/v1/admin/accounts/-1/unsilence', headers: headers |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'DELETE /api/v1/admin/accounts/:id' do |
||||
subject do |
||||
delete "/api/v1/admin/accounts/#{account.id}", headers: headers |
||||
end |
||||
|
||||
let(:account) { Fabricate(:account) } |
||||
|
||||
context 'when account is suspended' do |
||||
before do |
||||
account.suspend! |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'deletes the account successfully', :aggregate_failures do |
||||
allow(Admin::AccountDeletionWorker).to receive(:perform_async) |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
expect(Admin::AccountDeletionWorker).to have_received(:perform_async).with(account.id).once |
||||
end |
||||
end |
||||
|
||||
context 'when account is not suspended' do |
||||
it 'returns http forbidden' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
|
||||
context 'when the account is not found' do |
||||
it 'returns http not found' do |
||||
delete '/api/v1/admin/accounts/-1', headers: headers |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,129 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
describe 'Links' do |
||||
let(:role) { UserRole.find_by(name: 'Admin') } |
||||
let(:user) { Fabricate(:user, role: role) } |
||||
let(:scopes) { 'admin:read admin:write' } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } |
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } |
||||
|
||||
describe 'GET /api/v1/admin/trends/links' do |
||||
subject do |
||||
get '/api/v1/admin/trends/links', headers: headers |
||||
end |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
end |
||||
|
||||
describe 'POST /api/v1/admin/trends/links/:id/approve' do |
||||
subject do |
||||
post "/api/v1/admin/trends/links/#{preview_card.id}/approve", headers: headers |
||||
end |
||||
|
||||
let(:preview_card) { Fabricate(:preview_card, trendable: false) } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read write' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'sets the link as trendable' do |
||||
expect { subject }.to change { preview_card.reload.trendable }.from(false).to(true) |
||||
end |
||||
|
||||
it 'returns the link data' do |
||||
subject |
||||
|
||||
expect(body_as_json).to match( |
||||
a_hash_including( |
||||
url: preview_card.url, |
||||
title: preview_card.title, |
||||
description: preview_card.description, |
||||
type: 'link', |
||||
requires_review: false |
||||
) |
||||
) |
||||
end |
||||
|
||||
context 'when the link does not exist' do |
||||
it 'returns http not found' do |
||||
post '/api/v1/admin/trends/links/-1/approve', headers: headers |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
|
||||
context 'without an authorization header' do |
||||
let(:headers) { {} } |
||||
|
||||
it 'returns http forbidden' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'POST /api/v1/admin/trends/links/:id/reject' do |
||||
subject do |
||||
post "/api/v1/admin/trends/links/#{preview_card.id}/reject", headers: headers |
||||
end |
||||
|
||||
let(:preview_card) { Fabricate(:preview_card, trendable: false) } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read write' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'does not set the link as trendable' do |
||||
expect { subject }.to_not(change { preview_card.reload.trendable }) |
||||
end |
||||
|
||||
it 'returns the link data' do |
||||
subject |
||||
|
||||
expect(body_as_json).to match( |
||||
a_hash_including( |
||||
url: preview_card.url, |
||||
title: preview_card.title, |
||||
description: preview_card.description, |
||||
type: 'link', |
||||
requires_review: false |
||||
) |
||||
) |
||||
end |
||||
|
||||
context 'when the link does not exist' do |
||||
it 'returns http not found' do |
||||
post '/api/v1/admin/trends/links/-1/reject', headers: headers |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
|
||||
context 'without an authorization header' do |
||||
let(:headers) { {} } |
||||
|
||||
it 'returns http forbidden' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,80 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
RSpec.describe 'Blocks' do |
||||
let(:user) { Fabricate(:user) } |
||||
let(:scopes) { 'read:blocks' } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } |
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } |
||||
|
||||
describe 'GET /api/v1/blocks' do |
||||
subject do |
||||
get '/api/v1/blocks', headers: headers, params: params |
||||
end |
||||
|
||||
let!(:blocks) { Fabricate.times(3, :block, account: user.account) } |
||||
let(:params) { {} } |
||||
|
||||
let(:expected_response) do |
||||
blocks.map { |block| a_hash_including(id: block.target_account.id.to_s, username: block.target_account.username) } |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:blocks' |
||||
|
||||
it 'returns the blocked accounts', :aggregate_failures do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
expect(body_as_json).to match_array(expected_response) |
||||
end |
||||
|
||||
context 'with limit param' do |
||||
let(:params) { { limit: 2 } } |
||||
|
||||
it 'returns only the requested number of blocked accounts' do |
||||
subject |
||||
|
||||
expect(body_as_json.size).to eq(params[:limit]) |
||||
end |
||||
|
||||
it 'sets the correct pagination header for the prev path' do |
||||
subject |
||||
|
||||
expect(response.headers['Link'].find_link(%w(rel prev)).href).to eq(api_v1_blocks_url(limit: params[:limit], since_id: blocks.last.id)) |
||||
end |
||||
|
||||
it 'sets the correct pagination header for the next path' do |
||||
subject |
||||
|
||||
expect(response.headers['Link'].find_link(%w(rel next)).href).to eq(api_v1_blocks_url(limit: params[:limit], max_id: blocks[1].id)) |
||||
end |
||||
end |
||||
|
||||
context 'with max_id param' do |
||||
let(:params) { { max_id: blocks[1].id } } |
||||
|
||||
it 'queries the blocks in range according to max_id', :aggregate_failures do |
||||
subject |
||||
|
||||
response_body = body_as_json |
||||
|
||||
expect(response_body.size).to be 1 |
||||
expect(response_body[0][:id]).to eq(blocks[0].target_account.id.to_s) |
||||
end |
||||
end |
||||
|
||||
context 'with since_id param' do |
||||
let(:params) { { since_id: blocks[1].id } } |
||||
|
||||
it 'queries the blocks in range according to since_id', :aggregate_failures do |
||||
subject |
||||
|
||||
response_body = body_as_json |
||||
|
||||
expect(response_body.size).to be 1 |
||||
expect(response_body[0][:id]).to eq(blocks[2].target_account.id.to_s) |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,71 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
RSpec.describe 'Favourites' do |
||||
let(:user) { Fabricate(:user) } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } |
||||
let(:scopes) { 'read:favourites' } |
||||
let(:headers) { { Authorization: "Bearer #{token.token}" } } |
||||
|
||||
describe 'GET /api/v1/favourites' do |
||||
subject do |
||||
get '/api/v1/favourites', headers: headers, params: params |
||||
end |
||||
|
||||
let(:params) { {} } |
||||
let!(:favourites) { Fabricate.times(3, :favourite, account: user.account) } |
||||
|
||||
let(:expected_response) do |
||||
favourites.map do |favourite| |
||||
a_hash_including(id: favourite.status.id.to_s, account: a_hash_including(id: favourite.status.account.id.to_s)) |
||||
end |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write' |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns the favourites' do |
||||
subject |
||||
|
||||
expect(body_as_json).to match_array(expected_response) |
||||
end |
||||
|
||||
context 'with limit param' do |
||||
let(:params) { { limit: 2 } } |
||||
|
||||
it 'returns only the requested number of favourites' do |
||||
subject |
||||
|
||||
expect(body_as_json.size).to eq(params[:limit]) |
||||
end |
||||
|
||||
it 'sets the correct pagination header for the prev path' do |
||||
subject |
||||
|
||||
expect(response.headers['Link'].find_link(%w(rel prev)).href).to eq(api_v1_favourites_url(limit: params[:limit], min_id: favourites.last.id)) |
||||
end |
||||
|
||||
it 'sets the correct pagination header for the next path' do |
||||
subject |
||||
|
||||
expect(response.headers['Link'].find_link(%w(rel next)).href).to eq(api_v1_favourites_url(limit: params[:limit], max_id: favourites[1].id)) |
||||
end |
||||
end |
||||
|
||||
context 'without an authorization header' do |
||||
let(:headers) { {} } |
||||
|
||||
it 'returns http unauthorized' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(401) |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,65 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
RSpec.describe 'Followed tags' do |
||||
let(:user) { Fabricate(:user) } |
||||
let(:scopes) { 'read:follows' } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } |
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } |
||||
|
||||
describe 'GET /api/v1/followed_tags' do |
||||
subject do |
||||
get '/api/v1/followed_tags', headers: headers, params: params |
||||
end |
||||
|
||||
let!(:tag_follows) { Fabricate.times(5, :tag_follow, account: user.account) } |
||||
let(:params) { {} } |
||||
|
||||
let(:expected_response) do |
||||
tag_follows.map do |tag_follow| |
||||
a_hash_including(name: tag_follow.tag.name, following: true) |
||||
end |
||||
end |
||||
|
||||
before do |
||||
Fabricate(:tag_follow) |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:follows' |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(:success) |
||||
end |
||||
|
||||
it 'returns the followed tags correctly' do |
||||
subject |
||||
|
||||
expect(body_as_json).to match_array(expected_response) |
||||
end |
||||
|
||||
context 'with limit param' do |
||||
let(:params) { { limit: 3 } } |
||||
|
||||
it 'returns only the requested number of follow tags' do |
||||
subject |
||||
|
||||
expect(body_as_json.size).to eq(params[:limit]) |
||||
end |
||||
|
||||
it 'sets the correct pagination header for the prev path' do |
||||
subject |
||||
|
||||
expect(response.headers['Link'].find_link(%w(rel prev)).href).to eq(api_v1_followed_tags_url(limit: params[:limit], since_id: tag_follows.last.id)) |
||||
end |
||||
|
||||
it 'sets the correct pagination header for the next path' do |
||||
subject |
||||
|
||||
expect(response.headers['Link'].find_link(%w(rel next)).href).to eq(api_v1_followed_tags_url(limit: params[:limit], max_id: tag_follows[2].id)) |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,178 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
RSpec.describe 'Accounts' do |
||||
let(:user) { Fabricate(:user) } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } |
||||
let(:scopes) { 'read:lists write:lists' } |
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } |
||||
|
||||
describe 'GET /api/v1/lists/:id/accounts' do |
||||
subject do |
||||
get "/api/v1/lists/#{list.id}/accounts", headers: headers, params: params |
||||
end |
||||
|
||||
let(:params) { { limit: 0 } } |
||||
let(:list) { Fabricate(:list, account: user.account) } |
||||
let(:accounts) { Fabricate.times(3, :account) } |
||||
|
||||
let(:expected_response) do |
||||
accounts.map do |account| |
||||
a_hash_including(id: account.id.to_s, username: account.username, acct: account.acct) |
||||
end |
||||
end |
||||
|
||||
before do |
||||
accounts.each { |account| user.account.follow!(account) } |
||||
list.accounts << accounts |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:lists' |
||||
|
||||
it 'returns the accounts in the requested list', :aggregate_failures do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
expect(body_as_json).to match_array(expected_response) |
||||
end |
||||
|
||||
context 'with limit param' do |
||||
let(:params) { { limit: 1 } } |
||||
|
||||
it 'returns only the requested number of accounts' do |
||||
subject |
||||
|
||||
expect(body_as_json.size).to eq(params[:limit]) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'POST /api/v1/lists/:id/accounts' do |
||||
subject do |
||||
post "/api/v1/lists/#{list.id}/accounts", headers: headers, params: params |
||||
end |
||||
|
||||
let(:list) { Fabricate(:list, account: user.account) } |
||||
let(:bob) { Fabricate(:account, username: 'bob') } |
||||
let(:params) { { account_ids: [bob.id] } } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:lists' |
||||
|
||||
context 'when the added account is followed' do |
||||
before do |
||||
user.account.follow!(bob) |
||||
end |
||||
|
||||
it 'adds account to the list', :aggregate_failures do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
expect(list.accounts).to include(bob) |
||||
end |
||||
end |
||||
|
||||
context 'when the added account has been sent a follow request' do |
||||
before do |
||||
user.account.follow_requests.create!(target_account: bob) |
||||
end |
||||
|
||||
it 'adds account to the list', :aggregate_failures do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
expect(list.accounts).to include(bob) |
||||
end |
||||
end |
||||
|
||||
context 'when the added account is not followed' do |
||||
it 'does not add the account to the list', :aggregate_failures do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(404) |
||||
expect(list.accounts).to_not include(bob) |
||||
end |
||||
end |
||||
|
||||
context 'when the list is not owned by the requesting user' do |
||||
let(:list) { Fabricate(:list) } |
||||
|
||||
before do |
||||
user.account.follow!(bob) |
||||
end |
||||
|
||||
it 'returns http not found' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
|
||||
context 'when account is already in the list' do |
||||
before do |
||||
user.account.follow!(bob) |
||||
list.accounts << bob |
||||
end |
||||
|
||||
it 'returns http unprocessable entity' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(422) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'DELETE /api/v1/lists/:id/accounts' do |
||||
subject do |
||||
delete "/api/v1/lists/#{list.id}/accounts", headers: headers, params: params |
||||
end |
||||
|
||||
context 'when the list is owned by the requesting user' do |
||||
let(:list) { Fabricate(:list, account: user.account) } |
||||
let(:bob) { Fabricate(:account, username: 'bob') } |
||||
let(:peter) { Fabricate(:account, username: 'peter') } |
||||
let(:params) { { account_ids: [bob.id] } } |
||||
|
||||
before do |
||||
user.account.follow!(bob) |
||||
user.account.follow!(peter) |
||||
list.accounts << [bob, peter] |
||||
end |
||||
|
||||
it 'removes the specified account from the list', :aggregate_failures do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
expect(list.accounts).to_not include(bob) |
||||
end |
||||
|
||||
it 'does not remove any other account from the list' do |
||||
subject |
||||
|
||||
expect(list.accounts).to include(peter) |
||||
end |
||||
|
||||
context 'when the specified account is not in the list' do |
||||
let(:params) { { account_ids: [0] } } |
||||
|
||||
it 'does not remove any account from the list', :aggregate_failures do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
expect(list.accounts).to contain_exactly(bob, peter) |
||||
end |
||||
end |
||||
end |
||||
|
||||
context 'when the list is not owned by the requesting user' do |
||||
let(:list) { Fabricate(:list) } |
||||
let(:params) { {} } |
||||
|
||||
it 'returns http not found' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,89 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
RSpec.describe 'Reports' do |
||||
let(:user) { Fabricate(:user) } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } |
||||
let(:scopes) { 'write:reports' } |
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } |
||||
|
||||
describe 'POST /api/v1/reports' do |
||||
subject do |
||||
post '/api/v1/reports', headers: headers, params: params |
||||
end |
||||
|
||||
let!(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) } |
||||
let(:status) { Fabricate(:status) } |
||||
let(:target_account) { status.account } |
||||
let(:category) { 'other' } |
||||
let(:forward) { nil } |
||||
let(:rule_ids) { nil } |
||||
|
||||
let(:params) do |
||||
{ |
||||
status_ids: [status.id], |
||||
account_id: target_account.id, |
||||
comment: 'reasons', |
||||
category: category, |
||||
rule_ids: rule_ids, |
||||
forward: forward, |
||||
} |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:reports' |
||||
|
||||
it 'creates a report', :aggregate_failures do |
||||
perform_enqueued_jobs do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
expect(body_as_json).to match( |
||||
a_hash_including( |
||||
status_ids: [status.id.to_s], |
||||
category: category, |
||||
comment: 'reasons' |
||||
) |
||||
) |
||||
|
||||
expect(target_account.targeted_reports).to_not be_empty |
||||
expect(target_account.targeted_reports.first.comment).to eq 'reasons' |
||||
|
||||
expect(ActionMailer::Base.deliveries.first.to).to eq([admin.email]) |
||||
end |
||||
end |
||||
|
||||
context 'when a status does not belong to the reported account' do |
||||
let(:target_account) { Fabricate(:account) } |
||||
|
||||
it 'returns http not found' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
|
||||
context 'when a category is chosen' do |
||||
let(:category) { 'spam' } |
||||
|
||||
it 'saves category' do |
||||
subject |
||||
|
||||
expect(target_account.targeted_reports.first.spam?).to be true |
||||
end |
||||
end |
||||
|
||||
context 'when violated rules are chosen' do |
||||
let(:rule) { Fabricate(:rule) } |
||||
let(:category) { 'violation' } |
||||
let(:rule_ids) { [rule.id] } |
||||
|
||||
it 'saves category and rule_ids' do |
||||
subject |
||||
|
||||
expect(target_account.targeted_reports.first.violation?).to be true |
||||
expect(target_account.targeted_reports.first.rule_ids).to contain_exactly(rule.id) |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,74 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
RSpec.describe 'Sources' do |
||||
let(:user) { Fabricate(:user) } |
||||
let(:scopes) { 'read:statuses' } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } |
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } |
||||
|
||||
describe 'GET /api/v1/statuses/:status_id/source' do |
||||
subject do |
||||
get "/api/v1/statuses/#{status.id}/source", headers: headers |
||||
end |
||||
|
||||
let(:status) { Fabricate(:status) } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:statuses' |
||||
|
||||
context 'with public status' do |
||||
it 'returns the source properties of the status', :aggregate_failures do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
expect(body_as_json).to eq({ |
||||
id: status.id.to_s, |
||||
text: status.text, |
||||
spoiler_text: status.spoiler_text, |
||||
content_type: nil, |
||||
}) |
||||
end |
||||
end |
||||
|
||||
context 'with private status of non-followed account' do |
||||
let(:status) { Fabricate(:status, visibility: :private) } |
||||
|
||||
it 'returns http not found' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
|
||||
context 'with private status of followed account' do |
||||
let(:status) { Fabricate(:status, visibility: :private) } |
||||
|
||||
before do |
||||
user.account.follow!(status.account) |
||||
end |
||||
|
||||
it 'returns the source properties of the status', :aggregate_failures do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
expect(body_as_json).to eq({ |
||||
id: status.id.to_s, |
||||
text: status.text, |
||||
spoiler_text: status.spoiler_text, |
||||
content_type: nil, |
||||
}) |
||||
end |
||||
end |
||||
|
||||
context 'without an authorization header' do |
||||
let(:headers) { {} } |
||||
|
||||
it 'returns http unauthorized' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(401) |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,116 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
RSpec.describe 'Tag' do |
||||
let(:user) { Fabricate(:user) } |
||||
let(:scopes) { 'read:statuses' } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } |
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } |
||||
|
||||
shared_examples 'a successful request to the tag timeline' do |
||||
it 'returns the expected statuses', :aggregate_failures do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
expect(body_as_json.pluck(:id)).to match_array(expected_statuses.map { |status| status.id.to_s }) |
||||
end |
||||
end |
||||
|
||||
describe 'GET /api/v1/timelines/tag/:hashtag' do |
||||
subject do |
||||
get "/api/v1/timelines/tag/#{hashtag}", headers: headers, params: params |
||||
end |
||||
|
||||
before do |
||||
Setting.timeline_preview = true |
||||
end |
||||
|
||||
let(:account) { Fabricate(:account) } |
||||
let!(:private_status) { PostStatusService.new.call(account, visibility: :private, text: '#life could be a dream') } # rubocop:disable RSpec/LetSetup |
||||
let!(:life_status) { PostStatusService.new.call(account, text: 'tell me what is my #life without your #love') } |
||||
let!(:war_status) { PostStatusService.new.call(user.account, text: '#war, war never changes') } |
||||
let!(:love_status) { PostStatusService.new.call(account, text: 'what is #love?') } |
||||
let(:params) { {} } |
||||
let(:hashtag) { 'life' } |
||||
|
||||
context 'when given only one hashtag' do |
||||
let(:expected_statuses) { [life_status] } |
||||
|
||||
it_behaves_like 'a successful request to the tag timeline' |
||||
end |
||||
|
||||
context 'with any param' do |
||||
let(:expected_statuses) { [life_status, love_status] } |
||||
let(:params) { { any: %(love) } } |
||||
|
||||
it_behaves_like 'a successful request to the tag timeline' |
||||
end |
||||
|
||||
context 'with all param' do |
||||
let(:expected_statuses) { [life_status] } |
||||
let(:params) { { all: %w(love) } } |
||||
|
||||
it_behaves_like 'a successful request to the tag timeline' |
||||
end |
||||
|
||||
context 'with none param' do |
||||
let(:expected_statuses) { [war_status] } |
||||
let(:hashtag) { 'war' } |
||||
let(:params) { { none: %w(life love) } } |
||||
|
||||
it_behaves_like 'a successful request to the tag timeline' |
||||
end |
||||
|
||||
context 'with limit param' do |
||||
let(:hashtag) { 'love' } |
||||
let(:params) { { limit: 1 } } |
||||
|
||||
it 'returns only the requested number of statuses' do |
||||
subject |
||||
|
||||
expect(body_as_json.size).to eq(params[:limit]) |
||||
end |
||||
|
||||
it 'sets the correct pagination headers', :aggregate_failures do |
||||
subject |
||||
|
||||
headers = response.headers['Link'] |
||||
|
||||
expect(headers.find_link(%w(rel prev)).href).to eq(api_v1_timelines_tag_url(limit: 1, min_id: love_status.id.to_s)) |
||||
expect(headers.find_link(%w(rel next)).href).to eq(api_v1_timelines_tag_url(limit: 1, max_id: love_status.id.to_s)) |
||||
end |
||||
end |
||||
|
||||
context 'when the instance allows public preview' do |
||||
context 'when the user is not authenticated' do |
||||
let(:headers) { {} } |
||||
let(:expected_statuses) { [life_status] } |
||||
|
||||
it_behaves_like 'a successful request to the tag timeline' |
||||
end |
||||
end |
||||
|
||||
context 'when the instance does not allow public preview' do |
||||
before do |
||||
Form::AdminSettings.new(timeline_preview: false).save |
||||
end |
||||
|
||||
context 'when the user is not authenticated' do |
||||
let(:headers) { {} } |
||||
|
||||
it 'returns http unauthorized' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(401) |
||||
end |
||||
end |
||||
|
||||
context 'when the user is authenticated' do |
||||
let(:expected_statuses) { [life_status] } |
||||
|
||||
it_behaves_like 'a successful request to the tag timeline' |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,21 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
module SignedRequestHelpers |
||||
def get(path, headers: nil, sign_with: nil, **args) |
||||
return super path, headers: headers, **args if sign_with.nil? |
||||
|
||||
headers ||= {} |
||||
headers['Date'] = Time.now.utc.httpdate |
||||
headers['Host'] = ENV.fetch('LOCAL_DOMAIN') |
||||
signed_headers = headers.merge('(request-target)' => "get #{path}").slice('(request-target)', 'Host', 'Date') |
||||
|
||||
key_id = ActivityPub::TagManager.instance.key_uri_for(sign_with) |
||||
keypair = sign_with.keypair |
||||
signed_string = signed_headers.map { |key, value| "#{key.downcase}: #{value}" }.join("\n") |
||||
signature = Base64.strict_encode64(keypair.sign(OpenSSL::Digest.new('SHA256'), signed_string)) |
||||
|
||||
headers['Signature'] = "keyId=\"#{key_id}\",algorithm=\"rsa-sha256\",headers=\"#{signed_headers.keys.join(' ').downcase}\",signature=\"#{signature}\"" |
||||
|
||||
super path, headers: headers, **args |
||||
end |
||||
end |
@ -0,0 +1,83 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
describe ExistingUsernameValidator do |
||||
let(:record_class) do |
||||
Class.new do |
||||
include ActiveModel::Validations |
||||
attr_accessor :contact, :friends |
||||
|
||||
def self.name |
||||
'Record' |
||||
end |
||||
|
||||
validates :contact, existing_username: true |
||||
validates :friends, existing_username: { multiple: true } |
||||
end |
||||
end |
||||
let(:record) { record_class.new } |
||||
|
||||
describe '#validate_each' do |
||||
context 'with a nil value' do |
||||
it 'does not add errors' do |
||||
record.contact = nil |
||||
|
||||
expect(record).to be_valid |
||||
expect(record.errors).to be_empty |
||||
end |
||||
end |
||||
|
||||
context 'when there are no accounts' do |
||||
it 'adds errors to the record' do |
||||
record.contact = 'user@example.com' |
||||
|
||||
expect(record).to_not be_valid |
||||
expect(record.errors.first.attribute).to eq(:contact) |
||||
expect(record.errors.first.type).to eq I18n.t('existing_username_validator.not_found') |
||||
end |
||||
end |
||||
|
||||
context 'when there are accounts' do |
||||
before { Fabricate(:account, domain: 'example.com', username: 'user') } |
||||
|
||||
context 'when the value does not match' do |
||||
it 'adds errors to the record' do |
||||
record.contact = 'friend@other.host' |
||||
|
||||
expect(record).to_not be_valid |
||||
expect(record.errors.first.attribute).to eq(:contact) |
||||
expect(record.errors.first.type).to eq I18n.t('existing_username_validator.not_found') |
||||
end |
||||
|
||||
context 'when multiple is true' do |
||||
it 'adds errors to the record' do |
||||
record.friends = 'friend@other.host' |
||||
|
||||
expect(record).to_not be_valid |
||||
expect(record.errors.first.attribute).to eq(:friends) |
||||
expect(record.errors.first.type).to eq I18n.t('existing_username_validator.not_found_multiple', usernames: 'friend@other.host') |
||||
end |
||||
end |
||||
end |
||||
|
||||
context 'when the value does match' do |
||||
it 'does not add errors to the record' do |
||||
record.contact = 'user@example.com' |
||||
|
||||
expect(record).to be_valid |
||||
expect(record.errors).to be_empty |
||||
end |
||||
|
||||
context 'when multiple is true' do |
||||
it 'does not add errors to the record' do |
||||
record.friends = 'user@example.com' |
||||
|
||||
expect(record).to be_valid |
||||
expect(record.errors).to be_empty |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
Loading…
Reference in new issue