otwarchive-symphonyarchive/spec/controllers/users_controller_spec.rb

342 lines
12 KiB
Ruby
Raw Permalink Normal View History

2026-03-11 22:22:11 +00:00
require "spec_helper"
describe UsersController do
include RedirectExpectationHelper
include LoginMacros
shared_examples "an action only authorized admins can access" do |authorized_roles:|
before do
fake_login_admin(admin)
end
context "when logged in as an admin with no role" do
let(:admin) { create(:admin) }
it "redirects with an error" do
subject
it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.")
end
end
(Admin::VALID_ROLES - authorized_roles).each do |admin_role|
context "when logged in as an admin with role #{admin_role}" do
let(:admin) { create(:admin, roles: [admin_role]) }
it "redirects with an error" do
subject
it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.")
end
end
end
authorized_roles.each do |admin_role|
context "when logged in as an admin with role #{admin_role}" do
let(:admin) { create(:admin, roles: [admin_role]) }
it "succeeds" do
subject
success
end
end
end
end
shared_examples "blocks access for banned and suspended users" do
context "when logged in as a banned user" do
let(:user) { create(:user, banned: true) }
before do
fake_login_known_user(user)
end
it "redirects with an error" do
subject
it_redirects_to_simple(user_path(user))
expect(flash[:error]).to match("Your account has been banned")
end
end
context "when logged in as a suspended user" do
let(:user) { create(:user, suspended: true, suspended_until: 1.week.from_now) }
before do
fake_login_known_user(user)
end
it "redirects with an error" do
subject
it_redirects_to_simple(user_path(user))
expect(flash[:error]).to match("Your account has been suspended")
end
end
end
describe "GET #activate" do
let(:user) { create(:user, confirmed_at: nil) }
context "with no activation key" do
it "redirects with an error" do
get :activate, params: { id: "" }
it_redirects_to_with_error(root_path, "Your activation key is missing.")
end
end
context "with an invalid activation key" do
it "redirects with an error" do
get :activate, params: { id: "foobar" }
it_redirects_to_with_error(root_path, "Your activation key is invalid. If you didn't activate within 14 days, your account was deleted. Please sign up again, or contact support via the link in our footer for more help.")
end
end
context "with a used activation key" do
before { user.activate }
it "redirects with an error" do
expect(user.active?).to be_truthy
get :activate, params: { id: user.confirmation_token }
it_redirects_to_with_error(user_path(user), "Your account has already been activated.")
end
end
context "with a valid activation key" do
it "activates the account and redirects with a success message" do
expect(user.active?).to be_falsey
get :activate, params: { id: user.confirmation_token }
expect(user.reload.active?).to be_truthy
it_redirects_to_with_notice(new_user_session_path, "Account activation complete! Please log in.")
end
end
end
describe "show" do
let(:user) { create(:user) }
context "with a valid username" do
it "renders the show template" do
get :show, params: { id: user }
expect(response).to render_template(:show)
end
end
context "with an invalid username" do
it "raises an error" do
expect do
get :show, params: { id: "nobody" }
end.to raise_error ActiveRecord::RecordNotFound
end
end
end
describe "GET #change_username" do
let(:user) { create(:user) }
let(:success) { expect(response).to render_template(:change_username) }
subject { get :change_username, params: { id: user } }
context "when logged in as a valid user" do
before do
fake_login_known_user(user)
end
it "shows the change username form" do
subject
success
end
end
it_behaves_like "an action only authorized admins can access", authorized_roles: %w[superadmin policy_and_abuse]
it_behaves_like "blocks access for banned and suspended users"
end
describe "POST #changed_username" do
let(:user) { create(:user) }
let(:new_username) { "foo1234" }
let(:success) do
expect(user.reload.login).to eq(new_username)
end
subject do
post :changed_username, params: { id: user, new_login: new_username, password: user.password }
end
context "when logged in as a valid user" do
before do
fake_login_known_user(user)
end
it "updates the user's username" do
subject
success
end
end
it_behaves_like "an action only authorized admins can access", authorized_roles: %w[superadmin policy_and_abuse] do
# Non-exhaustive check that users who cannot access this page themselves (i.e. because they are banned)
# can still be renamed by an admin.
let(:user) { create(:user, banned: true) }
let(:new_username) { "user#{user.id}" }
before do
allow_any_instance_of(ZohoResourceClient).to receive(:find_ticket).and_return({
"status" => "Open",
"departmentId" => ""
})
end
subject do
post :changed_username, params: { id: user, new_login: new_username, ticket_number: 123 }
end
end
it_behaves_like "blocks access for banned and suspended users"
end
describe "PUT #confirm_change_email" do
let(:user) { create(:user, email: "old@example.com", password: "password") }
context "when logged out" do
it "errors and tells the user to log in" do
put :confirm_change_email, params: { id: user, new_email: "new@example.com", email_confirmation: "new@example.com", password_check: "password" }
it_redirects_to_with_error(user_path(user), "Sorry, you don't have permission to access the page you were trying to reach. Please log in.")
end
end
context "when logged in" do
before { fake_login_known_user(user) }
it "requires reauthentication" do
put :confirm_change_email, params: { id: user, new_email: "new@example.com", email_confirmation: "new@example.com" }
expect(response).to render_template(:change_email)
expect(flash[:error]).to eq("You must enter your password.")
end
it "disallows incorrect password" do
put :confirm_change_email, params: { id: user, new_email: "new@example.com", email_confirmation: "new@example.com", password_check: "wrong" }
expect(response).to render_template(:change_email)
expect(flash[:error]).to include("Your password was incorrect. Please try again or log out and reset your password via the link on")
end
it "disallows blank email address" do
put :confirm_change_email, params: { id: user, new_email: "", email_confirmation: "", password_check: "password" }
expect(response).to render_template(:change_email)
expect(flash[:error]).to eq("You must enter a new email address.")
end
it "requires a valid email address" do
put :confirm_change_email, params: { id: user, new_email: "wrong", email_confirmation: "wrong", password_check: "password" }
expect(response).to render_template(:change_email)
expect(assigns[:user].errors.full_messages).to include("Email should look like an email address.")
end
it "disallows non-matching email confirmation" do
put :confirm_change_email, params: { id: user, new_email: "new@example.com", email_confirmation: "different@example.com", password_check: "password" }
expect(response).to render_template(:change_email)
expect(flash[:error]).to eq("The email addresses you entered do not match. Please try again.")
end
it "allows case-insensitive email confirmation" do
put :confirm_change_email, params: { id: user, new_email: "new@example.com", email_confirmation: "NEW@example.com", password_check: "password" }
expect(response).to render_template(:confirm_change_email)
expect(flash[:error]).to be_blank
end
it "disallows using another user's email" do
create(:user, email: "new@example.com")
put :confirm_change_email, params: { id: user, new_email: "new@example.com", email_confirmation: "new@example.com", password_check: "password" }
expect(response).to render_template(:change_email)
expect(assigns[:user].errors.full_messages.first).to include("This email is already associated with another account. Please try again with a different email address.")
expect(assigns[:user].email).to eq("old@example.com")
end
it "disallows using current email" do
put :confirm_change_email, params: { id: user, new_email: "old@example.com", email_confirmation: "old@example.com", password_check: "password" }
expect(response).to render_template(:change_email)
expect(flash[:error]).to eq("Your new email address must be different from your current email.")
end
end
end
describe "POST #changed_email" do
let(:user) { create(:user, email: "old@example.com") }
context "when logged out" do
it "errors and tells the user to log in" do
post :changed_email, params: { id: user, new_email: "new@example.com" }
it_redirects_to_with_error(user_path(user), "Sorry, you don't have permission to access the page you were trying to reach. Please log in.")
end
end
context "when logged in" do
before { fake_login_known_user(user) }
it "requires a valid email address" do
post :changed_email, params: { id: user, new_email: "wrong" }
expect(response).to render_template(:change_email)
expect(assigns[:user].errors.full_messages).to include("Email should look like an email address.")
expect(assigns[:user].email).to eq("old@example.com")
end
end
end
describe "GET #reconfirm_email" do
let(:user) { create(:user) }
context "when logged out" do
it "errors and tells the user to log in" do
get :reconfirm_email, params: { id: user, confirmation_token: "foo" }
it_redirects_to_with_error(user_path(user), "Sorry, you don't have permission to access the page you were trying to reach. Please log in.")
end
end
context "when logged in as the wrong user" do
let(:another_user) { create(:user) }
before { fake_login_known_user(another_user) }
it "errors and tells the user to log out" do
get :reconfirm_email, params: { id: user, confirmation_token: "foo" }
it_redirects_to_with_error(user_path(user), "You are not logged in to the account whose email you are trying to change. Please log out and try again.")
end
end
context "when logged in as right user" do
before { fake_login_known_user(user) }
it "disallows invalid tokens" do
get :reconfirm_email, params: { id: user, confirmation_token: "foo" }
it_redirects_to_with_error(change_email_user_path(user), "This email confirmation link is invalid or expired. Please check your email for the correct link or submit the email change form again.")
end
end
end
describe "destroy" do
let(:user) { create(:user) }
before do
fake_login_known_user(user)
end
context "no log items" do
it "successfully destroys and redirects with success message" do
login = user.login
delete :destroy, params: { id: login }
it_redirects_to_with_notice(delete_confirmation_path, "You have successfully deleted your account.")
expect(User.find_by(login: login)).to be_nil
end
end
end
end