Skip to content

Commit 277927b

Browse files
authored
Merge branch 'main' into feature/platform-multi-tenancy
2 parents c0466d7 + d50870a commit 277927b

File tree

6 files changed

+121
-11
lines changed

6 files changed

+121
-11
lines changed

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ GEM
610610
rswag-ui (2.16.0)
611611
actionpack (>= 5.2, < 8.1)
612612
railties (>= 5.2, < 8.1)
613-
rubocop (1.73.0)
613+
rubocop (1.73.2)
614614
json (~> 2.3)
615615
language_server-protocol (~> 3.17.0.2)
616616
lint_roller (~> 1.1.0)

app/controllers/better_together/application_controller.rb

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ class ApplicationController < ActionController::Base # rubocop:todo Metrics/Clas
1010
before_action :check_platform_setup
1111
before_action :set_locale
1212
before_action :store_user_location!, if: :storable_location?
13+
14+
before_action :set_platform_invitation
1315
before_action :check_platform_privacy
1416
# The callback which stores the current location must be added before you authenticate the user
1517
# as `authenticate_user!` (or whatever your resource is) will halt the filter chain and redirect
@@ -24,7 +26,7 @@ class ApplicationController < ActionController::Base # rubocop:todo Metrics/Clas
2426
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
2527
rescue_from StandardError, with: :handle_error
2628

27-
helper_method :default_url_options
29+
helper_method :default_url_options, :valid_platform_invitation_token_present?
2830

2931
def self.default_url_options
3032
super.merge(locale: I18n.locale)
@@ -56,15 +58,66 @@ def check_platform_setup
5658
redirect_to setup_wizard_path
5759
end
5860

61+
# rubocop:todo Metrics/PerceivedComplexity
62+
# rubocop:todo Metrics/MethodLength
63+
# rubocop:todo Metrics/AbcSize
64+
def set_platform_invitation # rubocop:todo Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
65+
# Only proceed if there's an invitation token in the URL or already in the session.
66+
return unless params[:invitation_code].present? || session[:platform_invitation_token].present?
67+
68+
# Check if the session token has expired.
69+
if session[:platform_invitation_expires_at].present? && Time.current > session[:platform_invitation_expires_at]
70+
session.delete(:platform_invitation_token)
71+
session.delete(:platform_invitation_expires_at)
72+
return
73+
end
74+
75+
if params[:invitation_code].present?
76+
# On first visit with the invitation code, update the session with the token and a new expiry.
77+
token = params[:invitation_code]
78+
session[:platform_invitation_token] = token
79+
session[:platform_invitation_expires_at] ||= Time.current + platform_invitation_expiry_time
80+
else
81+
# If no params, simply use the token stored in the session.
82+
token = session[:platform_invitation_token]
83+
end
84+
85+
return unless token.present?
86+
87+
@platform_invitation = ::BetterTogether::PlatformInvitation.pending.find_by(token: token)
88+
89+
return if @platform_invitation
90+
91+
session.delete(:platform_invitation_token)
92+
session.delete(:platform_invitation_expires_at)
93+
end
94+
# rubocop:enable Metrics/AbcSize
95+
# rubocop:enable Metrics/MethodLength
96+
# rubocop:enable Metrics/PerceivedComplexity
97+
5998
def check_platform_privacy
6099
return if helpers.host_platform.privacy_public?
61100
return if current_user
62101
return unless BetterTogether.user_class.any?
102+
return if valid_platform_invitation_token_present?
63103

64104
flash[:error] = I18n.t('globals.platform_not_public')
65105
redirect_to new_user_session_path(locale: I18n.locale)
66106
end
67107

108+
def valid_platform_invitation_token_present?
109+
token = session[:platform_invitation_token]
110+
return false unless token.present?
111+
112+
if session[:platform_invitation_expires_at].present? && Time.current > session[:platform_invitation_expires_at]
113+
return false
114+
end
115+
116+
::BetterTogether::PlatformInvitation.pending.exists?(token: token)
117+
end
118+
119+
private
120+
68121
def handle404
69122
render_404
70123
end
@@ -171,8 +224,18 @@ def after_sign_in_path_for(resource)
171224
end
172225
end
173226

