964ae8eee5
Allow access to account settings, 2FA, authorized applications, and account deletions to unconfirmed and pending users, as well as users who had their accounts disabled. Suspended users cannot update their e-mail or password or delete their account. Display account status on account settings page, for example, when an account is frozen, limited, unconfirmed or pending review. After sign up, login users straight away and show a simple page that tells them the status of their account with links to account settings and logout, to reduce onboarding friction and allow users to correct wrongly typed e-mail addresses. Move the final sign-up step of SSO integrations to be the same as above to reduce code duplication.
364 lines
9.8 KiB
Ruby
364 lines
9.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'rails_helper'
|
|
|
|
describe ApplicationController, type: :controller do
|
|
controller do
|
|
def success
|
|
head 200
|
|
end
|
|
|
|
def routing_error
|
|
raise ActionController::RoutingError, ''
|
|
end
|
|
|
|
def record_not_found
|
|
raise ActiveRecord::RecordNotFound, ''
|
|
end
|
|
|
|
def invalid_authenticity_token
|
|
raise ActionController::InvalidAuthenticityToken, ''
|
|
end
|
|
end
|
|
|
|
shared_examples 'respond_with_error' do |code|
|
|
it "returns http #{code} for any" do
|
|
subject
|
|
expect(response).to have_http_status(code)
|
|
end
|
|
|
|
it "returns http #{code} for http" do
|
|
subject
|
|
expect(response).to have_http_status(code)
|
|
end
|
|
|
|
it "renders template for http" do
|
|
is_expected.to render_template("errors/#{code}", layout: 'error')
|
|
end
|
|
end
|
|
|
|
context 'forgery' do
|
|
subject do
|
|
ActionController::Base.allow_forgery_protection = true
|
|
routes.draw { post 'success' => 'anonymous#success' }
|
|
post 'success'
|
|
end
|
|
|
|
include_examples 'respond_with_error', 422
|
|
end
|
|
|
|
it "does not force ssl if Rails.env.production? is not 'true'" do
|
|
routes.draw { get 'success' => 'anonymous#success' }
|
|
allow(Rails.env).to receive(:production?).and_return(false)
|
|
get 'success'
|
|
expect(response).to have_http_status(200)
|
|
end
|
|
|
|
it "forces ssl if Rails.env.production? is 'true'" do
|
|
routes.draw { get 'success' => 'anonymous#success' }
|
|
allow(Rails.env).to receive(:production?).and_return(true)
|
|
get 'success'
|
|
expect(response).to redirect_to('https://test.host/success')
|
|
end
|
|
|
|
describe 'helper_method :current_account' do
|
|
it 'returns nil if not signed in' do
|
|
expect(controller.view_context.current_account).to be_nil
|
|
end
|
|
|
|
it 'returns account if signed in' do
|
|
account = Fabricate(:account)
|
|
sign_in(Fabricate(:user, account: account))
|
|
expect(controller.view_context.current_account).to eq account
|
|
end
|
|
end
|
|
|
|
describe 'helper_method :single_user_mode?' do
|
|
it 'returns false if it is in single_user_mode but there is no account' do
|
|
allow(Rails.configuration.x).to receive(:single_user_mode).and_return(true)
|
|
expect(controller.view_context.single_user_mode?).to eq false
|
|
end
|
|
|
|
it 'returns false if there is an account but it is not in single_user_mode' do
|
|
allow(Rails.configuration.x).to receive(:single_user_mode).and_return(false)
|
|
Fabricate(:account)
|
|
expect(controller.view_context.single_user_mode?).to eq false
|
|
end
|
|
|
|
it 'returns true if it is in single_user_mode and there is an account' do
|
|
allow(Rails.configuration.x).to receive(:single_user_mode).and_return(true)
|
|
Fabricate(:account)
|
|
expect(controller.view_context.single_user_mode?).to eq true
|
|
end
|
|
end
|
|
|
|
describe 'helper_method :current_theme' do
|
|
it 'returns "default" when theme wasn\'t changed in admin settings' do
|
|
allow(Setting).to receive(:default_settings).and_return({ 'theme' => 'default' })
|
|
|
|
expect(controller.view_context.current_theme).to eq 'default'
|
|
end
|
|
|
|
it 'returns instances\'s theme when user is not signed in' do
|
|
allow(Setting).to receive(:[]).with('theme').and_return 'contrast'
|
|
|
|
expect(controller.view_context.current_theme).to eq 'contrast'
|
|
end
|
|
|
|
it 'returns instances\'s default theme when user didn\'t set theme' do
|
|
current_user = Fabricate(:user)
|
|
sign_in current_user
|
|
|
|
allow(Setting).to receive(:[]).with('theme').and_return 'contrast'
|
|
|
|
expect(controller.view_context.current_theme).to eq 'contrast'
|
|
end
|
|
|
|
it 'returns user\'s theme when it is set' do
|
|
current_user = Fabricate(:user)
|
|
current_user.settings['theme'] = 'mastodon-light'
|
|
sign_in current_user
|
|
|
|
allow(Setting).to receive(:[]).with('theme').and_return 'contrast'
|
|
|
|
expect(controller.view_context.current_theme).to eq 'mastodon-light'
|
|
end
|
|
end
|
|
|
|
context 'ActionController::RoutingError' do
|
|
subject do
|
|
routes.draw { get 'routing_error' => 'anonymous#routing_error' }
|
|
get 'routing_error'
|
|
end
|
|
|
|
include_examples 'respond_with_error', 404
|
|
end
|
|
|
|
context 'ActiveRecord::RecordNotFound' do
|
|
subject do
|
|
routes.draw { get 'record_not_found' => 'anonymous#record_not_found' }
|
|
get 'record_not_found'
|
|
end
|
|
|
|
include_examples 'respond_with_error', 404
|
|
end
|
|
|
|
context 'ActionController::InvalidAuthenticityToken' do
|
|
subject do
|
|
routes.draw { get 'invalid_authenticity_token' => 'anonymous#invalid_authenticity_token' }
|
|
get 'invalid_authenticity_token'
|
|
end
|
|
|
|
include_examples 'respond_with_error', 422
|
|
end
|
|
|
|
describe 'before_action :store_current_location' do
|
|
it 'stores location for user if it is not devise controller' do
|
|
routes.draw { get 'success' => 'anonymous#success' }
|
|
get 'success'
|
|
expect(controller.stored_location_for(:user)).to eq '/success'
|
|
end
|
|
|
|
context do
|
|
controller Devise::SessionsController do
|
|
end
|
|
|
|
it 'does not store location for user if it is devise controller' do
|
|
@request.env["devise.mapping"] = Devise.mappings[:user]
|
|
get 'create'
|
|
expect(controller.stored_location_for(:user)).to be_nil
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'before_action :check_suspension' do
|
|
before do
|
|
routes.draw { get 'success' => 'anonymous#success' }
|
|
end
|
|
|
|
it 'does nothing if not signed in' do
|
|
get 'success'
|
|
expect(response).to have_http_status(200)
|
|
end
|
|
|
|
it 'does nothing if user who signed in is not suspended' do
|
|
sign_in(Fabricate(:user, account: Fabricate(:account, suspended: false)))
|
|
get 'success'
|
|
expect(response).to have_http_status(200)
|
|
end
|
|
|
|
it 'redirects to account status page' do
|
|
sign_in(Fabricate(:user, account: Fabricate(:account, suspended: true)))
|
|
get 'success'
|
|
expect(response).to redirect_to(edit_user_registration_path)
|
|
end
|
|
end
|
|
|
|
describe 'raise_not_found' do
|
|
it 'raises error' do
|
|
controller.params[:unmatched_route] = 'unmatched'
|
|
expect { controller.raise_not_found }.to raise_error(ActionController::RoutingError, 'No route matches unmatched')
|
|
end
|
|
end
|
|
|
|
describe 'require_admin!' do
|
|
controller do
|
|
before_action :require_admin!
|
|
|
|
def sucesss
|
|
head 200
|
|
end
|
|
end
|
|
|
|
before do
|
|
routes.draw { get 'sucesss' => 'anonymous#sucesss' }
|
|
end
|
|
|
|
it 'returns a 403 if current user is not admin' do
|
|
sign_in(Fabricate(:user, admin: false))
|
|
get 'sucesss'
|
|
expect(response).to have_http_status(403)
|
|
end
|
|
|
|
it 'returns a 403 if current user is only a moderator' do
|
|
sign_in(Fabricate(:user, moderator: true))
|
|
get 'sucesss'
|
|
expect(response).to have_http_status(403)
|
|
end
|
|
|
|
it 'does nothing if current user is admin' do
|
|
sign_in(Fabricate(:user, admin: true))
|
|
get 'sucesss'
|
|
expect(response).to have_http_status(200)
|
|
end
|
|
end
|
|
|
|
describe 'require_staff!' do
|
|
controller do
|
|
before_action :require_staff!
|
|
|
|
def sucesss
|
|
head 200
|
|
end
|
|
end
|
|
|
|
before do
|
|
routes.draw { get 'sucesss' => 'anonymous#sucesss' }
|
|
end
|
|
|
|
it 'returns a 403 if current user is not admin or moderator' do
|
|
sign_in(Fabricate(:user, admin: false, moderator: false))
|
|
get 'sucesss'
|
|
expect(response).to have_http_status(403)
|
|
end
|
|
|
|
it 'does nothing if current user is moderator' do
|
|
sign_in(Fabricate(:user, moderator: true))
|
|
get 'sucesss'
|
|
expect(response).to have_http_status(200)
|
|
end
|
|
|
|
it 'does nothing if current user is admin' do
|
|
sign_in(Fabricate(:user, admin: true))
|
|
get 'sucesss'
|
|
expect(response).to have_http_status(200)
|
|
end
|
|
end
|
|
|
|
describe 'forbidden' do
|
|
controller do
|
|
def route_forbidden
|
|
forbidden
|
|
end
|
|
end
|
|
|
|
subject do
|
|
routes.draw { get 'route_forbidden' => 'anonymous#route_forbidden' }
|
|
get 'route_forbidden'
|
|
end
|
|
|
|
include_examples 'respond_with_error', 403
|
|
end
|
|
|
|
describe 'not_found' do
|
|
controller do
|
|
def route_not_found
|
|
not_found
|
|
end
|
|
end
|
|
|
|
subject do
|
|
routes.draw { get 'route_not_found' => 'anonymous#route_not_found' }
|
|
get 'route_not_found'
|
|
end
|
|
|
|
include_examples 'respond_with_error', 404
|
|
end
|
|
|
|
describe 'gone' do
|
|
controller do
|
|
def route_gone
|
|
gone
|
|
end
|
|
end
|
|
|
|
subject do
|
|
routes.draw { get 'route_gone' => 'anonymous#route_gone' }
|
|
get 'route_gone'
|
|
end
|
|
|
|
include_examples 'respond_with_error', 410
|
|
end
|
|
|
|
describe 'unprocessable_entity' do
|
|
controller do
|
|
def route_unprocessable_entity
|
|
unprocessable_entity
|
|
end
|
|
end
|
|
|
|
subject do
|
|
routes.draw { get 'route_unprocessable_entity' => 'anonymous#route_unprocessable_entity' }
|
|
get 'route_unprocessable_entity'
|
|
end
|
|
|
|
include_examples 'respond_with_error', 422
|
|
end
|
|
|
|
describe 'cache_collection' do
|
|
class C < ApplicationController
|
|
public :cache_collection
|
|
end
|
|
|
|
shared_examples 'receives :with_includes' do |fabricator, klass|
|
|
it 'uses raw if it is not an ActiveRecord::Relation' do
|
|
record = Fabricate(fabricator)
|
|
expect(C.new.cache_collection([record], klass)).to eq [record]
|
|
end
|
|
end
|
|
|
|
shared_examples 'cacheable' do |fabricator, klass|
|
|
include_examples 'receives :with_includes', fabricator, klass
|
|
|
|
it 'calls cache_ids of raw if it is an ActiveRecord::Relation' do
|
|
record = Fabricate(fabricator)
|
|
relation = klass.none
|
|
allow(relation).to receive(:cache_ids).and_return([record])
|
|
expect(C.new.cache_collection(relation, klass)).to eq [record]
|
|
end
|
|
end
|
|
|
|
it 'returns raw unless class responds to :with_includes' do
|
|
raw = Object.new
|
|
expect(C.new.cache_collection(raw, Object)).to eq raw
|
|
end
|
|
|
|
context 'Notification' do
|
|
include_examples 'cacheable', :notification, Notification
|
|
end
|
|
|
|
context 'Status' do
|
|
include_examples 'cacheable', :status, Status
|
|
end
|
|
end
|
|
end
|