From 5921cf82c25322d57a9ce8246ab649bba29e8a5a Mon Sep 17 00:00:00 2001 From: Dan Milne Date: Sat, 25 Oct 2025 13:49:10 +1100 Subject: [PATCH] Add invite button and routes for resending invitations --- Gemfile | 4 ++-- Gemfile.lock | 16 ++++++++-------- app/models/user.rb | 1 + app/views/admin/users/index.html.erb | 3 +++ app/views/layouts/application.html.erb | 2 +- config/routes.rb | 7 ++++++- 6 files changed, 21 insertions(+), 12 deletions(-) diff --git a/Gemfile b/Gemfile index 0bc986a..6113637 100644 --- a/Gemfile +++ b/Gemfile @@ -26,10 +26,10 @@ gem "bcrypt", "~> 3.1.7" gem "rotp", "~> 6.3" # QR code generation for TOTP setup -gem "rqrcode", "~> 2.0" +gem "rqrcode", "~> 3.1" # JWT for OIDC ID tokens -gem "jwt", "~> 2.9" +gem "jwt", "~> 3.1" # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem "tzinfo-data", platforms: %i[ windows jruby ] diff --git a/Gemfile.lock b/Gemfile.lock index 50efbbf..2aa1354 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -145,7 +145,7 @@ GEM actionview (>= 7.0.0) activesupport (>= 7.0.0) json (2.15.1) - jwt (2.10.2) + jwt (3.1.2) base64 kamal (2.8.1) activesupport (>= 7.0) @@ -276,10 +276,10 @@ GEM io-console (~> 0.5) rexml (3.4.4) rotp (6.3.0) - rqrcode (2.2.0) + rqrcode (3.1.0) chunky_png (~> 1.0) - rqrcode_core (~> 1.0) - rqrcode_core (1.2.0) + rqrcode_core (~> 2.0) + rqrcode_core (2.0.0) rubocop (1.81.6) json (~> 2.3) language_server-protocol (~> 3.17.0.2) @@ -312,9 +312,9 @@ GEM ruby-vips (2.2.5) ffi (~> 1.12) logger - rubyzip (3.2.0) + rubyzip (3.2.1) securerandom (0.4.1) - selenium-webdriver (4.37.0) + selenium-webdriver (4.38.0) base64 (~> 0.2) logger (~> 1.4) rexml (~> 3.2, >= 3.2.5) @@ -414,13 +414,13 @@ DEPENDENCIES image_processing (~> 1.2) importmap-rails jbuilder - jwt (~> 2.9) + jwt (~> 3.1) kamal propshaft puma (>= 5.0) rails (~> 8.1.0) rotp (~> 6.3) - rqrcode (~> 2.0) + rqrcode (~> 3.1) rubocop-rails-omakase selenium-webdriver solid_cable diff --git a/app/models/user.rb b/app/models/user.rb index 30842e5..b289a69 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -8,6 +8,7 @@ class User < ApplicationRecord has_many :oidc_user_consents, dependent: :destroy # Token generation for passwordless flows + generates_token_for :invitation_login, expires_in: 24.hours generates_token_for :invitation, expires_in: 7.days generates_token_for :password_reset, expires_in: 1.hour generates_token_for :magic_login, expires_in: 15.minutes diff --git a/app/views/admin/users/index.html.erb b/app/views/admin/users/index.html.erb index d8d257f..c12955b 100644 --- a/app/views/admin/users/index.html.erb +++ b/app/views/admin/users/index.html.erb @@ -66,6 +66,9 @@ <%= user.groups.count %> + <% if user.pending_invitation? %> + <%= button_to "Resend", resend_invitation_admin_user_path(user), method: :post, class: "text-yellow-600 hover:text-yellow-900 mr-4" %> + <% end %> <%= link_to "Edit", edit_admin_user_path(user), class: "text-blue-600 hover:text-blue-900 mr-4" %> <%= button_to "Delete", admin_user_path(user), method: :delete, data: { turbo_confirm: "Are you sure you want to delete this user?" }, class: "text-red-600 hover:text-red-900" %> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index f1fd876..2c50951 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -46,7 +46,7 @@ <% else %> -
+
<%= render "shared/flash" %> <%= yield %>
diff --git a/config/routes.rb b/config/routes.rb index d9cd205..8decd97 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,7 @@ Rails.application.routes.draw do resource :session resources :passwords, param: :token + resources :invitations, param: :token, only: [:show, :update] mount ActionCable.server => "/cable" # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html @@ -56,7 +57,11 @@ Rails.application.routes.draw do # Admin routes namespace :admin do root "dashboard#index" - resources :users + resources :users do + member do + post :resend_invitation + end + end resources :applications do member do post :regenerate_credentials