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`.th-downstream
commit
b867d4581e
@ -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