diff --git a/.env.example b/.env.example
index eeb61f00f..7c5299bad 100644
--- a/.env.example
+++ b/.env.example
@@ -18,7 +18,7 @@ FORCE_SSL=false
# true : default option, allows sign ups
# false : disables all the end points related to sign ups
# api_only: disables the UI for signup, but you can create sign ups via the account apis
-ENABLE_ACCOUNT_SIGNUP=true
+ENABLE_ACCOUNT_SIGNUP=false
# Redis config
REDIS_URL=redis://redis:6379
diff --git a/app.json b/app.json
index b321e9b89..af1a496a4 100644
--- a/app.json
+++ b/app.json
@@ -11,7 +11,10 @@
"rails",
"vue"
],
- "success_url": "/app/login",
+ "success_url": "/",
+ "scripts": {
+ "postdeploy": "bundle exec rake db:seed"
+ },
"env": {
"SECRET_TOKEN": {
"description": "A secret key for verifying the integrity of signed cookies.",
diff --git a/app/builders/account_builder.rb b/app/builders/account_builder.rb
index 807f499e1..f7f94fada 100644
--- a/app/builders/account_builder.rb
+++ b/app/builders/account_builder.rb
@@ -2,7 +2,7 @@
class AccountBuilder
include CustomExceptions::Account
- pattr_initialize [:account_name!, :email!, :confirmed!, :user, :user_full_name]
+ pattr_initialize [:account_name!, :email!, :confirmed!, :user, :user_full_name, :user_password]
def perform
if @user.nil?
@@ -26,7 +26,7 @@ class AccountBuilder
if address.valid? # && !address.disposable?
true
else
- raise InvalidEmail.new(valid: address.valid?) # , disposable: address.disposable?})
+ raise InvalidEmail.new(valid: address.valid?)
end
end
@@ -61,7 +61,7 @@ class AccountBuilder
end
def create_user
- password = SecureRandom.alphanumeric(12)
+ password = user_password || SecureRandom.alphanumeric(12)
@user = User.new(email: @email,
password: password,
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index ddf8382f8..9ed9f7f47 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -3,6 +3,7 @@ class DashboardController < ActionController::Base
before_action :set_global_config
around_action :switch_locale
+ before_action :ensure_installation_onboarding, only: [:index]
layout 'vueapp'
@@ -24,4 +25,8 @@ class DashboardController < ActionController::Base
APP_VERSION: Chatwoot.config[:version]
)
end
+
+ def ensure_installation_onboarding
+ redirect_to '/installation/onboarding' if ::Redis::Alfred.get(::Redis::Alfred::CHATWOOT_INSTALLATION_ONBOARDING)
+ end
end
diff --git a/app/controllers/installation/onboarding_controller.rb b/app/controllers/installation/onboarding_controller.rb
new file mode 100644
index 000000000..a6f04238b
--- /dev/null
+++ b/app/controllers/installation/onboarding_controller.rb
@@ -0,0 +1,36 @@
+class Installation::OnboardingController < ApplicationController
+ before_action :ensure_installation_onboarding
+
+ def index; end
+
+ def create
+ begin
+ AccountBuilder.new(
+ account_name: onboarding_params.dig(:user, :company),
+ user_full_name: onboarding_params.dig(:user, :name),
+ email: onboarding_params.dig(:user, :email),
+ user_password: params.dig(:user, :password),
+ confirmed: true
+ ).perform
+ rescue StandardError => e
+ redirect_to '/', flash: { error: e.message } and return
+ end
+ finish_onboarding
+ redirect_to '/'
+ end
+
+ private
+
+ def onboarding_params
+ params.permit(:subscribe_to_updates, user: [:name, :company, :email])
+ end
+
+ def finish_onboarding
+ ::Redis::Alfred.delete(::Redis::Alfred::CHATWOOT_INSTALLATION_ONBOARDING)
+ ChatwootHub.register_instance(onboarding_params) if onboarding_params[:subscribe_to_updates]
+ end
+
+ def ensure_installation_onboarding
+ redirect_to '/' unless ::Redis::Alfred.get(::Redis::Alfred::CHATWOOT_INSTALLATION_ONBOARDING)
+ end
+end
diff --git a/app/javascript/dashboard/assets/scss/super_admin/index.scss b/app/javascript/dashboard/assets/scss/super_admin/index.scss
index a646bf5f9..205a10f70 100644
--- a/app/javascript/dashboard/assets/scss/super_admin/index.scss
+++ b/app/javascript/dashboard/assets/scss/super_admin/index.scss
@@ -1,15 +1,36 @@
@import '../variables';
.superadmin-body {
- background: $color-background;
+ background: var(--color-background);
+
+ .hero--title {
+ font-size: var(--font-size-mega);
+ font-weight: var(--font-weight-light);
+ margin-top: var(--space-large);
+ }
}
.alert-box {
- background-color: $alert-color;
+ background-color: var(--r-500);
border-radius: 5px;
- color: $color-white;
+ color: var(--color-white);
font-size: 14px;
margin-bottom: 14px;
padding: 10px;
text-align: center;
}
+
+.update-subscription--checkbox {
+ display: flex;
+
+ input {
+ line-height: 1.5;
+ margin-right: var(--space-one);
+ }
+
+ div {
+ font-size: var(--font-size-small);
+ line-height: 1.5;
+ margin-bottom: var(--space-normal);
+ }
+}
diff --git a/app/views/installation/onboarding/index.html.erb b/app/views/installation/onboarding/index.html.erb
new file mode 100644
index 000000000..8287714cd
--- /dev/null
+++ b/app/views/installation/onboarding/index.html.erb
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+

+
+ Howdy, Welcome to Chatwoot 👋
+
+
+
+
+ <%= form_tag('/installation/onboarding', class: 'login-box column align-self-top') do %>
+
+ <% end %>
+
+
+
+
+
diff --git a/config/routes.rb b/config/routes.rb
index 7d1715dea..06b8a4487 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -230,6 +230,11 @@ Rails.application.routes.draw do
end
end
+ namespace :installation do
+ get 'onboarding', to: 'onboarding#index'
+ post 'onboarding', to: 'onboarding#create'
+ end
+
# ---------------------------------------------------------------------
# Routes for swagger docs
get '/swagger/*path', to: 'swagger#respond'
diff --git a/db/seeds.rb b/db/seeds.rb
index 3b1395004..e3422e62c 100644
--- a/db/seeds.rb
+++ b/db/seeds.rb
@@ -2,39 +2,48 @@
GlobalConfig.clear_cache
ConfigLoader.new.process
-account = Account.create!(
- name: 'Acme Inc',
- domain: 'support.chatwoot.com',
- support_email: ENV.fetch('MAILER_SENDER_EMAIL', 'accounts@chatwoot.com')
-)
+## Seeds productions
+if Rails.env.production?
+ # Setup Onboarding flow
+ ::Redis::Alfred.set(::Redis::Alfred::CHATWOOT_INSTALLATION_ONBOARDING, true)
+end
-user = User.new(name: 'John', email: 'john@acme.inc', password: '123456')
-user.skip_confirmation!
-user.save!
+## Seeds for Local Development
+unless Rails.env.production?
+ SuperAdmin.create!(email: 'john@acme.inc', password: '123456')
-SuperAdmin.create!(email: 'john@acme.inc', password: '123456') unless Rails.env.production?
+ account = Account.create!(
+ name: 'Acme Inc',
+ domain: 'support.chatwoot.com',
+ support_email: ENV.fetch('MAILER_SENDER_EMAIL', 'accounts@chatwoot.com')
+ )
-AccountUser.create!(
- account_id: account.id,
- user_id: user.id,
- role: :administrator
-)
+ user = User.new(name: 'John', email: 'john@acme.inc', password: '123456')
+ user.skip_confirmation!
+ user.save!
-web_widget = Channel::WebWidget.create!(account: account, website_url: 'https://acme.inc')
+ AccountUser.create!(
+ account_id: account.id,
+ user_id: user.id,
+ role: :administrator
+ )
-inbox = Inbox.create!(channel: web_widget, account: account, name: 'Acme Support')
-InboxMember.create!(user: user, inbox: inbox)
+ web_widget = Channel::WebWidget.create!(account: account, website_url: 'https://acme.inc')
-contact = Contact.create!(name: 'jane', email: 'jane@example.com', phone_number: '0000', account: account)
-contact_inbox = ContactInbox.create!(inbox: inbox, contact: contact, source_id: user.id)
-conversation = Conversation.create!(
- account: account,
- inbox: inbox,
- status: :open,
- assignee: user,
- contact: contact,
- contact_inbox: contact_inbox,
- additional_attributes: {}
-)
-Message.create!(content: 'Hello', account: account, inbox: inbox, conversation: conversation, message_type: :incoming)
-CannedResponse.create!(account: account, short_code: 'start', content: 'Hello welcome to chatwoot.')
+ inbox = Inbox.create!(channel: web_widget, account: account, name: 'Acme Support')
+ InboxMember.create!(user: user, inbox: inbox)
+
+ contact = Contact.create!(name: 'jane', email: 'jane@example.com', phone_number: '0000', account: account)
+ contact_inbox = ContactInbox.create!(inbox: inbox, contact: contact, source_id: user.id)
+ conversation = Conversation.create!(
+ account: account,
+ inbox: inbox,
+ status: :open,
+ assignee: user,
+ contact: contact,
+ contact_inbox: contact_inbox,
+ additional_attributes: {}
+ )
+ Message.create!(content: 'Hello', account: account, inbox: inbox, conversation: conversation, message_type: :incoming)
+ CannedResponse.create!(account: account, short_code: 'start', content: 'Hello welcome to chatwoot.')
+end
diff --git a/lib/chatwoot_hub.rb b/lib/chatwoot_hub.rb
index 69e95ad9f..ef500e57b 100644
--- a/lib/chatwoot_hub.rb
+++ b/lib/chatwoot_hub.rb
@@ -1,5 +1,5 @@
class ChatwootHub
- BASE_URL = 'https://hub.chatwoot.com'.freeze
+ BASE_URL = ENV['CHATWOOT_HUB_URL'] || 'https://hub.chatwoot.com'
def self.instance_config
{
@@ -19,4 +19,12 @@ class ChatwootHub
end
version
end
+
+ def self.register_instance(info)
+ RestClient.post("#{BASE_URL}/register_instance", info.merge(instance_config).to_json, { content_type: :json, accept: :json })
+ rescue *ExceptionList::REST_CLIENT_EXCEPTIONS, *ExceptionList::URI_EXCEPTIONS => e
+ Rails.logger.info "Exception: #{e.message}"
+ rescue StandardError => e
+ Raven.capture_exception(e)
+ end
end
diff --git a/lib/redis/redis_keys.rb b/lib/redis/redis_keys.rb
index cef29705c..13c24cdb4 100644
--- a/lib/redis/redis_keys.rb
+++ b/lib/redis/redis_keys.rb
@@ -27,5 +27,6 @@ module Redis::RedisKeys
REAUTHORIZATION_REQUIRED = 'REAUTHORIZATION_REQUIRED:%
s:%d'.freeze
## Internal Installation related keys
+ CHATWOOT_INSTALLATION_ONBOARDING = 'CHATWOOT_INSTALLATION_ONBOARDING'.freeze
LATEST_CHATWOOT_VERSION = 'LATEST_CHATWOOT_VERSION'.freeze
end
diff --git a/spec/controllers/installation/onboarding_controller_spec.rb b/spec/controllers/installation/onboarding_controller_spec.rb
new file mode 100644
index 000000000..7b1416616
--- /dev/null
+++ b/spec/controllers/installation/onboarding_controller_spec.rb
@@ -0,0 +1,64 @@
+require 'rails_helper'
+
+RSpec.describe 'Installation::Onboarding API', type: :request do
+ let(:super_admin) { create(:super_admin) }
+
+ describe 'GET /installation/onboarding' do
+ context 'when CHATWOOT_INSTALLATION_ONBOARDING redis key is not set' do
+ it 'redirects back' do
+ expect(::Redis::Alfred.get(::Redis::Alfred::CHATWOOT_INSTALLATION_ONBOARDING)).to eq nil
+ get '/installation/onboarding'
+ expect(response).to have_http_status(:redirect)
+ end
+ end
+
+ context 'when CHATWOOT_INSTALLATION_ONBOARDING redis key is set' do
+ it 'returns onboarding page' do
+ ::Redis::Alfred.set(::Redis::Alfred::CHATWOOT_INSTALLATION_ONBOARDING, true)
+ get '/installation/onboarding'
+ expect(response).to have_http_status(:success)
+ ::Redis::Alfred.delete(::Redis::Alfred::CHATWOOT_INSTALLATION_ONBOARDING)
+ end
+ end
+ end
+
+ describe 'POST /installation/onboarding' do
+ let(:account_builder) { instance_double('account_builder') }
+
+ before do
+ allow(AccountBuilder).to receive(:new).and_return(account_builder)
+ allow(account_builder).to receive(:perform).and_return(true)
+ allow(ChatwootHub).to receive(:register_instance).and_return(true)
+ ::Redis::Alfred.set(::Redis::Alfred::CHATWOOT_INSTALLATION_ONBOARDING, true)
+ end
+
+ after do
+ ::Redis::Alfred.delete(::Redis::Alfred::CHATWOOT_INSTALLATION_ONBOARDING)
+ end
+
+ context 'when onboarding successfull' do
+ it 'deletes the redis key' do
+ post '/installation/onboarding', params: { user: {} }
+ expect(::Redis::Alfred.get(::Redis::Alfred::CHATWOOT_INSTALLATION_ONBOARDING)).to eq nil
+ end
+
+ it 'will not call register instance when checkboxes are unchecked' do
+ post '/installation/onboarding', params: { user: {} }
+ expect(ChatwootHub).not_to have_received(:register_instance)
+ end
+
+ it 'will call register instance when checkboxes are checked' do
+ post '/installation/onboarding', params: { user: {}, subscribe_to_updates: 1 }
+ expect(ChatwootHub).to have_received(:register_instance)
+ end
+ end
+
+ context 'when onboarding is not successfull' do
+ it ' does not deletes the redis key' do
+ allow(AccountBuilder).to receive(:new).and_raise('error')
+ post '/installation/onboarding', params: { user: {} }
+ expect(::Redis::Alfred.get(::Redis::Alfred::CHATWOOT_INSTALLATION_ONBOARDING)).not_to eq nil
+ end
+ end
+ end
+end