Skip to content

Commit 16d9cd9

Browse files
committed
Add GuestAccess subtype of PlatformInvitation
Allows for time-bound short-term access to platform without ability to register account
1 parent 786d77e commit 16d9cd9

File tree

22 files changed

+282
-89
lines changed

22 files changed

+282
-89
lines changed

app/controllers/better_together/application_controller.rb

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class ApplicationController < ActionController::Base # rubocop:todo Metrics/Clas
2626
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
2727
rescue_from StandardError, with: :handle_error
2828

29-
helper_method :default_url_options, :valid_platform_invitation_token_present?
29+
helper_method :current_invitation, :default_url_options, :valid_platform_invitation_token_present?
3030

3131
def self.default_url_options
3232
super.merge(locale: I18n.locale)
@@ -72,29 +72,33 @@ def set_platform_invitation # rubocop:todo Metrics/CyclomaticComplexity, Metrics
7272
return
7373
end
7474

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
75+
token = if params[:invitation_code].present?
76+
# On first visit with the invitation code, update the session with the token and a new expiry.
77+
session[:platform_invitation_token] = params[:invitation_code]
78+
else
79+
# If no params, simply use the token stored in the session.
80+
session[:platform_invitation_token]
81+
end
8482

8583
return unless token.present?
8684

8785
@platform_invitation = ::BetterTogether::PlatformInvitation.pending.find_by(token: token)
8886

89-
return if @platform_invitation
90-
91-
session.delete(:platform_invitation_token)
92-
session.delete(:platform_invitation_expires_at)
87+
if @platform_invitation
88+
session[:platform_invitation_expires_at] ||= Time.current + @platform_invitation.session_duration_mins.minutes
89+
else
90+
session.delete(:platform_invitation_token)
91+
session.delete(:platform_invitation_expires_at)
92+
end
9393
end
9494
# rubocop:enable Metrics/AbcSize
9595
# rubocop:enable Metrics/MethodLength
9696
# rubocop:enable Metrics/PerceivedComplexity
9797

98+
def current_invitation
99+
@platform_invitation
100+
end
101+
98102
def check_platform_privacy
99103
return if helpers.host_platform.privacy_public?
100104
return if current_user

app/controllers/better_together/platform_invitations_controller.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,10 @@ def set_platform_invitation
113113
end
114114

115115
def platform_invitation_params
116-
params.require(:platform_invitation).permit(:invitee_email, :platform_role_id, :community_role_id, :locale)
116+
params.require(:platform_invitation).permit(
117+
:invitee_email, :platform_role_id, :community_role_id, :locale,
118+
:valid_from, :valid_until, :greeting, :type, :session_duration_mins
119+
)
117120
end
118121
end
119122
end

app/controllers/better_together/platforms_controller.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ class PlatformsController < FriendlyResourceController # rubocop:todo Style/Docu
66
before_action :authorize_platform, only: %i[show edit update destroy]
77
after_action :verify_authorized, except: :index
88

9+
before_action only: %i[show], if: -> { Rails.env.development? } do
10+
# Make sure that all Platform Invitation subclasses are loaded in dev to generate new block buttons
11+
::BetterTogether::PlatformInvitation.load_all_subclasses
12+
end
13+
914
# GET /platforms
1015
def index
1116
# @platforms = ::BetterTogether::Platform.all

app/helpers/better_together/form_helper.rb

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,26 +99,39 @@ def required_label(form_or_object, field, **options) # rubocop:todo Metrics/AbcS
9999
# rubocop:enable Metrics/MethodLength
100100

101101
# rubocop:todo Metrics/MethodLength
102-
def type_select_field(form:, model_class:, selected_type: nil, include_blank: true, **options)
102+
# rubocop:todo Metrics/PerceivedComplexity
103+
# rubocop:todo Metrics/AbcSize
104+
# rubocop:todo Metrics/ParameterLists
105+
def type_select_field(form:, model_class:, selected_type: nil, include_model_class: false, include_blank: true,
106+
**options)
107+
# rubocop:enable Metrics/ParameterLists
103108
# Determine if the model is persisted
104109
disabled = form&.object&.persisted? || false
105110

106111
options = {
107-
**options,
108112
required: true,
109113
class: 'form-select',
110-
disabled: # Disable if the model is persisted
114+
disabled:, # Disable if the model is persisted
115+
**options
111116
}
112117

113118
descendants = model_class.descendants.map { |descendant| [descendant.model_name.human, descendant.name] }
114119

120+
dropdown_values = if include_model_class
121+
[[model_class.model_name.human, model_class.name]] + descendants
122+
else
123+
descendants
124+
end
125+
115126
if form
116-
form.select :type, options_for_select(descendants, form.object.type), { include_blank: }, options
127+
form.select :type, options_for_select(dropdown_values, form.object.type), { include_blank: }, options
117128
else
118-
select_tag 'type', options_for_select(descendants, selected_type),
129+
select_tag 'type', options_for_select(dropdown_values, selected_type),
119130
{ include_blank: }.merge(options)
120131
end
121132
end
133+
# rubocop:enable Metrics/AbcSize
134+
# rubocop:enable Metrics/PerceivedComplexity
122135
# rubocop:enable Metrics/MethodLength
123136
end
124137
end

