Chore: Making Account Signup Optional (#563)

Introduce new environment variable that lets you control account signups
ENABLE_ACCOUNT_SIGNUP :( true | false | api_only )
Fixes: #406

Co-authored-by: Pranav Raj S <pranavrajs@gmail.com>
This commit is contained in:
Sojan Jose 2020-02-29 11:20:33 +05:30 committed by GitHub
parent 0aad99ff0b
commit b05f843790
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 92 additions and 15 deletions

View file

@ -2,6 +2,12 @@ SECRET_KEY_BASE=
# Force all access to the app over SSL, default is set to false # Force all access to the app over SSL, default is set to false
FORCE_SSL= FORCE_SSL=
# This lets you control new sign ups on your chatwoot installation
# 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=
#redis config #redis config
REDIS_URL=redis://redis:6379 REDIS_URL=redis://redis:6379
# If you are using docker-compose, set this variable's value to be any string, # If you are using docker-compose, set this variable's value to be any string,

View file

@ -4,6 +4,7 @@ class Api::V1::AccountsController < Api::BaseController
skip_before_action :verify_authenticity_token, only: [:create] skip_before_action :verify_authenticity_token, only: [:create]
skip_before_action :authenticate_user!, :set_current_user, :check_subscription, :handle_with_exception, skip_before_action :authenticate_user!, :set_current_user, :check_subscription, :handle_with_exception,
only: [:create], raise: false only: [:create], raise: false
before_action :check_signup_enabled
rescue_from CustomExceptions::Account::InvalidEmail, rescue_from CustomExceptions::Account::InvalidEmail,
CustomExceptions::Account::UserExists, CustomExceptions::Account::UserExists,
@ -30,4 +31,8 @@ class Api::V1::AccountsController < Api::BaseController
def account_params def account_params
params.permit(:account_name, :email) params.permit(:account_name, :email)
end end
def check_signup_enabled
raise ActionController::RoutingError, 'Not Found' if ENV.fetch('ENABLE_ACCOUNT_SIGNUP', true) == 'false'
end
end end

View file

@ -36,6 +36,7 @@ export default {
path: 'signup', path: 'signup',
name: 'auth_signup', name: 'auth_signup',
component: Signup, component: Signup,
meta: { requireSignupEnabled: true },
}, },
{ {
path: 'reset/password', path: 'reset/password',

View file

@ -97,6 +97,14 @@ export const validateAuthenticateRoutePermission = (to, from, next) => {
}; };
const validateRouteAccess = (to, from, next) => { const validateRouteAccess = (to, from, next) => {
if (
window.chatwootConfig.signupEnabled !== 'true' &&
to.meta &&
to.meta.requireSignupEnabled
) {
next(frontendURL('dashboard'));
}
if (authIgnoreRoutes.includes(to.name)) { if (authIgnoreRoutes.includes(to.name)) {
return next(); return next();
} }

View file

@ -1,24 +1,44 @@
<template> <template>
<div class="medium-12 column login"> <div class="medium-12 column login">
<div class="text-center medium-12 login__hero align-self-top"> <div class="text-center medium-12 login__hero align-self-top">
<img src="~dashboard/assets/images/woot-logo.svg" alt="Woot-logo" class="hero__logo" /> <img
<h2 class="hero__title">{{$t('LOGIN.TITLE')}}</h2> src="~dashboard/assets/images/woot-logo.svg"
alt="Woot-logo"
class="hero__logo"
/>
<h2 class="hero__title">
{{ $t('LOGIN.TITLE') }}
</h2>
</div> </div>
<div class="row align-center"> <div class="row align-center">
<div class="small-12 medium-4 column"> <div class="small-12 medium-4 column">
<form class="login-box column align-self-top" v-on:submit.prevent="login()"> <form class="login-box column align-self-top" @submit.prevent="login()">
<div class="column log-in-form"> <div class="column log-in-form">
<!-- <h4 class="text-center">{{$t('LOGIN.TITLE')}}</h4> --> <!-- <h4 class="text-center">{{$t('LOGIN.TITLE')}}</h4> -->
<label :class="{ 'error': $v.credentials.email.$error }"> <label :class="{ error: $v.credentials.email.$error }">
{{$t('LOGIN.EMAIL.LABEL')}} {{ $t('LOGIN.EMAIL.LABEL') }}
<input type="text" v-bind:placeholder="$t('LOGIN.EMAIL.PLACEHOLDER')" v-model.trim="credentials.email" @input="$v.credentials.email.$touch"> <input
v-model.trim="credentials.email"
type="text"
:placeholder="$t('LOGIN.EMAIL.PLACEHOLDER')"
@input="$v.credentials.email.$touch"
/>
</label> </label>
<label :class="{ 'error': $v.credentials.password.$error }"> <label :class="{ error: $v.credentials.password.$error }">
{{$t('LOGIN.PASSWORD.LABEL')}} {{ $t('LOGIN.PASSWORD.LABEL') }}
<input type="password" v-bind:placeholder="$t('LOGIN.PASSWORD.PLACEHOLDER')" v-model.trim="credentials.password" @input="$v.credentials.password.$touch"> <input
v-model.trim="credentials.password"
type="password"
:placeholder="$t('LOGIN.PASSWORD.PLACEHOLDER')"
@input="$v.credentials.password.$touch"
/>
</label> </label>
<woot-submit-button <woot-submit-button
:disabled="$v.credentials.email.$invalid || $v.credentials.password.$invalid || loginApi.showLoading" :disabled="
$v.credentials.email.$invalid ||
$v.credentials.password.$invalid ||
loginApi.showLoading
"
:button-text="$t('LOGIN.SUBMIT')" :button-text="$t('LOGIN.SUBMIT')"
:loading="loginApi.showLoading" :loading="loginApi.showLoading"
button-class="large expanded" button-class="large expanded"
@ -30,10 +50,10 @@
<div class="column text-center sigin__footer"> <div class="column text-center sigin__footer">
<p> <p>
<router-link to="auth/reset/password"> <router-link to="auth/reset/password">
{{$t('LOGIN.FORGOT_PASSWORD')}} {{ $t('LOGIN.FORGOT_PASSWORD') }}
</router-link> </router-link>
</p> </p>
<p> <p v-if="showSignupLink()">
<router-link to="auth/signup"> <router-link to="auth/signup">
{{ $t('LOGIN.CREATE_NEW_ACCOUNT') }} {{ $t('LOGIN.CREATE_NEW_ACCOUNT') }}
</router-link> </router-link>
@ -89,6 +109,9 @@ export default {
this.loginApi.message = message; this.loginApi.message = message;
bus.$emit('newToastMessage', this.loginApi.message); bus.$emit('newToastMessage', this.loginApi.message);
}, },
showSignupLink() {
return window.chatwootConfig.signupEnabled === 'true';
},
login() { login() {
this.loginApi.showLoading = true; this.loginApi.showLoading = true;
const credentials = { const credentials = {
@ -100,7 +123,7 @@ export default {
.then(() => { .then(() => {
this.showAlert(this.$t('LOGIN.API.SUCCESS_MESSAGE')); this.showAlert(this.$t('LOGIN.API.SUCCESS_MESSAGE'));
}) })
.catch((response) => { .catch(response => {
if (response && response.status === 401) { if (response && response.status === 401) {
this.showAlert(this.$t('LOGIN.API.UNAUTH')); this.showAlert(this.$t('LOGIN.API.UNAUTH'));
return; return;

View file

@ -31,8 +31,9 @@
<%= yield %> <%= yield %>
<script> <script>
window.chatwootConfig = { window.chatwootConfig = {
fbAppId: '<%= ENV['FB_APP_ID'] %>', fbAppId: '<%= ENV.fetch('FB_APP_ID', nil) %>',
billingEnabled: '<%= ENV['BILLING_ENABLED'] %>' billingEnabled: <%= ActiveModel::Type::Boolean.new.cast(ENV.fetch('BILLING_ENABLED', false)) %>,
signupEnabled: '<%= ENV.fetch('ENABLE_ACCOUNT_SIGNUP', true) %>'
} }
</script> </script>
</body> </body>

View file

@ -9,6 +9,7 @@ RSpec.describe 'Accounts API', type: :request do
before do before do
allow(AccountBuilder).to receive(:new).and_return(account_builder) allow(AccountBuilder).to receive(:new).and_return(account_builder)
ENV['ENABLE_ACCOUNT_SIGNUP'] = nil
end end
it 'calls account builder' do it 'calls account builder' do
@ -40,5 +41,37 @@ RSpec.describe 'Accounts API', type: :request do
expect(response.body).to eq({ message: I18n.t('errors.signup.failed') }.to_json) expect(response.body).to eq({ message: I18n.t('errors.signup.failed') }.to_json)
end end
end end
context 'when ENABLE_ACCOUNT_SIGNUP env variable is set to false' do
let(:email) { Faker::Internet.email }
it 'responds 404 on requests' do
params = { account_name: 'test', email: email }
ENV['ENABLE_ACCOUNT_SIGNUP'] = 'false'
post api_v1_accounts_url,
params: params,
as: :json
expect(response).to have_http_status(:not_found)
ENV['ENABLE_ACCOUNT_SIGNUP'] = nil
end
end
context 'when ENABLE_ACCOUNT_SIGNUP env variable is set to api_only' do
let(:email) { Faker::Internet.email }
it 'does not respond 404 on requests' do
params = { account_name: 'test', email: email }
ENV['ENABLE_ACCOUNT_SIGNUP'] = 'api_only'
post api_v1_accounts_url,
params: params,
as: :json
expect(response).not_to have_http_status(:not_found)
ENV['ENABLE_ACCOUNT_SIGNUP'] = nil
end
end
end end
end end