[deploy] Allow initial user to sign up and configure app (#10073)
* Allow initial user to sign up and configure app * Fix added value unneeded * Make siteconfig public in tests * Remove deprecated method and adjust seed default * Add new controllers not to redirect for public * Modify tests * Edit test defaults * Fix linting * Add starter mode to seed file
This commit is contained in:
parent
25e20bdc1c
commit
dba151915b
11 changed files with 160 additions and 64 deletions
|
|
@ -17,11 +17,12 @@ class ApplicationController < ActionController::Base
|
|||
error_too_many_requests(exc)
|
||||
end
|
||||
|
||||
PUBLIC_CONTROLLERS = %w[shell async_info ga_events].freeze
|
||||
PUBLIC_CONTROLLERS = %w[shell async_info ga_events service_worker omniauth_callbacks registrations].freeze
|
||||
private_constant :PUBLIC_CONTROLLERS
|
||||
|
||||
def verify_private_forem
|
||||
return if controller_name.in?(PUBLIC_CONTROLLERS)
|
||||
return if self.class.module_parent.to_s == "Admin"
|
||||
return if user_signed_in? || SiteConfig.public
|
||||
|
||||
if api_action?
|
||||
|
|
|
|||
|
|
@ -34,9 +34,9 @@ module VerifySetupCompleted
|
|||
private
|
||||
|
||||
def verify_setup_completed
|
||||
return if config_path? || setup_completed?
|
||||
return if config_path? || setup_completed? || SiteConfig.waiting_on_first_user
|
||||
|
||||
link = helpers.link_to("the configuration page", admin_config_path)
|
||||
link = helpers.link_to("the configuration page", admin_config_path, "data-no-instant" => true)
|
||||
# rubocop:disable Rails/OutputSafety
|
||||
flash[:global_notice] = "Setup not completed yet, please visit #{link}.".html_safe
|
||||
# rubocop:enable Rails/OutputSafety
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ class RegistrationsController < Devise::RegistrationsController
|
|||
end
|
||||
|
||||
def create
|
||||
not_authorized unless SiteConfig.allow_email_password_registration
|
||||
not_authorized unless SiteConfig.allow_email_password_registration || SiteConfig.waiting_on_first_user
|
||||
|
||||
build_resource(sign_up_params)
|
||||
resource.saw_onboarding = false
|
||||
|
|
@ -18,9 +18,20 @@ class RegistrationsController < Devise::RegistrationsController
|
|||
resource.save if resource.email.present?
|
||||
yield resource if block_given?
|
||||
if resource.persisted?
|
||||
update_first_user_permissions(resource)
|
||||
redirect_to "/confirm-email?email=#{resource.email}"
|
||||
else
|
||||
render action: "by_email"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def update_first_user_permissions(resource)
|
||||
return unless SiteConfig.waiting_on_first_user
|
||||
|
||||
resource.add_role(:super_admin)
|
||||
resource.add_role(:single_resource_admin, Config)
|
||||
SiteConfig.waiting_on_first_user = false
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ class SiteConfig < RailsSettings::Base
|
|||
STACK_ICON = File.read(Rails.root.join("app/assets/images/stack.svg")).freeze
|
||||
LIGHTNING_ICON = File.read(Rails.root.join("app/assets/images/lightning.svg")).freeze
|
||||
|
||||
field :waiting_on_first_user, type: :boolean, default: !User.exists?
|
||||
|
||||
# API Tokens
|
||||
field :health_check_token, type: :string
|
||||
|
||||
|
|
@ -148,7 +150,7 @@ class SiteConfig < RailsSettings::Base
|
|||
field :feed_style, type: :string, default: "basic"
|
||||
# a non-public forem will redirect all unauthenticated pages to the registration page.
|
||||
# a public forem could have more fine-grained authentication (listings ar private etc.) in future
|
||||
field :public, type: :boolean, default: 1
|
||||
field :public, type: :boolean, default: 0
|
||||
# The default font for all users that have not chosen a custom font yet
|
||||
field :default_font, type: :string, default: "sans_serif"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
<% if params[:state] == "beta_email_signup" %>
|
||||
<% if params[:state] == "beta_email_signup" && SiteConfig.allow_email_password_registration %>
|
||||
<%= render "shared/authentication/email_registration_form" %>
|
||||
<% elsif params[:state] == "beta_email_signup" %>
|
||||
<div class="crayons-notice crayons-notice--danger mb-10 mt-8 mx-auto" style="width: 680px;max-width:94%;">
|
||||
Email authentication is not enabled for this Forem.
|
||||
</div>
|
||||
<% elsif SiteConfig.waiting_on_first_user %>
|
||||
<%= render "shared/authentication/initial_account_wizard" %>
|
||||
<% else %>
|
||||
<%= render "devise/shared/authorization_error" %>
|
||||
<%= render "devise/registrations/registration_form" %>
|
||||
|
|
|
|||
|
|
@ -1,61 +1,55 @@
|
|||
<% if SiteConfig.allow_email_password_registration %>
|
||||
<div id="sign-in-password-form" class="mt-8 mb-6 crayons-card p-7 align-left mx-auto" style="max-width:580px;">
|
||||
<%= form_for(User.new, as: :user, url: registration_path(:user)) do |f| %>
|
||||
<% if resource.errors.any? %>
|
||||
<div class="crayons-card crayons-card--secondary crayons-notice crayons-notice--danger">
|
||||
<div class="crayons-card__header">
|
||||
<h3 class="crayons-card__headline">
|
||||
Whoops, we found <%= pluralize(resource.errors.size, "problem") %>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="crayons-card__body">
|
||||
<ul>
|
||||
<% resource.errors.full_messages.each do |message| %>
|
||||
<li><%= message %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="sign-in-password-form" class="mt-8 mb-6 crayons-card p-7 align-left mx-auto" style="max-width:580px;">
|
||||
<%= form_for(User.new, as: :user, url: registration_path(:user)) do |f| %>
|
||||
<% if defined?(resource) && resource&.errors&.any? %>
|
||||
<div class="crayons-card crayons-card--secondary crayons-notice crayons-notice--danger">
|
||||
<div class="crayons-card__header">
|
||||
<h3 class="crayons-card__headline">
|
||||
Whoops, we found <%= pluralize(resource.errors.size, "problem") %>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="crayons-card__body">
|
||||
<ul>
|
||||
<% resource.errors.full_messages.each do |message| %>
|
||||
<li><%= message %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% else %>
|
||||
<p class="pb-4 fw-bold">Create account from email... (beta)</p>
|
||||
<% end %>
|
||||
<div class="crayons-field mt-3">
|
||||
<%= f.label :profile_image, class: "crayons-field__label" %>
|
||||
<%= f.file_field :profile_image, accept: "image/*", class: "crayons-card crayons-card--secondary p-3 flex items-center flex-1 w-100" %>
|
||||
</div>
|
||||
|
||||
<div class="crayons-field mt-2">
|
||||
<%= f.label :name, class: "crayons-field__label" %>
|
||||
<%= f.text_field :name, class: "crayons-textfield" %>
|
||||
</div>
|
||||
|
||||
<div class="crayons-field mt-2">
|
||||
<%= f.label :username, class: "crayons-field__label" %>
|
||||
<%= f.text_field :username, class: "crayons-textfield" %>
|
||||
</div>
|
||||
|
||||
<div class="crayons-field mt-2">
|
||||
<%= f.label :email, class: "crayons-field__label" %>
|
||||
<%= f.email_field :email, autocomplete: "email", class: "crayons-textfield" %>
|
||||
</div>
|
||||
|
||||
<div class="crayons-field mt-2">
|
||||
<%= f.label :password, class: "crayons-field__label" %>
|
||||
<%= f.password_field :password, autocomplete: "current-password", class: "crayons-textfield" %>
|
||||
</div>
|
||||
|
||||
<div class="crayons-field mt-2">
|
||||
<%= f.label :password_confirmation, class: "crayons-field__label" %>
|
||||
<%= f.password_field :password_confirmation, autocomplete: "current-password", class: "crayons-textfield" %>
|
||||
</div>
|
||||
|
||||
<div class="actions pt-3">
|
||||
<%= f.submit "Sign up", class: "crayons-btn" %>
|
||||
</div>
|
||||
<% else %>
|
||||
<p class="pb-4 fw-bold">Create your account</p>
|
||||
<% end %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="crayons-notice crayons-notice--danger mb-10 mt-8 mx-auto" style="width: 680px;max-width:94%;">
|
||||
Email authentication is not enabled for this Forem.
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="crayons-field mt-3">
|
||||
<%= f.label :profile_image, class: "crayons-field__label" %>
|
||||
<%= f.file_field :profile_image, accept: "image/*", class: "crayons-card crayons-card--secondary p-3 flex items-center flex-1 w-100", required: true %>
|
||||
</div>
|
||||
|
||||
<div class="crayons-field mt-2">
|
||||
<%= f.label :name, class: "crayons-field__label" %>
|
||||
<%= f.text_field :name, class: "crayons-textfield", required: true %>
|
||||
</div>
|
||||
|
||||
<div class="crayons-field mt-2">
|
||||
<%= f.label :username, class: "crayons-field__label" %>
|
||||
<%= f.text_field :username, class: "crayons-textfield", required: true %>
|
||||
</div>
|
||||
|
||||
<div class="crayons-field mt-2">
|
||||
<%= f.label :email, class: "crayons-field__label" %>
|
||||
<%= f.email_field :email, autocomplete: "email", class: "crayons-textfield", required: true %>
|
||||
</div>
|
||||
|
||||
<div class="crayons-field mt-2">
|
||||
<%= f.label :password, class: "crayons-field__label" %>
|
||||
<%= f.password_field :password, autocomplete: "current-password", class: "crayons-textfield", required: true %>
|
||||
</div>
|
||||
|
||||
<div class="crayons-field mt-2">
|
||||
<%= f.label :password_confirmation, class: "crayons-field__label" %>
|
||||
<%= f.password_field :password_confirmation, autocomplete: "current-password", class: "crayons-textfield", required: true %>
|
||||
</div>
|
||||
|
||||
<div class="actions pt-3">
|
||||
<%= f.submit "Sign up", class: "crayons-btn" %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
<% title "Let's get started with Forem" %>
|
||||
<div class="crayons-card crayons-card--secondary crayons-notice crayons-notice--success mx-auto mt-8 mb-10 p-4 fs-2xl lh-base align-center" style="width:96%;max-width:1300px;">
|
||||
<h1 class="m-7 mb-3">Let's start your Forem journey</h1>
|
||||
<img class="m-7 mb-2 radius-default" src="https://media.giphy.com/media/F9hQLAVhWnL56/giphy.gif" style="height:220px" />
|
||||
<p class="mb-4 mt-6">
|
||||
Create an account. It will be the first super admin account.
|
||||
</p>
|
||||
<p class="mb-4">
|
||||
Once you sign up below, you can configure your community at <a href="/admin/config">admin/config</a>.
|
||||
</p>
|
||||
<p class="mb-4">
|
||||
There is lots you can do as an admin, but there is a learning curve.
|
||||
</p>
|
||||
<p class="mb-8">
|
||||
Please reach out to the Forem team if you are unsure about anything!
|
||||
</p>
|
||||
<p class="mb-7 fw-bold">
|
||||
For Empowering Community 🌱
|
||||
</p>
|
||||
<%= render "shared/authentication/email_registration_form" %>
|
||||
</div>
|
||||
15
db/seeds.rb
15
db/seeds.rb
|
|
@ -30,6 +30,21 @@ SEEDS_MULTIPLIER = [1, ENV["SEEDS_MULTIPLIER"].to_i].max
|
|||
puts "Seeding with multiplication factor: #{SEEDS_MULTIPLIER}\n\n"
|
||||
|
||||
##############################################################################
|
||||
# Default development site config if different from production scenario
|
||||
|
||||
SiteConfig.public = true
|
||||
SiteConfig.waiting_on_first_user = false
|
||||
|
||||
##############################################################################
|
||||
|
||||
# Put forem into "starter mode"
|
||||
|
||||
if ENV["MODE"] == "STARTER"
|
||||
SiteConfig.public = false
|
||||
SiteConfig.waiting_on_first_user = true
|
||||
puts "Seeding forem in starter mode to replicate new creator experience"
|
||||
exit # We don't need any models if we're launching things from startup.
|
||||
end
|
||||
|
||||
seeder.create_if_none(Organization) do
|
||||
3.times do
|
||||
|
|
|
|||
|
|
@ -45,3 +45,11 @@ will result in creating double the default amount of items in the database.
|
|||
It's currently used only for `articles` and `users`.
|
||||
|
||||
It can also be used for `rails db:seed` and `rails db:reset`.
|
||||
|
||||
### Other seed modes
|
||||
|
||||
To put your local forem into "starter mode", as it would be for a new creator, use `MODE=STARTER` i.e...
|
||||
|
||||
```shell
|
||||
MODE=STARTER rails db:setup
|
||||
```
|
||||
|
|
@ -167,6 +167,8 @@ RSpec.configure do |config|
|
|||
}).to_return(status: 200, body: "", headers: {})
|
||||
|
||||
allow(SiteConfig).to receive(:community_description).and_return("Some description")
|
||||
SiteConfig.public = true
|
||||
SiteConfig.waiting_on_first_user = false
|
||||
end
|
||||
|
||||
config.after do
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ RSpec.describe "Registrations", type: :request do
|
|||
before do
|
||||
SiteConfig.allow_email_password_registration = false
|
||||
end
|
||||
|
||||
it "disallows communities where email registration is not allowed" do
|
||||
expect { post "/users" }.to raise_error Pundit::NotAuthorizedError
|
||||
end
|
||||
|
|
@ -87,5 +88,40 @@ RSpec.describe "Registrations", type: :request do
|
|||
expect(User.all.size).to be 0
|
||||
end
|
||||
end
|
||||
|
||||
context "when site is in waiting_on_first_user state" do
|
||||
before do
|
||||
SiteConfig.waiting_on_first_user = true
|
||||
end
|
||||
|
||||
after do
|
||||
SiteConfig.waiting_on_first_user = false
|
||||
end
|
||||
|
||||
it "does not raise disallowed if community is set to allow email" do
|
||||
expect { post "/users" }.not_to raise_error Pundit::NotAuthorizedError
|
||||
end
|
||||
|
||||
it "creates user with valid params passed" do
|
||||
post "/users", params:
|
||||
{ user: { name: "test #{rand(10)}",
|
||||
username: "haha_#{rand(10)}",
|
||||
email: "yoooo#{rand(100)}@yo.co",
|
||||
password: "PaSSw0rd_yo000",
|
||||
password_confirmation: "PaSSw0rd_yo000" } }
|
||||
expect(User.all.size).to be 1
|
||||
end
|
||||
|
||||
it "makes user super admin and config admin" do
|
||||
post "/users", params:
|
||||
{ user: { name: "test #{rand(10)}",
|
||||
username: "haha_#{rand(10)}",
|
||||
email: "yoooo#{rand(100)}@yo.co",
|
||||
password: "PaSSw0rd_yo000",
|
||||
password_confirmation: "PaSSw0rd_yo000" } }
|
||||
expect(User.first.has_role?(:super_admin)).to be true
|
||||
expect(User.first.has_role?(:single_resource_admin, Config)).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue