Skip to content

Commit 72e7d77

Browse files
authored
Add onboarding state selector for self-hosted signup (#251)
* Add onboarding modes to self-hosted signup * Style form consistently * Configure ONBOARDING_STATE via ENV
1 parent dcb6748 commit 72e7d77

File tree

16 files changed

+121
-23
lines changed

16 files changed

+121
-23
lines changed

.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
# Enables self hosting features (should be set to true unless you know what you're doing)
1111
SELF_HOSTED=true
1212

13+
# Controls onboarding flow (valid: open, closed, invite_only)
14+
ONBOARDING_STATE=open
15+
1316
# Secret key used to encrypt credentials (https://api.rubyonrails.org/v7.1.3.2/classes/Rails/Application.html#method-i-secret_key_base)
1417
# Has to be a random string, generated eg. by running `openssl rand -hex 64`
1518
SECRET_KEY_BASE=secret-value

.env.local.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# To enable / disable self-hosting features.
22
SELF_HOSTED = true
33

4+
# Controls onboarding flow (valid: open, closed, invite_only)
5+
ONBOARDING_STATE = open
6+
47
# Enable Twelve market data (careful, this will use your API credits)
58
TWELVE_DATA_API_KEY =
69

.env.test.example

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
SELF_HOSTED=false
22

3+
# Controls onboarding flow (valid: open, closed, invite_only)
4+
ONBOARDING_STATE=open
5+
36
# OpenID Connect for tests
47
OIDC_ISSUER=
58
OIDC_CLIENT_ID=
@@ -21,4 +24,4 @@ OIDC_REDIRECT_URI=http://localhost:3000/auth/openid_connect/callback
2124
COVERAGE=false
2225

2326
# Set to true to run test suite serially
24-
DISABLE_PARALLELIZATION=false
27+
DISABLE_PARALLELIZATION=false

app/controllers/concerns/invitable.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ module Invitable
88
private
99
def invite_code_required?
1010
return false if @invitation.present?
11-
self_hosted? ? Setting.require_invite_for_signup : ENV["REQUIRE_INVITE_CODE"] == "true"
11+
if self_hosted?
12+
Setting.onboarding_state == "invite_only"
13+
else
14+
ENV["REQUIRE_INVITE_CODE"] == "true"
15+
end
1216
end
1317

1418
def self_hosted?

app/controllers/registrations_controller.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ class RegistrationsController < ApplicationController
33

44
layout "auth"
55

6+
before_action :ensure_signup_open, if: :self_hosted?
67
before_action :set_user, only: :create
78
before_action :set_invitation
89
before_action :claim_invite_code, only: :create, if: :invite_code_required?
@@ -79,4 +80,10 @@ def validate_password_requirements
7980
render :new, status: :unprocessable_entity
8081
end
8182
end
83+
84+
def ensure_signup_open
85+
return unless Setting.onboarding_state == "closed"
86+
87+
redirect_to new_session_path, alert: t("registrations.closed")
88+
end
8289
end

app/controllers/settings/hostings_controller.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ def show
1515
end
1616

1717
def update
18-
if hosting_params.key?(:require_invite_for_signup)
19-
Setting.require_invite_for_signup = hosting_params[:require_invite_for_signup]
18+
if hosting_params.key?(:onboarding_state)
19+
onboarding_state = hosting_params[:onboarding_state].to_s
20+
Setting.onboarding_state = onboarding_state
2021
end
2122

2223
if hosting_params.key?(:require_email_confirmation)
@@ -68,7 +69,7 @@ def clear_cache
6869

6970
private
7071
def hosting_params
71-
params.require(:setting).permit(:require_invite_for_signup, :require_email_confirmation, :brand_fetch_client_id, :twelve_data_api_key, :openai_access_token, :openai_uri_base, :openai_model)
72+
params.require(:setting).permit(:onboarding_state, :require_email_confirmation, :brand_fetch_client_id, :twelve_data_api_key, :openai_access_token, :openai_uri_base, :openai_model)
7273
end
7374

7475
def ensure_admin

app/models/setting.rb

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,40 @@ class ValidationError < StandardError; end
1010
field :openai_model, type: :string, default: ENV["OPENAI_MODEL"]
1111
field :brand_fetch_client_id, type: :string, default: ENV["BRAND_FETCH_CLIENT_ID"]
1212

13+
ONBOARDING_STATES = %w[open closed invite_only].freeze
14+
DEFAULT_ONBOARDING_STATE = begin
15+
env_value = ENV["ONBOARDING_STATE"].to_s.presence || "open"
16+
ONBOARDING_STATES.include?(env_value) ? env_value : "open"
17+
end
18+
19+
field :onboarding_state, type: :string, default: DEFAULT_ONBOARDING_STATE
1320
field :require_invite_for_signup, type: :boolean, default: false
1421
field :require_email_confirmation, type: :boolean, default: ENV.fetch("REQUIRE_EMAIL_CONFIRMATION", "true") == "true"
1522

23+
def self.validate_onboarding_state!(state)
24+
return if ONBOARDING_STATES.include?(state)
25+
26+
raise ValidationError, I18n.t("settings.hostings.update.invalid_onboarding_state")
27+
end
28+
29+
class << self
30+
alias_method :raw_onboarding_state, :onboarding_state
31+
alias_method :raw_onboarding_state=, :onboarding_state=
32+
33+
def onboarding_state
34+
value = raw_onboarding_state
35+
return "invite_only" if value.blank? && require_invite_for_signup
36+
37+
value.presence || DEFAULT_ONBOARDING_STATE
38+
end
39+
40+
def onboarding_state=(state)
41+
validate_onboarding_state!(state)
42+
self.require_invite_for_signup = state == "invite_only"
43+
self.raw_onboarding_state = state
44+
end
45+
end
46+
1647
# Validates OpenAI configuration requires model when custom URI base is set
1748
def self.validate_openai_config!(uri_base: nil, model: nil)
1849
# Use provided values or current settings

app/views/settings/hostings/_invite_code_settings.html.erb

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,19 @@
99
url: settings_hosting_path,
1010
method: :patch,
1111
data: { controller: "auto-submit-form", auto_submit_form_trigger_event_value: "change" } do |form| %>
12-
<%= form.toggle :require_invite_for_signup, { data: { auto_submit_form_target: "auto" } } %>
12+
<div class="form-field w-fit">
13+
<%= form.select :onboarding_state,
14+
options_for_select(
15+
[
16+
[ t(".states.open"), "open" ],
17+
[ t(".states.closed"), "closed" ],
18+
[ t(".states.invite_only"), "invite_only" ]
19+
],
20+
Setting.onboarding_state
21+
),
22+
{ label: false },
23+
{ data: { auto_submit_form_target: "auto" } } %>
24+
</div>
1325
<% end %>
1426
</div>
1527

@@ -27,7 +39,7 @@
2739
<% end %>
2840
</div>
2941

30-
<% if Setting.require_invite_for_signup %>
42+
<% if Setting.onboarding_state == "invite_only" %>
3143
<div class="flex items-center justify-between mb-4">
3244
<div>
3345
<span class="text-primary text-base font-medium"><%= t(".generated_tokens") %></span>

config/locales/views/registrations/en.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ en:
88
user:
99
create: Continue
1010
registrations:
11+
closed: Signups are currently closed.
1112
create:
1213
failure: There was a problem signing up.
1314
invalid_invite_code: Invalid invite code, please try again.

config/locales/views/registrations/nb.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ nb:
88
user:
99
create: Fortsett
1010
registrations:
11+
closed: Registrering er midlertidig stengt.
1112
create:
1213
failure: Det oppsto et problem med registreringen.
1314
invalid_invite_code: Ugyldig invitasjonskode, vennligst prøv igjen.
@@ -22,4 +23,4 @@ nb:
2223
welcome_body: For å komme i gang må du registrere deg for en ny konto. Du vil
2324
da kunne konfigurere flere innstillinger i appen.
2425
welcome_title: Velkommen til Self Hosted %{product_name}!
25-
password_placeholder: Angi passordet ditt
26+
password_placeholder: Angi passordet ditt

0 commit comments

Comments
 (0)