diff --git a/app/controllers/users/invitations_controller.rb b/app/controllers/users/invitations_controller.rb
deleted file mode 100644
index d2026c64e2..0000000000
--- a/app/controllers/users/invitations_controller.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-# frozen_string_literal: true
-
-class Users::InvitationsController < Devise::InvitationsController
- # GET /users/invitation/accept?invitation_token=abcdef123456
- def edit
- set_minimum_password_length
- # Ensure the invitation_token is set on the resource from the URL parameter
- resource.invitation_token = params[:invitation_token]
-
- # Removed logging of invitation tokens for security reasons
-
-
- render :edit
- end
-
- # PUT /users/invitation
- def update
- # Removed logging of invitation tokens for security reasons
- super
- end
-
- protected
-
- # Permit the invitation_token parameter
- def update_resource_params
- params.require(resource_name).permit(:invitation_token, :password, :password_confirmation)
- end
-end
diff --git a/app/views/devise/invitations/edit.html.erb b/app/views/devise/invitations/edit.html.erb
index 24d5348055..bb47799bf3 100644
--- a/app/views/devise/invitations/edit.html.erb
+++ b/app/views/devise/invitations/edit.html.erb
@@ -3,7 +3,7 @@
<%= form_with(model: resource, as: resource_name, url: invitation_path(resource_name), local: true, html: {method: :put}) do |f| %>
<%= render "/shared/error_messages", resource: resource %>
- <%= f.hidden_field :invitation_token %>
+ <%= f.hidden_field :invitation_token, readonly: true %>
<% if f.object.class.require_password_on_accepting %>
diff --git a/config/routes.rb b/config/routes.rb
index e486ce17cf..6f849a7f53 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -5,7 +5,7 @@
mount Rswag::Api::Engine => "/api-docs"
devise_for :all_casa_admins, path: "all_casa_admins", controllers: {sessions: "all_casa_admins/sessions"}
- devise_for :users, controllers: {sessions: "users/sessions", passwords: "users/passwords", invitations: "users/invitations"}
+ devise_for :users, controllers: {sessions: "users/sessions", passwords: "users/passwords"}
authenticate :all_casa_admins do
mount PgHero::Engine, at: "pg_dashboard", constraints: lambda { |request|
admin = request.env["warden"].user(:all_casa_admin)
diff --git a/spec/requests/users/invitations_controller_spec.rb b/spec/requests/users/invitations_controller_spec.rb
deleted file mode 100644
index eb403449e7..0000000000
--- a/spec/requests/users/invitations_controller_spec.rb
+++ /dev/null
@@ -1,236 +0,0 @@
-# frozen_string_literal: true
-
-require "rails_helper"
-
-RSpec.describe "Users::InvitationsController", type: :request do
- let(:casa_org) { create(:casa_org) }
- let(:volunteer) { create(:volunteer, casa_org: casa_org) }
-
- describe "GET /users/invitation/accept" do
- context "with valid invitation_token" do
- before do
- volunteer.invite!
- end
-
- it "sets invitation_token on the resource" do
- get accept_user_invitation_path(invitation_token: volunteer.raw_invitation_token)
-
- expect(response).to have_http_status(:success)
- expect(response.body).to include("Set my password")
- expect(response.body).to include(volunteer.raw_invitation_token)
- end
-
- it "renders the edit template" do
- get accept_user_invitation_path(invitation_token: volunteer.raw_invitation_token)
-
- expect(response).to render_template(:edit)
- end
- end
-
- context "without invitation_token" do
- it "redirects away" do
- get accept_user_invitation_path
-
- # Devise may redirect to root or sign_in depending on configuration
- expect(response).to have_http_status(:redirect)
- end
- end
- end
-
- describe "PUT /users/invitation" do
- let(:valid_password) { "Password123!" }
-
- context "with valid invitation_token and password" do
- before do
- volunteer.invite!
- end
-
- let(:params) do
- {
- user: {
- invitation_token: volunteer.raw_invitation_token,
- password: valid_password,
- password_confirmation: valid_password
- }
- }
- end
-
- it "accepts the invitation" do
- expect {
- put user_invitation_path, params: params
- }.to change { volunteer.reload.invitation_accepted_at }.from(nil)
- end
-
- it "sets the password" do
- put user_invitation_path, params: params
-
- volunteer.reload
- expect(volunteer.valid_password?(valid_password)).to be true
- end
-
- it "signs in the user" do
- put user_invitation_path, params: params
-
- expect(controller.current_user).to eq(volunteer)
- end
-
- it "redirects after acceptance" do
- put user_invitation_path, params: params
-
- expect(response).to redirect_to(authenticated_user_root_path)
- end
- end
-
- context "with invalid invitation_token" do
- let(:params) do
- {
- user: {
- invitation_token: "invalid_token",
- password: valid_password,
- password_confirmation: valid_password
- }
- }
- end
-
- it "does not accept the invitation" do
- put user_invitation_path, params: params
-
- expect(response).to have_http_status(:success)
- expect(response.body).to include("Invitation token is invalid")
- end
- end
-
- context "with blank invitation_token" do
- let(:params) do
- {
- user: {
- invitation_token: "",
- password: valid_password,
- password_confirmation: valid_password
- }
- }
- end
-
- it "shows validation error" do
- put user_invitation_path, params: params
-
- expect(response).to have_http_status(:success)
- expect(response.body).to include("Invitation token")
- end
- end
-
- context "with mismatched passwords" do
- before do
- volunteer.invite!
- end
-
- let(:params) do
- {
- user: {
- invitation_token: volunteer.raw_invitation_token,
- password: valid_password,
- password_confirmation: "DifferentPassword123!"
- }
- }
- end
-
- it "does not accept the invitation" do
- expect {
- put user_invitation_path, params: params
- }.not_to change { volunteer.reload.invitation_accepted_at }
- end
-
- it "shows validation error" do
- put user_invitation_path, params: params
-
- expect(response).to have_http_status(:success)
- expect(response.body).to include("Password confirmation")
- end
- end
-
- context "with password too short" do
- before do
- volunteer.invite!
- end
-
- let(:params) do
- {
- user: {
- invitation_token: volunteer.raw_invitation_token,
- password: "short",
- password_confirmation: "short"
- }
- }
- end
-
- it "does not accept the invitation" do
- expect {
- put user_invitation_path, params: params
- }.not_to change { volunteer.reload.invitation_accepted_at }
- end
-
- it "shows validation error" do
- put user_invitation_path, params: params
-
- expect(response).to have_http_status(:success)
- expect(response.body).to include("Password is too short")
- end
- end
-
- context "with expired invitation" do
- before do
- volunteer.invite!
- travel_to 2.years.from_now
- end
-
- after do
- travel_back
- end
-
- let(:params) do
- {
- user: {
- invitation_token: volunteer.raw_invitation_token,
- password: valid_password,
- password_confirmation: valid_password
- }
- }
- end
-
- it "does not accept the invitation" do
- expect {
- put user_invitation_path, params: params
- }.not_to change { volunteer.reload.invitation_accepted_at }
- end
-
- it "shows validation error" do
- put user_invitation_path, params: params
-
- expect(response).to have_http_status(:success)
- expect(response.body).to include("Invitation token is invalid")
- end
- end
- end
-
- describe "parameter sanitization" do
- before do
- volunteer.invite!
- end
-
- it "permits invitation_token in update" do
- params = {
- user: {
- invitation_token: volunteer.raw_invitation_token,
- password: "Password123!",
- password_confirmation: "Password123!",
- extra_param: "should_not_be_permitted"
- }
- }
-
- put user_invitation_path, params: params
-
- # If the invitation_token was properly permitted, the invitation should be accepted
- expect(volunteer.reload.invitation_accepted_at).to be_present
- end
- end
-end
diff --git a/spec/views/devise/invitations/edit.html.erb_spec.rb b/spec/views/devise/invitations/edit.html.erb_spec.rb
deleted file mode 100644
index a01a7bb57e..0000000000
--- a/spec/views/devise/invitations/edit.html.erb_spec.rb
+++ /dev/null
@@ -1,55 +0,0 @@
-# frozen_string_literal: true
-
-require "rails_helper"
-
-RSpec.describe "devise/invitations/edit.html.erb", type: :view do
- let(:casa_org) { create(:casa_org) }
- let(:volunteer) { create(:volunteer, casa_org: casa_org) }
-
- before do
- volunteer.invite!
- assign(:resource, volunteer)
- assign(:resource_name, :user)
- assign(:devise_mapping, Devise.mappings[:user])
- assign(:minimum_password_length, 6)
-
- # Set the invitation_token on the resource as the controller does
- volunteer.invitation_token = volunteer.raw_invitation_token
-
- # Allow the class to respond to require_password_on_accepting
- allow(volunteer.class).to receive(:require_password_on_accepting).and_return(true)
-
- render
- end
-
- it "uses form_with with local: true" do
- # form_with local: true should not have data-remote="true"
- expect(rendered).not_to have_selector('form[data-remote="true"]')
- end
-
- it "includes invitation_token field" do
- expect(rendered).to match(/invitation_token/)
- end
-
- it "does not have readonly attribute on invitation_token field" do
- expect(rendered).not_to match(/invitation_token.*readonly/)
- end
-
- it "includes password fields" do
- expect(rendered).to match(/password/)
- expect(rendered).to match(/password_confirmation/)
- end
-
- it "includes submit button" do
- expect(rendered).to have_button("Set my password")
- end
-
- it "uses PUT method" do
- expect(rendered).to have_selector('form[method="post"]') # Rails uses POST with _method=put
- expect(rendered).to have_field("_method", type: :hidden, with: "put")
- end
-
- it "posts to invitation_path" do
- expect(rendered).to have_selector("form[action='#{user_invitation_path}']")
- end
-end