Merge commit 'e387175fc9a3ebfd72ab45ebfe43ecfabef7b0c3' into glitch-soc/merge-upstream
This commit is contained in:
@@ -18,4 +18,59 @@ describe Admin::AnnouncementsController do
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #new' do
|
||||
it 'returns http success and renders new' do
|
||||
get :new
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to render_template(:new)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #edit' do
|
||||
let(:announcement) { Fabricate(:announcement) }
|
||||
|
||||
it 'returns http success and renders edit' do
|
||||
get :edit, params: { id: announcement.id }
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to render_template(:edit)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
it 'creates a new announcement and redirects' do
|
||||
expect do
|
||||
post :create, params: { announcement: { text: 'The announcement message.' } }
|
||||
end.to change(Announcement, :count).by(1)
|
||||
|
||||
expect(response).to redirect_to(admin_announcements_path)
|
||||
expect(flash.notice).to match(I18n.t('admin.announcements.published_msg'))
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT #update' do
|
||||
let(:announcement) { Fabricate(:announcement, text: 'Original text') }
|
||||
|
||||
it 'updates an announcement and redirects' do
|
||||
put :update, params: { id: announcement.id, announcement: { text: 'Updated text.' } }
|
||||
|
||||
expect(response).to redirect_to(admin_announcements_path)
|
||||
expect(flash.notice).to match(I18n.t('admin.announcements.updated_msg'))
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE #destroy' do
|
||||
let!(:announcement) { Fabricate(:announcement, text: 'Original text') }
|
||||
|
||||
it 'destroys an announcement and redirects' do
|
||||
expect do
|
||||
delete :destroy, params: { id: announcement.id }
|
||||
end.to change(Announcement, :count).by(-1)
|
||||
|
||||
expect(response).to redirect_to(admin_announcements_path)
|
||||
expect(flash.notice).to match(I18n.t('admin.announcements.destroyed_msg'))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe Api::V1::FeaturedTagsController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') }
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
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
|
||||
end
|
||||
@@ -3,5 +3,5 @@
|
||||
Fabricator(:featured_tag) do
|
||||
account
|
||||
tag
|
||||
name 'Tag'
|
||||
name { sequence(:name) { |i| "Tag#{i}" } }
|
||||
end
|
||||
|
||||
35
spec/features/captcha_spec.rb
Normal file
35
spec/features/captcha_spec.rb
Normal file
@@ -0,0 +1,35 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe 'email confirmation flow when captcha is enabled' do
|
||||
let(:user) { Fabricate(:user, confirmed_at: nil, confirmation_token: 'foobar', created_by_application: client_app) }
|
||||
let(:client_app) { nil }
|
||||
|
||||
before do
|
||||
# rubocop:disable RSpec/AnyInstance -- easiest way to deal with that that I know of
|
||||
allow_any_instance_of(Auth::ConfirmationsController).to receive(:captcha_enabled?).and_return(true)
|
||||
allow_any_instance_of(Auth::ConfirmationsController).to receive(:check_captcha!).and_return(true)
|
||||
allow_any_instance_of(Auth::ConfirmationsController).to receive(:render_captcha).and_return(nil)
|
||||
# rubocop:enable RSpec/AnyInstance
|
||||
end
|
||||
|
||||
context 'when the user signed up through an app' do
|
||||
let(:client_app) { Fabricate(:application) }
|
||||
|
||||
it 'logs in' do
|
||||
visit "/auth/confirmation?confirmation_token=#{user.confirmation_token}&redirect_to_app=true"
|
||||
|
||||
# It presents the user with a captcha form
|
||||
expect(page).to have_title(I18n.t('auth.captcha_confirmation.title'))
|
||||
|
||||
# It does not confirm the user just yet
|
||||
expect(user.reload.confirmed?).to be false
|
||||
|
||||
# It redirects to app and confirms user
|
||||
click_on I18n.t('challenge.confirm')
|
||||
expect(user.reload.confirmed?).to be true
|
||||
expect(page).to have_current_path(/\A#{client_app.confirmation_redirect_uri}/, url: true)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -11,75 +11,79 @@ RSpec.describe StatusPolicy, type: :model do
|
||||
let(:bob) { Fabricate(:account, username: 'bob') }
|
||||
let(:status) { Fabricate(:status, account: alice) }
|
||||
|
||||
permissions :show?, :reblog? do
|
||||
it 'grants access when no viewer' do
|
||||
expect(subject).to permit(nil, status)
|
||||
end
|
||||
context 'with the permissions of show? and reblog?' do
|
||||
permissions :show?, :reblog? do
|
||||
it 'grants access when no viewer' do
|
||||
expect(subject).to permit(nil, status)
|
||||
end
|
||||
|
||||
it 'denies access when viewer is blocked' do
|
||||
block = Fabricate(:block)
|
||||
status.visibility = :private
|
||||
status.account = block.target_account
|
||||
it 'denies access when viewer is blocked' do
|
||||
block = Fabricate(:block)
|
||||
status.visibility = :private
|
||||
status.account = block.target_account
|
||||
|
||||
expect(subject).to_not permit(block.account, status)
|
||||
expect(subject).to_not permit(block.account, status)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
permissions :show? do
|
||||
it 'grants access when direct and account is viewer' do
|
||||
status.visibility = :direct
|
||||
context 'with the permission of show?' do
|
||||
permissions :show? do
|
||||
it 'grants access when direct and account is viewer' do
|
||||
status.visibility = :direct
|
||||
|
||||
expect(subject).to permit(status.account, status)
|
||||
end
|
||||
expect(subject).to permit(status.account, status)
|
||||
end
|
||||
|
||||
it 'grants access when direct and viewer is mentioned' do
|
||||
status.visibility = :direct
|
||||
status.mentions = [Fabricate(:mention, account: alice)]
|
||||
it 'grants access when direct and viewer is mentioned' do
|
||||
status.visibility = :direct
|
||||
status.mentions = [Fabricate(:mention, account: alice)]
|
||||
|
||||
expect(subject).to permit(alice, status)
|
||||
end
|
||||
expect(subject).to permit(alice, status)
|
||||
end
|
||||
|
||||
it 'grants access when direct and non-owner viewer is mentioned and mentions are loaded' do
|
||||
status.visibility = :direct
|
||||
status.mentions = [Fabricate(:mention, account: bob)]
|
||||
status.mentions.load
|
||||
it 'grants access when direct and non-owner viewer is mentioned and mentions are loaded' do
|
||||
status.visibility = :direct
|
||||
status.mentions = [Fabricate(:mention, account: bob)]
|
||||
status.mentions.load
|
||||
|
||||
expect(subject).to permit(bob, status)
|
||||
end
|
||||
expect(subject).to permit(bob, status)
|
||||
end
|
||||
|
||||
it 'denies access when direct and viewer is not mentioned' do
|
||||
viewer = Fabricate(:account)
|
||||
status.visibility = :direct
|
||||
it 'denies access when direct and viewer is not mentioned' do
|
||||
viewer = Fabricate(:account)
|
||||
status.visibility = :direct
|
||||
|
||||
expect(subject).to_not permit(viewer, status)
|
||||
end
|
||||
expect(subject).to_not permit(viewer, status)
|
||||
end
|
||||
|
||||
it 'grants access when private and account is viewer' do
|
||||
status.visibility = :private
|
||||
it 'grants access when private and account is viewer' do
|
||||
status.visibility = :private
|
||||
|
||||
expect(subject).to permit(status.account, status)
|
||||
end
|
||||
expect(subject).to permit(status.account, status)
|
||||
end
|
||||
|
||||
it 'grants access when private and account is following viewer' do
|
||||
follow = Fabricate(:follow)
|
||||
status.visibility = :private
|
||||
status.account = follow.target_account
|
||||
it 'grants access when private and account is following viewer' do
|
||||
follow = Fabricate(:follow)
|
||||
status.visibility = :private
|
||||
status.account = follow.target_account
|
||||
|
||||
expect(subject).to permit(follow.account, status)
|
||||
end
|
||||
expect(subject).to permit(follow.account, status)
|
||||
end
|
||||
|
||||
it 'grants access when private and viewer is mentioned' do
|
||||
status.visibility = :private
|
||||
status.mentions = [Fabricate(:mention, account: alice)]
|
||||
it 'grants access when private and viewer is mentioned' do
|
||||
status.visibility = :private
|
||||
status.mentions = [Fabricate(:mention, account: alice)]
|
||||
|
||||
expect(subject).to permit(alice, status)
|
||||
end
|
||||
expect(subject).to permit(alice, status)
|
||||
end
|
||||
|
||||
it 'denies access when private and viewer is not mentioned or followed' do
|
||||
viewer = Fabricate(:account)
|
||||
status.visibility = :private
|
||||
it 'denies access when private and viewer is not mentioned or followed' do
|
||||
viewer = Fabricate(:account)
|
||||
status.visibility = :private
|
||||
|
||||
expect(subject).to_not permit(viewer, status)
|
||||
expect(subject).to_not permit(viewer, status)
|
||||
end
|
||||
end
|
||||
|
||||
it 'denies access when local-only and the viewer is not logged in' do
|
||||
@@ -95,55 +99,63 @@ RSpec.describe StatusPolicy, type: :model do
|
||||
end
|
||||
end
|
||||
|
||||
permissions :reblog? do
|
||||
it 'denies access when private' do
|
||||
viewer = Fabricate(:account)
|
||||
status.visibility = :private
|
||||
context 'with the permission of reblog?' do
|
||||
permissions :reblog? do
|
||||
it 'denies access when private' do
|
||||
viewer = Fabricate(:account)
|
||||
status.visibility = :private
|
||||
|
||||
expect(subject).to_not permit(viewer, status)
|
||||
end
|
||||
expect(subject).to_not permit(viewer, status)
|
||||
end
|
||||
|
||||
it 'denies access when direct' do
|
||||
viewer = Fabricate(:account)
|
||||
status.visibility = :direct
|
||||
it 'denies access when direct' do
|
||||
viewer = Fabricate(:account)
|
||||
status.visibility = :direct
|
||||
|
||||
expect(subject).to_not permit(viewer, status)
|
||||
expect(subject).to_not permit(viewer, status)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
permissions :destroy?, :unreblog? do
|
||||
it 'grants access when account is deleter' do
|
||||
expect(subject).to permit(status.account, status)
|
||||
end
|
||||
context 'with the permissions of destroy? and unreblog?' do
|
||||
permissions :destroy?, :unreblog? do
|
||||
it 'grants access when account is deleter' do
|
||||
expect(subject).to permit(status.account, status)
|
||||
end
|
||||
|
||||
it 'denies access when account is not deleter' do
|
||||
expect(subject).to_not permit(bob, status)
|
||||
end
|
||||
it 'denies access when account is not deleter' do
|
||||
expect(subject).to_not permit(bob, status)
|
||||
end
|
||||
|
||||
it 'denies access when no deleter' do
|
||||
expect(subject).to_not permit(nil, status)
|
||||
it 'denies access when no deleter' do
|
||||
expect(subject).to_not permit(nil, status)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
permissions :favourite? do
|
||||
it 'grants access when viewer is not blocked' do
|
||||
follow = Fabricate(:follow)
|
||||
status.account = follow.target_account
|
||||
context 'with the permission of favourite?' do
|
||||
permissions :favourite? do
|
||||
it 'grants access when viewer is not blocked' do
|
||||
follow = Fabricate(:follow)
|
||||
status.account = follow.target_account
|
||||
|
||||
expect(subject).to permit(follow.account, status)
|
||||
end
|
||||
expect(subject).to permit(follow.account, status)
|
||||
end
|
||||
|
||||
it 'denies when viewer is blocked' do
|
||||
block = Fabricate(:block)
|
||||
status.account = block.target_account
|
||||
it 'denies when viewer is blocked' do
|
||||
block = Fabricate(:block)
|
||||
status.account = block.target_account
|
||||
|
||||
expect(subject).to_not permit(block.account, status)
|
||||
expect(subject).to_not permit(block.account, status)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
permissions :update? do
|
||||
it 'grants access if owner' do
|
||||
expect(subject).to permit(status.account, status)
|
||||
context 'with the permission of update?' do
|
||||
permissions :update? do
|
||||
it 'grants access if owner' do
|
||||
expect(subject).to permit(status.account, status)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -15,7 +15,7 @@ RSpec.describe StatusRelationshipsPresenter do
|
||||
let(:presenter) { StatusRelationshipsPresenter.new(statuses, current_account_id, **options) }
|
||||
let(:current_account_id) { Fabricate(:account).id }
|
||||
let(:statuses) { [Fabricate(:status)] }
|
||||
let(:status_ids) { statuses.map(&:id) + statuses.map(&:reblog_of_id).compact }
|
||||
let(:status_ids) { statuses.map(&:id) + statuses.filter_map(&:reblog_of_id) }
|
||||
let(:default_map) { { 1 => true } }
|
||||
|
||||
context 'when options are not set' do
|
||||
|
||||
201
spec/requests/api/v1/featured_tags_spec.rb
Normal file
201
spec/requests/api/v1/featured_tags_spec.rb
Normal file
@@ -0,0 +1,201 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'FeaturedTags' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:accounts write:accounts' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope|
|
||||
let(:scopes) { wrong_scope }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v1/featured_tags' do
|
||||
context 'with wrong scope' do
|
||||
before do
|
||||
get '/api/v1/featured_tags', headers: headers
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read:statuses'
|
||||
end
|
||||
|
||||
context 'when Authorization header is missing' do
|
||||
it 'returns http unauthorized' do
|
||||
get '/api/v1/featured_tags'
|
||||
|
||||
expect(response).to have_http_status(401)
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
get '/api/v1/featured_tags', headers: headers
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
context 'when the requesting user has no featured tag' do
|
||||
before { Fabricate.times(3, :featured_tag) }
|
||||
|
||||
it 'returns an empty body' do
|
||||
get '/api/v1/featured_tags', headers: headers
|
||||
|
||||
body = body_as_json
|
||||
|
||||
expect(body).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the requesting user has featured tags' do
|
||||
let!(:user_featured_tags) { Fabricate.times(5, :featured_tag, account: user.account) }
|
||||
|
||||
it 'returns only the featured tags belonging to the requesting user' do
|
||||
get '/api/v1/featured_tags', headers: headers
|
||||
|
||||
body = body_as_json
|
||||
expected_ids = user_featured_tags.pluck(:id).map(&:to_s)
|
||||
|
||||
expect(body.pluck(:id)).to match_array(expected_ids)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/featured_tags' do
|
||||
let(:params) { { name: 'tag' } }
|
||||
|
||||
it 'returns http success' do
|
||||
post '/api/v1/featured_tags', headers: headers, params: params
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the correct tag name' do
|
||||
post '/api/v1/featured_tags', headers: headers, params: params
|
||||
|
||||
body = body_as_json
|
||||
|
||||
expect(body[:name]).to eq(params[:name])
|
||||
end
|
||||
|
||||
it 'creates a new featured tag for the requesting user' do
|
||||
post '/api/v1/featured_tags', headers: headers, params: params
|
||||
|
||||
featured_tag = FeaturedTag.find_by(name: params[:name], account: user.account)
|
||||
|
||||
expect(featured_tag).to be_present
|
||||
end
|
||||
|
||||
context 'with wrong scope' do
|
||||
before do
|
||||
post '/api/v1/featured_tags', headers: headers, params: params
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read:statuses'
|
||||
end
|
||||
|
||||
context 'when Authorization header is missing' do
|
||||
it 'returns http unauthorized' do
|
||||
post '/api/v1/featured_tags', params: params
|
||||
|
||||
expect(response).to have_http_status(401)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when required param "name" is not provided' do
|
||||
it 'returns http bad request' do
|
||||
post '/api/v1/featured_tags', headers: headers
|
||||
|
||||
expect(response).to have_http_status(400)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when provided tag name is invalid' do
|
||||
let(:params) { { name: 'asj&*!' } }
|
||||
|
||||
it 'returns http unprocessable entity' do
|
||||
post '/api/v1/featured_tags', headers: headers, params: params
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when tag name is already taken' do
|
||||
before do
|
||||
FeaturedTag.create(name: params[:name], account: user.account)
|
||||
end
|
||||
|
||||
it 'returns http unprocessable entity' do
|
||||
post '/api/v1/featured_tags', headers: headers, params: params
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE /api/v1/featured_tags' do
|
||||
let!(:featured_tag) { FeaturedTag.create(name: 'tag', account: user.account) }
|
||||
let(:id) { featured_tag.id }
|
||||
|
||||
it 'returns http success' do
|
||||
delete "/api/v1/featured_tags/#{id}", headers: headers
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns an empty body' do
|
||||
delete "/api/v1/featured_tags/#{id}", headers: headers
|
||||
|
||||
body = body_as_json
|
||||
|
||||
expect(body).to be_empty
|
||||
end
|
||||
|
||||
it 'deletes the featured tag' do
|
||||
delete "/api/v1/featured_tags/#{id}", headers: headers
|
||||
|
||||
featured_tag = FeaturedTag.find_by(id: id)
|
||||
|
||||
expect(featured_tag).to be_nil
|
||||
end
|
||||
|
||||
context 'with wrong scope' do
|
||||
before do
|
||||
delete "/api/v1/featured_tags/#{id}", headers: headers
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read:statuses'
|
||||
end
|
||||
|
||||
context 'when Authorization header is missing' do
|
||||
it 'returns http unauthorized' do
|
||||
delete "/api/v1/featured_tags/#{id}"
|
||||
|
||||
expect(response).to have_http_status(401)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when featured tag with given id does not exist' do
|
||||
it 'returns http not found' do
|
||||
delete '/api/v1/featured_tags/0', headers: headers
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when deleting a featured tag of another user' do
|
||||
let!(:other_user_featured_tag) { Fabricate(:featured_tag) }
|
||||
let(:id) { other_user_featured_tag.id }
|
||||
|
||||
it 'returns http not found' do
|
||||
delete "/api/v1/featured_tags/#{id}", headers: headers
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user