app/mailers/better_together/platform_invitation_mailer.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,21 @@
55
module BetterTogether
66
# Sends the email to the recipient to accept or decline their invitation to the platform
77
class PlatformInvitationMailer < ApplicationMailer
8-
def invite(platform_invitation)
8+
def invite(platform_invitation) # rubocop:todo Metrics/MethodLength
99
@platform_invitation = platform_invitation
1010
@platform = platform_invitation.invitable
1111

1212
# Override time zone and locale if necessary
1313
self.locale = platform_invitation.locale
1414

1515
@invitee_email = @platform_invitation.invitee_email
16+
return if @invitee_email.blank?
17+
18+
@greeting = @platform_invitation.greeting
1619
@valid_from = @platform_invitation.valid_from
1720
@valid_until = @platform_invitation.valid_until
1821

19-
@invitation_url = better_together.new_user_registration_url(invitation_code: @platform_invitation.token)
22+
@invitation_url = @platform_invitation.url
2023

2124
mail(to: @invitee_email,
2225
subject: I18n.t('better_together.platform_invitation_mailer.invite.subject',
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# frozen_string_literal: true
2+
3+
module BetterTogether
4+
# Allows for platform managers to allow guest access to the platform
5+
class GuestAccess < PlatformInvitation
6+
def self.model_name
7+
ActiveModel::Name.new(self)
8+
end
9+
10+
def registers_user?
11+
false
12+
end
13+
14+
def url
15+
BetterTogether::Engine.routes.url_helpers.home_page_url(invitation_code: token, locale:)
16+
end
17+
end
18+
end

app/models/better_together/platform_invitation.rb

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ class PlatformInvitation < ApplicationRecord
3030

3131
enum status: STATUS_VALUES, _prefix: :status
3232

33-
validates :invitee_email, presence: true, uniqueness: { scope: :invitable_id }
33+
has_rich_text :greeting, encrypted: true
34+
35+
validates :invitee_email, uniqueness: { scope: :invitable_id, allow_nil: true }
36+
validates :invitee_email, uniqueness: { scope: :invitable_id, allow_nil: true, allow_blank: true }
3437
validates :locale, presence: true, inclusion: { in: I18n.available_locales.map(&:to_s) }
3538
validates :status, presence: true, inclusion: { in: STATUS_VALUES.values }
3639
validates :token, uniqueness: true
@@ -48,6 +51,10 @@ class PlatformInvitation < ApplicationRecord
4851

4952
# TODO: add 'not expired' scope to find only invitations that are available
5053

54+
def self.load_all_subclasses
55+
[self, GuestAccess].each(&:connection) # Add all known subclasses here
56+
end
57+
5158
def accept!(invitee:, save_record: true)
5259
self.invitee = invitee
5360
self.status = STATUS_VALUES[:accepted]
@@ -58,6 +65,23 @@ def expired?
5865
valid_until.present? && valid_until < Time.current
5966
end
6067

68+
def invitee_email=(email)
69+
new_value = email&.strip&.downcase
70+
super(new_value.present? ? new_value : nil)
71+
end
72+
73+
def registers_user?
74+
true
75+
end
76+
77+
def url
78+
BetterTogether::Engine.routes.url_helpers.new_user_registration_url(invitation_code: token)
79+
end
80+
81+
def to_s
82+
"[#{self.class.model_name.human}] - #{id}"
83+
end
84+
6185
private
6286

6387
def set_accepted_timestamp
@@ -71,7 +95,7 @@ def queue_invitation_email
7195
end
7296

7397
def should_send_email?
74-
!email_recently_sent? && !throttled?
98+
invitee_email.present? && !email_recently_sent? && !throttled?
7599
end
76100

77101
def email_recently_sent?
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# frozen_string_literal: true
2+
3+
module BetterTogether
4+
class GuestAccessPolicy < PlatformInvitationPolicy
5+
class Scope < PlatformInvitationPolicy::Scope # rubocop:todo Style/Documentation
6+
def resolve
7+
scope.all
8+
end
9+
end
10+
end
11+
end

app/policies/better_together/platform_invitation_policy.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
module BetterTogether
44
class PlatformInvitationPolicy < ApplicationPolicy # rubocop:todo Style/Documentation
55
def create?
6-
user.present?
6+
user.present? && permitted_to?('manage_platform')
77
end
88

99
def destroy?
10-
user.present? && record.status_pending?
10+
user.present? && record.status_pending? && permitted_to?('manage_platform')
1111
end
1212

1313
def resend?
14-
user.present? && record.status_pending?
14+
user.present? && record.status_pending? && permitted_to?('manage_platform')
1515
end
1616

1717
class Scope < Scope # rubocop:todo Style/Documentation

app/views/better_together/platform_invitation_mailer/invite.html.erb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
<p><%= t('.message', platform: @platform.name) %></p>
66

7+
<% if @greeting.present? %>
8+
<%= @greeting %>
9+
<% end %>
10+
711
<p><%= link_to t('.link_text'), @invitation_url %></p>
812

913
<p><%= t('.invitation_code', invitation_code: @platform_invitation.token) %></p>

0 commit comments

Comments
 (0)