227+
def after_inactive_sign_up_path_for(resource)
228+
new_user_session_path if helpers.host_platform&.private?
229+
super
230+
end
231+
174232
def after_sign_out_path_for(_resource_or_scope)
175233
BetterTogether.base_path_with_locale
176234
end
235+
236+
# Configurable expiration time (e.g., 30 minutes)
237+
def platform_invitation_expiry_time
238+
30.minutes
239+
end
177240
end
178241
end

app/controllers/better_together/users/registrations_controller.rb

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ class RegistrationsController < ::Devise::RegistrationsController
77
include DeviseLocales
88
skip_before_action :check_platform_privacy
99

10-
before_action :set_platform_invitation, only: %i[new create]
11-
1210
def new
1311
super do |user|
1412
user.email = @platform_invitation.invitee_email if @platform_invitation && user.email.empty?
@@ -51,12 +49,6 @@ def create # rubocop:todo Metrics/MethodLength, Metrics/AbcSize
5149

5250
protected
5351

54-
def set_platform_invitation
55-
return unless params[:invitation_code].present?
56-
57-
@platform_invitation = ::BetterTogether::PlatformInvitation.pending.find_by(token: params[:invitation_code])
58-
end
59-
6052
def person_params
6153
params.require(:user).require(:person_attributes).permit(%i[identifier name description])
6254
end

app/helpers/better_together/platforms_helper.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,8 @@
22

33
module BetterTogether
44
module PlatformsHelper # rubocop:todo Style/Documentation
5+
def invitation_token_expires_at
6+
session[:platform_invitation_expires_at].to_datetime.to_i
7+
end
58
end
69
end
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// app/javascript/controllers/invitation_timer_controller.js
2+
3+
import { Controller } from '@hotwired/stimulus'
4+
5+
export default class extends Controller {
6+
static values = {
7+
expiresAt: Number // Timestamp in seconds (epoch time)
8+
}
9+
10+
connect() {
11+
this.updateTimer()
12+
this.interval = setInterval(() => this.updateTimer(), 1000)
13+
}
14+
15+
disconnect() {
16+
clearInterval(this.interval)
17+
}
18+
19+
updateTimer() {
20+
const now = Math.floor(Date.now() / 1000)
21+
const remainingSeconds = this.expiresAtValue - now
22+
console.log("Timer:", { expiresAt: this.expiresAtValue, now, remainingSeconds })
23+
24+
if (remainingSeconds <= 0) {
25+
this.element.textContent = 'Expired'
26+
this.element.classList.remove('bg-info')
27+
this.element.classList.add('bg-danger')
28+
clearInterval(this.interval)
29+
return
30+
}
31+
32+
const minutes = Math.floor(remainingSeconds / 60)
33+
this.element.textContent = `${minutes} min`
34+
}
35+
}

app/views/layouts/better_together/_header.html.erb

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,24 @@
5858
<% else %>
5959
<!-- If user is not signed in, show 'Sign In' -->
6060
<li class="nav-item">
61-
<%= link_to t('navbar.sign_in'), new_user_session_path, class: "nav-link" %>
61+
<% if valid_platform_invitation_token_present? %>
62+
<%= link_to new_user_registration_path(invitation_code: session[:platform_invitation_token]), class: "nav-link d-flex align-items-center gap-2" do %>
63+
<i class="fas fa-envelope-open-text"></i>
64+
<%= t('navbar.accept_invitation') %>
65+
<% expires_at_unix = invitation_token_expires_at %>
66+
67+
<span class="badge bg-info ms-2"
68+
data-controller="better_together--invitation-timer"
69+
data-better_together--invitation-timer-expires-at-value="<%= expires_at_unix %>">
70+
<%= t('invitations.calculating') %>
71+
</span>
72+
<% end %>
73+
<% else %>
74+
<%= link_to new_user_session_path, class: "nav-link d-flex align-items-center gap-2" do %>
75+
<i class="fas fa-sign-in-alt"></i>
76+
<%= t('navbar.sign_in') %>
77+
<% end %>
78+
<% end %>
6279
</li>
6380
<% end %>
6481
</ul>

0 commit comments

Comments
 (0)