diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index c8365a6..3ca54c8 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -1,6 +1,6 @@ module Admin class UsersController < BaseController - before_action :set_user, only: [:show, :edit, :update, :destroy] + before_action :set_user, only: [:show, :edit, :update, :destroy, :resend_invitation] def index @users = User.order(created_at: :desc) @@ -16,9 +16,11 @@ module Admin def create @user = User.new(user_params) @user.password = SecureRandom.alphanumeric(16) if user_params[:password].blank? + @user.status = :pending_invitation if @user.save - redirect_to admin_users_path, notice: "User created successfully." + InvitationsMailer.invite_user(@user).deliver_later + redirect_to admin_users_path, notice: "User created successfully. Invitation email sent to #{@user.email_address}." else render :new, status: :unprocessable_entity end @@ -46,6 +48,16 @@ module Admin end end + def resend_invitation + unless @user.pending_invitation? + redirect_to admin_users_path, alert: "Cannot send invitation. User is not pending invitation." + return + end + + InvitationsMailer.invite_user(@user).deliver_later + redirect_to admin_users_path, notice: "Invitation email resent to #{@user.email_address}." + end + def destroy # Prevent admin from deleting themselves if @user == Current.session.user diff --git a/app/controllers/invitations_controller.rb b/app/controllers/invitations_controller.rb new file mode 100644 index 0000000..2dae64b --- /dev/null +++ b/app/controllers/invitations_controller.rb @@ -0,0 +1,31 @@ +class InvitationsController < ApplicationController + allow_unauthenticated_access + before_action :set_user_by_invitation_token, only: %i[ show update ] + + def show + # Show the password setup form + end + + def update + if @user.update(params.permit(:password, :password_confirmation)) + @user.update!(status: :active) + @user.sessions.destroy_all + redirect_to new_session_path, notice: "Your account has been set up successfully. Please sign in." + else + redirect_to invite_path(params[:token]), alert: "Passwords did not match." + end + end + + private + + def set_user_by_invitation_token + @user = User.find_by_invitation_login_token!(params[:token]) + + # Check if user is still pending invitation + unless @user.pending_invitation? + redirect_to new_session_path, alert: "This invitation has already been used or is no longer valid." + end + rescue ActiveSupport::MessageVerifier::InvalidSignature + redirect_to new_session_path, alert: "Invitation link is invalid or has expired." + end +end \ No newline at end of file diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 26da98a..65915f1 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -23,7 +23,11 @@ class SessionsController < ApplicationController # Check if user is active unless user.active? - redirect_to signin_path, alert: "Your account is not active. Please contact an administrator." + if user.pending_invitation? + redirect_to signin_path, alert: "Please check your email for an invitation to set up your account." + else + redirect_to signin_path, alert: "Your account is not active. Please contact an administrator." + end return end diff --git a/app/mailers/invitations_mailer.rb b/app/mailers/invitations_mailer.rb new file mode 100644 index 0000000..4943ccc --- /dev/null +++ b/app/mailers/invitations_mailer.rb @@ -0,0 +1,6 @@ +class InvitationsMailer < ApplicationMailer + def invite_user(user) + @user = user + mail subject: "You're invited to join Clinch", to: user.email_address + end +end \ No newline at end of file diff --git a/app/views/invitations/show.html.erb b/app/views/invitations/show.html.erb new file mode 100644 index 0000000..70edaf4 --- /dev/null +++ b/app/views/invitations/show.html.erb @@ -0,0 +1,22 @@ +
<%= alert %>
+ <% end %> + +You've been invited to join Clinch. Please create your password to complete your account setup.
+ + <%= form_with url: invite_path(params[:token]), method: :put, class: "contents" do |form| %> +