[Team Email Login] Refactor Authentication Provider Enable/Disable (#11185)
* Starting out
* Building away...
* Hooking buttons up
* Hook Auth Provider buttons to Array Field
* trying to fix NoNameError
* Remains InviteOnlyMode disable and tests
* Smashing remaining tasks
* Last of tasks
* add tests
* Complete specs and tests 😅
* Fix bug
* Additional guard
* pass event to functions
* Position Email Auth first
* Fix bug in Email Auth Modal
* Fix spacing issue
* Update docs for adminModal.js
* Show/hide Enabled Indicator with Enable/Undo buttons
* Complete Auth Providers functionality
* Update app/javascript/admin/controllers/config_controller.js
Co-authored-by: Vaidehi Joshi <vaidehi.sj@gmail.com>
* Update app/javascript/admin/controllers/config_controller.js
Co-authored-by: Vaidehi Joshi <vaidehi.sj@gmail.com>
* Update app/controllers/admin/configs_controller.rb
Co-authored-by: Vaidehi Joshi <vaidehi.sj@gmail.com>
* Update helper names
* better implementation of EnabledIndicator show/hide
* Small copy changes
* Update spec/helpers/authentication_helper_spec.rb
Co-authored-by: Vaidehi Joshi <vaidehi.sj@gmail.com>
* Update app/views/admin/configs/show.html.erb
Co-authored-by: Vaidehi Joshi <vaidehi.sj@gmail.com>
* Update app/helpers/authentication_helper.rb
Co-authored-by: Vaidehi Joshi <vaidehi.sj@gmail.com>
Co-authored-by: Vaidehi Joshi <vaidehi.sj@gmail.com>
This commit is contained in:
parent
397a1c2389
commit
08796b5cee
12 changed files with 446 additions and 205 deletions
|
|
@ -5,8 +5,8 @@
|
|||
* @param {string} title The title/heading text to be displayed
|
||||
* @param {string} text The body text to be displayed
|
||||
* @param {string} confirm_text Text of the confirmation button
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* @example
|
||||
* showUserAlertModal('Warning', 'You must wait', 'OK', '/faq/why-must-i-wait', 'Why must I wait?');
|
||||
*/
|
||||
function showUserAlertModal(title, text, confirm_text) {
|
||||
|
|
@ -14,44 +14,54 @@ function showUserAlertModal(title, text, confirm_text) {
|
|||
toggleUserAlertModal();
|
||||
}
|
||||
/**
|
||||
* Displays a user rate limit alert modal letting the user know what they did that exceeded a rate limit,
|
||||
* Displays a user rate limit alert modal letting the user know what they did that exceeded a rate limit,
|
||||
* and gives them links to explain why they must wait
|
||||
*
|
||||
* @function showUserAlertModal
|
||||
* @param {string} action_text Description of the action taken by the user
|
||||
* @param {string} next_action_text Description of the next action that can be taken
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* @example
|
||||
* showRateLimitModal('Made a comment', 'comment again');
|
||||
*/
|
||||
function showRateLimitModal(action_text, next_action_text) {
|
||||
let rateLimitText = buildRateLimitText(action_text, next_action_text);
|
||||
let rateLimitLink = "/faq";
|
||||
showUserAlertModal('Wait a Moment...', rateLimitText, 'Got it', rateLimitLink, "Why do I have to wait?")
|
||||
let rateLimitLink = '/faq';
|
||||
showUserAlertModal(
|
||||
'Wait a Moment...',
|
||||
rateLimitText,
|
||||
'Got it',
|
||||
rateLimitLink,
|
||||
'Why do I have to wait?',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML ID for modal DOM node
|
||||
*
|
||||
*
|
||||
* @private
|
||||
* @constant modalId *
|
||||
* @constant modalId *
|
||||
* @type {string}
|
||||
*/
|
||||
const modalId = 'user-alert-modal';
|
||||
|
||||
/**
|
||||
* HTML template for modal
|
||||
*
|
||||
*
|
||||
* @private
|
||||
* @function getModalHtml
|
||||
*
|
||||
*
|
||||
* @param {string} title The title/heading text to be displayed
|
||||
* @param {string} text The body text to be displayed
|
||||
* @param {string} confirm_text Text of the confirmation button
|
||||
*
|
||||
*
|
||||
* @returns {string} HTML for the modal
|
||||
*/
|
||||
const getModalHtml = (title, text, confirm_text) => `<div id="${modalId}" data-testid="modal-container" class="crayons-modal hidden">
|
||||
const getModalHtml = (
|
||||
title,
|
||||
text,
|
||||
confirm_text,
|
||||
) => `<div id="${modalId}" data-testid="modal-container" class="crayons-modal hidden">
|
||||
<div role="dialog" aria-modal="true" class="crayons-modal__box">
|
||||
<div class="crayons-modal__box__header">
|
||||
<h2>${title}</h2>
|
||||
|
|
@ -78,25 +88,25 @@ const getModalHtml = (title, text, confirm_text) => `<div id="${modalId}" data-t
|
|||
|
||||
/**
|
||||
* Constructs wording for rate limit modals
|
||||
*
|
||||
*
|
||||
* @private
|
||||
* @function buildRateLimitText
|
||||
*
|
||||
*
|
||||
* @param {string} action_text Description of the action taken by the user
|
||||
* @param {string} next_action_text Description of the next action that can be taken
|
||||
*
|
||||
*
|
||||
* @returns {string} Formatted body text for a rate limit modal
|
||||
*/
|
||||
function buildRateLimitText(action_text, next_action_text) {
|
||||
return `Since you recently ${action_text}, you’ll need to wait a moment before ${next_action_text}.`
|
||||
return `Since you recently ${action_text}, you’ll need to wait a moment before ${next_action_text}.`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows or hides the user alert modal by toggling it's 'hidden' class
|
||||
*
|
||||
*
|
||||
* @private
|
||||
* @function toggleUserAlertModal
|
||||
*
|
||||
*
|
||||
*/
|
||||
function toggleUserAlertModal() {
|
||||
let modalDiv = document.getElementById(modalId);
|
||||
|
|
@ -107,14 +117,14 @@ function toggleUserAlertModal() {
|
|||
|
||||
/**
|
||||
* Checks for the alert modal, and if it's not present builds and inserts it in the DOM
|
||||
*
|
||||
*
|
||||
* @private
|
||||
* @function buildModalDiv
|
||||
*
|
||||
*
|
||||
* @param {string} title The title/heading text to be displayed
|
||||
* @param {string} text The body text to be displayed
|
||||
* @param {string} confirm_text Text of the confirmation button
|
||||
*
|
||||
*
|
||||
* @returns {Element} DOM node of the inserted alert modal
|
||||
*/
|
||||
function buildModalDiv(title, text, confirm_text) {
|
||||
|
|
@ -128,18 +138,18 @@ function buildModalDiv(title, text, confirm_text) {
|
|||
|
||||
/**
|
||||
* Takes template HTML for a modal and creates a DOM node based on supplied arguments
|
||||
*
|
||||
*
|
||||
* @private
|
||||
* @function getModal
|
||||
*
|
||||
*
|
||||
* @param {string} title The title/heading text to be displayed
|
||||
* @param {string} text The body text to be displayed
|
||||
* @param {string} confirm_text Text of the confirmation button
|
||||
*
|
||||
*
|
||||
* @returns {Element} DOM node of alert modal with formatted text
|
||||
*/
|
||||
function getModal(title, text, confirm_text) {
|
||||
let wrapper = document.createElement('div');
|
||||
wrapper.innerHTML= getModalHtml(title, text, confirm_text);
|
||||
wrapper.innerHTML = getModalHtml(title, text, confirm_text);
|
||||
return wrapper.firstChild;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,6 +128,17 @@ label {
|
|||
height: 40px;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
&--label {
|
||||
.enabled-indicator-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.enabled-indicator-visible {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.config-authentication-form {
|
||||
|
|
|
|||
|
|
@ -89,11 +89,6 @@ module Admin
|
|||
display_jobs_banner
|
||||
].freeze
|
||||
|
||||
ALLOWED_EMPTY_ENUMERABLES =
|
||||
%i[
|
||||
authentication_providers
|
||||
].freeze
|
||||
|
||||
ALLOWED_PARAMS =
|
||||
%i[
|
||||
ga_tracking_id
|
||||
|
|
@ -117,6 +112,7 @@ module Admin
|
|||
github_secret
|
||||
facebook_key
|
||||
facebook_secret
|
||||
auth_providers_to_enable
|
||||
invite_only_mode
|
||||
allow_both_email_signup_and_login
|
||||
require_captcha_for_email_password_registration
|
||||
|
|
@ -143,7 +139,9 @@ module Admin
|
|||
clean_up_params
|
||||
|
||||
config_params.each do |key, value|
|
||||
if value.is_a?(Array)
|
||||
if key == "auth_providers_to_enable"
|
||||
update_enabled_auth_providers(value) unless value.class.name != "String"
|
||||
elsif value.is_a?(Array)
|
||||
SiteConfig.public_send("#{key}=", value.reject(&:blank?)) unless value.empty?
|
||||
elsif value.respond_to?(:to_h)
|
||||
SiteConfig.public_send("#{key}=", value.to_h) unless value.empty?
|
||||
|
|
@ -223,6 +221,23 @@ module Admin
|
|||
end
|
||||
end
|
||||
|
||||
def update_enabled_auth_providers(value)
|
||||
enabled_providers = []
|
||||
value.split(",").each do |entry|
|
||||
enabled_providers.push(entry) unless invalid_provider_entry(entry)
|
||||
end
|
||||
SiteConfig.public_send("authentication_providers=", enabled_providers) unless
|
||||
prevent_all_auth_provider_disable?(enabled_providers)
|
||||
end
|
||||
|
||||
def invalid_provider_entry(entry)
|
||||
entry.blank? || helpers.available_providers_array.exclude?(entry)
|
||||
end
|
||||
|
||||
def prevent_all_auth_provider_disable?(value)
|
||||
value.empty? && !SiteConfig.allow_email_password_login
|
||||
end
|
||||
|
||||
# Validations
|
||||
def brand_contrast_too_low
|
||||
hex = params.dig(:site_config, :primary_brand_color_hex)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@ module AuthenticationHelper
|
|||
Authentication::Providers.enabled_for_user(user)
|
||||
end
|
||||
|
||||
def available_providers_array
|
||||
Authentication::Providers.available.map(&:to_s)
|
||||
end
|
||||
|
||||
def recaptcha_configured_and_enabled?
|
||||
SiteConfig.recaptcha_secret_key.present? &&
|
||||
SiteConfig.recaptcha_site_key.present? &&
|
||||
|
|
@ -33,23 +37,45 @@ module AuthenticationHelper
|
|||
SiteConfig.waiting_on_first_user
|
||||
end
|
||||
|
||||
def disable_email_tooltip_class
|
||||
SiteConfig.invite_only_mode || authentication_enabled_providers.none? ? "crayons-tooltip" : ""
|
||||
def invite_only_mode_or_no_enabled_providers
|
||||
SiteConfig.invite_only_mode || authentication_enabled_providers.none?
|
||||
end
|
||||
|
||||
def disable_email_tooltip_content
|
||||
SiteConfig.invite_only_mode || authentication_enabled_providers.none? ? disable_email_auth_tooltip_text : ""
|
||||
def email_login_disabled_and_one_auth_provider_enabled
|
||||
!SiteConfig.allow_email_password_login && authentication_enabled_providers.count == 1
|
||||
end
|
||||
|
||||
def disable_button_class
|
||||
SiteConfig.invite_only_mode || authentication_enabled_providers.none? ? "disabled" : ""
|
||||
def tooltip_class_on_email_auth_disablebtn
|
||||
invite_only_mode_or_no_enabled_providers ? "crayons-tooltip" : ""
|
||||
end
|
||||
|
||||
def disable_email_auth_tooltip_text
|
||||
def tooltip_class_on_auth_provider_enablebtn
|
||||
SiteConfig.invite_only_mode ? "crayons-tooltip" : ""
|
||||
end
|
||||
|
||||
def tooltip_class_on_auth_provider_disablebtn
|
||||
email_login_disabled_and_one_auth_provider_enabled ? "crayons-tooltip" : ""
|
||||
end
|
||||
|
||||
def disabled_attr_on_email_auth_disablebtn
|
||||
invite_only_mode_or_no_enabled_providers ? "disabled" : ""
|
||||
end
|
||||
|
||||
def disabled_attr_on_auth_provider_enablebtn
|
||||
SiteConfig.invite_only_mode ? "disabled" : ""
|
||||
end
|
||||
|
||||
def disabled_attr_on_auth_rpovider_disablebtn
|
||||
email_login_disabled_and_one_auth_provider_enabled ? "disabled" : ""
|
||||
end
|
||||
|
||||
def tooltip_text_email_or_auth_provider_btns
|
||||
if SiteConfig.invite_only_mode
|
||||
"You cannot do this until you disable Invite Only Mode"
|
||||
elsif authentication_enabled_providers.none?
|
||||
elsif authentication_enabled_providers.none? || email_login_disabled_and_one_auth_provider_enabled
|
||||
"You cannot do this until you enable at least one other registration option"
|
||||
else
|
||||
""
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
* @param {string} confirmBtnAction The function that fires when "Confirm" button is clicked.
|
||||
* @param {string} cancelBtnText The text for the modal's "Cancel" button.
|
||||
* @param {string} cancelBtnAction The function that fires when "Cancel" button is clicked.
|
||||
* @param {string} customAttr A custom data attribute name. Will be apprended to the "data-" part.
|
||||
* @param {string} customAttrValue The value of the custom attribute "customAttr".
|
||||
*/
|
||||
const adminModal = (
|
||||
title,
|
||||
|
|
@ -16,6 +18,8 @@ const adminModal = (
|
|||
confirmBtnAction,
|
||||
cancelBtnText,
|
||||
cancelBtnAction,
|
||||
customAttr = null,
|
||||
customAttrValue = null,
|
||||
) => `
|
||||
<div class="crayons-modal crayons-modal--s">
|
||||
<div class="crayons-modal__box">
|
||||
|
|
@ -32,7 +36,8 @@ const adminModal = (
|
|||
<div class="flex gap-2">
|
||||
<button
|
||||
class="crayons-btn crayons-btn--danger"
|
||||
data-action="click->config#${confirmBtnAction}">
|
||||
data-action="click->config#${confirmBtnAction}"
|
||||
data-${customAttr}="${customAttrValue}">
|
||||
${confirmBtnText}
|
||||
</button>
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ const emailSigninAndLoginCheckbox = document.querySelector(
|
|||
const emailAuthSettingsSection = document.querySelector(
|
||||
'#email-auth-settings-section',
|
||||
);
|
||||
const emailAuthModalTitle = 'Disable email address registration';
|
||||
const emailAuthModalTitle = 'Disable Email address registration';
|
||||
// TODO: Remove the sentence "You must update site config to save this action!"
|
||||
// once we build more robust flow for Admin/Config
|
||||
const emailAuthModalBody =
|
||||
'<p>If you disable email address as a registration option, people cannot create an account with their email address.</p><p>However, people who have already created an account using their email address can continue to login.</p><p><strong>Please update site config to save this action.</strong></p>';
|
||||
'<p>If you disable Email address as a registration option, people cannot create an account with their email address.</p><p>However, people who have already created an account using their email address can continue to login.</p><p><strong>Please update site config to save this action.</strong></p>';
|
||||
|
||||
export default class ConfigController extends Controller {
|
||||
static targets = [
|
||||
|
|
@ -25,6 +25,8 @@ export default class ConfigController extends Controller {
|
|||
'requireCaptchaForEmailPasswordRegistration',
|
||||
];
|
||||
|
||||
// GENERAL FUNCTIONS START
|
||||
|
||||
disableTargetField(event) {
|
||||
const targetElementName = event.target.dataset.disableTarget;
|
||||
const targetElement = this[`${targetElementName}Target`];
|
||||
|
|
@ -43,6 +45,23 @@ export default class ConfigController extends Controller {
|
|||
}
|
||||
}
|
||||
|
||||
closeAdminConfigModal() {
|
||||
this.configModalAnchorTarget.innerHTML = '';
|
||||
document.body.style.height = 'inherit';
|
||||
document.body.style.overflowY = 'inherit';
|
||||
}
|
||||
|
||||
positionModalOnPage() {
|
||||
if (document.querySelector('.crayons-modal')) {
|
||||
document.body.style.height = '100vh';
|
||||
document.body.style.overflowY = 'hidden';
|
||||
}
|
||||
}
|
||||
|
||||
// GENERAL FUNCTIONS END
|
||||
|
||||
// EMAIL AUTH FUNCTIONS START
|
||||
|
||||
toggleGoogleRecaptchaFields() {
|
||||
if (this.requireCaptchaForEmailPasswordRegistrationTarget.checked) {
|
||||
recaptchaFields.classList.remove('hidden');
|
||||
|
|
@ -51,18 +70,18 @@ export default class ConfigController extends Controller {
|
|||
}
|
||||
}
|
||||
|
||||
enableOrEditEmailAuthSettings() {
|
||||
enableOrEditEmailAuthSettings(event) {
|
||||
event.preventDefault();
|
||||
if (this.emailAuthSettingsBtnTarget.dataset.buttonText === 'enable') {
|
||||
emailSigninAndLoginCheckbox.checked = true;
|
||||
this.enabledIndicatorTarget.classList.add('flex', 'items-center');
|
||||
this.enabledIndicatorTarget.classList.remove('hidden');
|
||||
this.emailAuthSettingsBtnTarget.setAttribute('data-button-text', 'edit');
|
||||
this.enabledIndicatorTarget.classList.toggle('enabled-indicator-visible');
|
||||
}
|
||||
this.emailAuthSettingsBtnTarget.classList.add('hidden');
|
||||
emailAuthSettingsSection.classList.remove('hidden');
|
||||
}
|
||||
|
||||
hideEmailAuthSettings() {
|
||||
hideEmailAuthSettings(event) {
|
||||
event.preventDefault();
|
||||
this.emailAuthSettingsBtnTarget.classList.remove('hidden');
|
||||
emailAuthSettingsSection.classList.add('hidden');
|
||||
|
|
@ -78,30 +97,144 @@ export default class ConfigController extends Controller {
|
|||
'Cancel',
|
||||
'closeAdminConfigModal',
|
||||
);
|
||||
if (document.querySelector('.crayons-modal')) {
|
||||
document.body.style.height = '100vh';
|
||||
document.body.style.overflowY = 'hidden';
|
||||
}
|
||||
this.positionModalOnPage();
|
||||
}
|
||||
|
||||
closeAdminConfigModal() {
|
||||
this.configModalAnchorTarget.innerHTML = '';
|
||||
document.body.style.height = 'inherit';
|
||||
document.body.style.overflowY = 'inherit';
|
||||
}
|
||||
|
||||
disableEmailAuthFromModal() {
|
||||
disableEmailAuthFromModal(event) {
|
||||
event.preventDefault();
|
||||
this.disableEmailAuth();
|
||||
this.closeAdminConfigModal();
|
||||
this.disableEmailAuth(event);
|
||||
this.closeAdminConfigModal(event);
|
||||
}
|
||||
|
||||
disableEmailAuth() {
|
||||
disableEmailAuth(event) {
|
||||
event.preventDefault();
|
||||
emailSigninAndLoginCheckbox.checked = false;
|
||||
this.emailAuthSettingsBtnTarget.innerHTML = 'Enable';
|
||||
this.enabledIndicatorTarget.classList.remove('flex', 'items-center');
|
||||
this.enabledIndicatorTarget.classList.add('hidden');
|
||||
this.hideEmailAuthSettings();
|
||||
this.emailAuthSettingsBtnTarget.setAttribute('data-button-text', 'enable');
|
||||
this.enabledIndicatorTarget.classList.toggle('enabled-indicator-visible');
|
||||
this.hideEmailAuthSettings(event);
|
||||
}
|
||||
|
||||
// EMAIL AUTH FUNCTIONS END
|
||||
|
||||
// AUTH PROVIDERS FUNCTIONS START
|
||||
|
||||
enableOrEditAuthProvider(event) {
|
||||
event.preventDefault();
|
||||
const provider = event.target.dataset.authProviderEnable;
|
||||
const enabledIndicator = document.querySelector(
|
||||
`#${provider}-enabled-indicator`,
|
||||
);
|
||||
if (event.target.dataset.buttonText === 'enable') {
|
||||
enabledIndicator.classList.add('enabled-indicator-visible');
|
||||
event.target.setAttribute('data-enable-auth', 'true');
|
||||
this.listAuthToBeEnabled();
|
||||
}
|
||||
document
|
||||
.querySelector(`#${provider}-auth-settings`)
|
||||
.classList.remove('hidden');
|
||||
event.target.classList.add('hidden');
|
||||
}
|
||||
|
||||
disableAuthProvider(event) {
|
||||
event.preventDefault();
|
||||
const provider = event.target.dataset.authProvider;
|
||||
const enabledIndicator = document.querySelector(
|
||||
`#${provider}-enabled-indicator`,
|
||||
);
|
||||
const authEnableButton = document.querySelector(
|
||||
`[data-auth-provider-enable="${provider}"]`,
|
||||
);
|
||||
authEnableButton.setAttribute('data-enable-auth', 'false');
|
||||
enabledIndicator.classList.remove('enabled-indicator-visible');
|
||||
this.listAuthToBeEnabled(event);
|
||||
this.hideAuthProviderSettings(event);
|
||||
}
|
||||
|
||||
authProviderModalTitle(provider) {
|
||||
return `Disable ${provider} login`;
|
||||
}
|
||||
|
||||
authProviderModalBody(provider) {
|
||||
return `<p>If you disable ${provider} as a login option, people cannot authenticate with ${provider}.</p><p><strong>You must update Site Config to save this action!</strong></p>`;
|
||||
}
|
||||
|
||||
activateAuthProviderModal(event) {
|
||||
event.preventDefault();
|
||||
const provider = event.target.dataset.authProvider;
|
||||
const official_provider = event.target.dataset.authProviderOfficial;
|
||||
this.configModalAnchorTarget.innerHTML = adminModal(
|
||||
this.authProviderModalTitle(official_provider),
|
||||
this.authProviderModalBody(official_provider),
|
||||
'Confirm disable',
|
||||
'disableAuthProviderFromModal',
|
||||
'Cancel',
|
||||
'closeAdminConfigModal',
|
||||
'auth-provider',
|
||||
provider,
|
||||
);
|
||||
this.positionModalOnPage();
|
||||
}
|
||||
|
||||
disableAuthProviderFromModal(event) {
|
||||
event.preventDefault();
|
||||
const provider = event.target.dataset.authProvider;
|
||||
const authEnableButton = document.querySelector(
|
||||
`[data-auth-provider-enable="${provider}"]`,
|
||||
);
|
||||
const enabledIndicator = document.querySelector(
|
||||
`#${provider}-enabled-indicator`,
|
||||
);
|
||||
authEnableButton.setAttribute('data-enable-auth', 'false');
|
||||
this.listAuthToBeEnabled(event);
|
||||
this.checkForAndGuardSoleAuthProvider();
|
||||
enabledIndicator.classList.remove('enabled-indicator-visible');
|
||||
this.hideAuthProviderSettings(event);
|
||||
this.closeAdminConfigModal(event);
|
||||
}
|
||||
|
||||
checkForAndGuardSoleAuthProvider() {
|
||||
if (
|
||||
document.querySelectorAll('[data-enable-auth="true"]').length === 1 &&
|
||||
document
|
||||
.querySelector('#email-auth-enable-edit-btn')
|
||||
.getAttribute('data-button-text') === 'enable'
|
||||
) {
|
||||
const targetAuthDisableBtn = document.querySelector(
|
||||
'[data-enable-auth="true"]',
|
||||
);
|
||||
targetAuthDisableBtn.parentElement.classList.add('crayons-tooltip');
|
||||
targetAuthDisableBtn.parentElement.setAttribute(
|
||||
'data-tooltip',
|
||||
'To edit this, you must first enable Email address as a registration option',
|
||||
);
|
||||
targetAuthDisableBtn.setAttribute('disabled', true);
|
||||
}
|
||||
}
|
||||
|
||||
hideAuthProviderSettings(event) {
|
||||
event.preventDefault();
|
||||
const provider = event.target.dataset.authProvider;
|
||||
document
|
||||
.querySelector(`#${provider}-auth-settings`)
|
||||
.classList.add('hidden');
|
||||
document.querySelector(`#${provider}-auth-btn`).classList.remove('hidden');
|
||||
}
|
||||
|
||||
listAuthToBeEnabled() {
|
||||
const enabledProviderArray = [];
|
||||
document
|
||||
.querySelectorAll('[data-enable-auth="true"]')
|
||||
.forEach((provider) => {
|
||||
enabledProviderArray.push(provider.dataset.authProviderEnable);
|
||||
});
|
||||
document.querySelector(
|
||||
'#auth_providers_to_enable',
|
||||
).value = enabledProviderArray;
|
||||
}
|
||||
|
||||
disableAuthenticationOptions() {
|
||||
document.querySelector('#auth_providers_to_enable').value = '';
|
||||
}
|
||||
// AUTH PROVIDERS FUNCTIONS END
|
||||
}
|
||||
|
|
|
|||
54
app/views/admin/configs/_auth_provider_settings.html.erb
Normal file
54
app/views/admin/configs/_auth_provider_settings.html.erb
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
<div class="config-authentication__item">
|
||||
<div class="config-authentication__item--container">
|
||||
<div class="config-authentication__item--body">
|
||||
<fieldset class="config-authentication-form">
|
||||
<div class="crayons-field">
|
||||
<%= admin_config_label :"#{provider.provider_name}_key" %>
|
||||
<p class="crayons-field__description">
|
||||
<%= Constants::SiteConfig::DETAILS[:"#{provider.provider_name}_key"][:description] %>
|
||||
</p>
|
||||
<%= f.text_field :"#{provider.provider_name}_key",
|
||||
class: "crayons-textfield",
|
||||
value: SiteConfig.public_send("#{provider.provider_name}_key"),
|
||||
placeholder: Constants::SiteConfig::DETAILS[:"#{provider.provider_name}_key"][:placeholder] %>
|
||||
</div>
|
||||
<div class="crayons-field">
|
||||
<%= admin_config_label :"#{provider.provider_name}_secret" %>
|
||||
<p class="crayons-field__description">
|
||||
<%= Constants::SiteConfig::DETAILS[:"#{provider.provider_name}_secret"][:description] %>
|
||||
<p>
|
||||
<%= f.text_field :"#{provider.provider_name}_secret",
|
||||
class: "crayons-textfield",
|
||||
value: SiteConfig.public_send("#{provider.provider_name}_secret"),
|
||||
placeholder: Constants::SiteConfig::DETAILS[:"#{provider.provider_name}_secret"][:placeholder] %>
|
||||
</div>
|
||||
<div class="mt-6">
|
||||
<% if authentication_enabled_providers.include?(provider) %>
|
||||
<button
|
||||
class="crayons-btn crayons-btn--danger <%= tooltip_class_on_auth_provider_disablebtn %>"
|
||||
data-action="click->config#activateAuthProviderModal"
|
||||
data-tooltip="<%= tooltip_text_email_or_auth_provider_btns %>"
|
||||
data-auth-provider="<%= provider.provider_name %>"
|
||||
data-auth-provider-official="<%= provider.official_name %>"
|
||||
<%= disabled_attr_on_auth_rpovider_disablebtn %>>
|
||||
Disable
|
||||
</button>
|
||||
<button
|
||||
class="crayons-btn crayons-btn--secondary"
|
||||
data-auth-provider="<%= provider.provider_name %>"
|
||||
data-action="click->config#hideAuthProviderSettings">
|
||||
Close
|
||||
</button>
|
||||
<% else %>
|
||||
<button
|
||||
class="crayons-btn crayons-btn--secondary"
|
||||
data-auth-provider="<%= provider.provider_name %>"
|
||||
data-action="click->config#disableAuthProvider">
|
||||
Undo
|
||||
</button>
|
||||
<% end %>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -162,7 +162,7 @@
|
|||
</p>
|
||||
</header>
|
||||
|
||||
<section class="config-authentication__item">
|
||||
<section class="config-authentication__item mb-0">
|
||||
<figure class="config-authentication__item--icon">
|
||||
<%= inline_svg_tag("email.svg", class: "crayons-icon", aria: true, title: "Email icon") %>
|
||||
</figure>
|
||||
|
|
@ -173,7 +173,9 @@
|
|||
<p class="crayons-field__label <%= SiteConfig.allow_both_email_signup_and_login ? "pb-0" : "" %>">
|
||||
Email address
|
||||
</p>
|
||||
<div class="<%= SiteConfig.allow_both_email_signup_and_login ? "flex items-center" : "hidden" %>" data-target="config.enabledIndicator">
|
||||
<div
|
||||
class="enabled-indicator-hidden <%= SiteConfig.allow_both_email_signup_and_login ? "enabled-indicator-visible" : "" %>"
|
||||
data-target="config.enabledIndicator">
|
||||
<%= inline_svg_tag("checkmark.svg", aria: true, class: "crayons-icon admin-config-checkmark", title: "Checkmark") %>
|
||||
<small class="crayons-field__description ml-1">Enabled</small>
|
||||
</div>
|
||||
|
|
@ -181,6 +183,7 @@
|
|||
|
||||
<button
|
||||
class="crayons-btn crayons-btn--secondary"
|
||||
id="email-auth-enable-edit-btn"
|
||||
data-button-text="<%= SiteConfig.allow_both_email_signup_and_login ? "edit" : "enable" %>"
|
||||
data-target="config.emailAuthSettingsBtn"
|
||||
data-action="click->config#enableOrEditEmailAuthSettings">
|
||||
|
|
@ -227,15 +230,13 @@
|
|||
<div class="flex gap-2">
|
||||
<% if SiteConfig.allow_both_email_signup_and_login %>
|
||||
<button
|
||||
class="crayons-btn crayons-btn--danger <%= disable_email_tooltip_class %>"
|
||||
class="crayons-btn crayons-btn--danger <%= tooltip_class_on_email_auth_disablebtn %>"
|
||||
data-action="click->config#activateEmailAuthModal"
|
||||
data-tooltip="<%= disable_email_tooltip_content %>"
|
||||
<%= disable_button_class %>>
|
||||
data-tooltip="<%= tooltip_text_email_or_auth_provider_btns %>"
|
||||
<%= disabled_attr_on_email_auth_disablebtn %>>
|
||||
Disable
|
||||
</button>
|
||||
<% end %>
|
||||
<% if SiteConfig.allow_both_email_signup_and_login %>
|
||||
<button
|
||||
<button
|
||||
class="crayons-btn crayons-btn--secondary"
|
||||
data-action="click->config#hideEmailAuthSettings">
|
||||
Close
|
||||
|
|
@ -252,136 +253,60 @@
|
|||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<hr class="my-0" />
|
||||
|
||||
<div class="form-group">
|
||||
<%= admin_config_label :authentication_providers %>
|
||||
<p class="crayons-field__description">
|
||||
<%= Constants::SiteConfig::DETAILS[:authentication_providers][:description] %>
|
||||
</p>
|
||||
<%= select_tag "site_config[authentication_providers]",
|
||||
options_from_collection_for_select(
|
||||
authentication_available_providers,
|
||||
:provider_name,
|
||||
:official_name,
|
||||
authentication_enabled_providers.map(&:provider_name),
|
||||
),
|
||||
multiple: true,
|
||||
class: "form-control selectpicker",
|
||||
data: { target: "config.authenticationProviders" } %>
|
||||
</div>
|
||||
|
||||
<section class="config-authentication__item">
|
||||
<figure class="config-authentication__item--icon">
|
||||
<%= inline_svg_tag("twitter.svg", class: "crayons-icon", aria: true, title: "Twitter logo") %>
|
||||
</figure>
|
||||
<div class="config-authentication__item--container">
|
||||
<div class="config-authentication__item--label">
|
||||
<p class="fw-medium">
|
||||
Twitter
|
||||
</p>
|
||||
</div>
|
||||
<div class="config-authentication__item--body">
|
||||
<fieldset class="config-authentication-form">
|
||||
<div class="crayons-field">
|
||||
<%= admin_config_label :twitter_key %>
|
||||
<p class="crayons-field__description">
|
||||
<%= Constants::SiteConfig::DETAILS[:twitter_key][:description] %>
|
||||
</p>
|
||||
<%= f.text_field :twitter_key,
|
||||
class: "crayons-textfield",
|
||||
value: SiteConfig.twitter_key,
|
||||
placeholder: Constants::SiteConfig::DETAILS[:twitter_key][:placeholder] %>
|
||||
</div>
|
||||
|
||||
<div class="crayons-field">
|
||||
<%= admin_config_label :twitter_secret %>
|
||||
<p class="crayons-field__description">
|
||||
<%= Constants::SiteConfig::DETAILS[:twitter_secret][:description] %>
|
||||
<p>
|
||||
<%= f.text_field :twitter_secret,
|
||||
class: "crayons-textfield",
|
||||
value: SiteConfig.twitter_secret,
|
||||
placeholder: Constants::SiteConfig::DETAILS[:twitter_secret][:placeholder] %>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
<section class="mb-6">
|
||||
<div class="form-group mb-0">
|
||||
<%= f.text_field :auth_providers_to_enable,
|
||||
id: "auth_providers_to_enable",
|
||||
class: "form-control hidden",
|
||||
value: SiteConfig.authentication_providers.join(","),
|
||||
readonly: true %>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="config-authentication__item">
|
||||
<figure class="config-authentication__item--icon">
|
||||
<%= inline_svg_tag("github.svg", class: "crayons-icon", aria: true, title: "Twitter logo") %>
|
||||
</figure>
|
||||
<div class="config-authentication__item--container">
|
||||
<div class="config-authentication__item--label">
|
||||
<p class="fw-medium">
|
||||
Github
|
||||
</p>
|
||||
</div>
|
||||
<div class="config-authentication__item--body">
|
||||
<fieldset class="config-authentication-form">
|
||||
<div class="crayons-field">
|
||||
<%= admin_config_label :github_key %>
|
||||
<p class="crayons-field__description">
|
||||
<%= Constants::SiteConfig::DETAILS[:github_key][:description] %>
|
||||
</p>
|
||||
<%= f.text_field :github_key,
|
||||
class: "crayons-textfield",
|
||||
value: SiteConfig.github_key,
|
||||
placeholder: Constants::SiteConfig::DETAILS[:github_key][:placeholder] %>
|
||||
|
||||
</div>
|
||||
<div class="crayons-field">
|
||||
<%= admin_config_label :github_secret %>
|
||||
<p class="config-authentication__row--subtitle">
|
||||
<%= Constants::SiteConfig::DETAILS[:github_secret][:description] %>
|
||||
</p>
|
||||
<%= f.text_field :github_secret,
|
||||
class: "crayons-textfield",
|
||||
value: SiteConfig.github_secret,
|
||||
placeholder: Constants::SiteConfig::DETAILS[:github_secret][:placeholder] %>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="config-authentication__item">
|
||||
<figure class="config-authentication__item--icon">
|
||||
<%= inline_svg_tag("facebook.svg", class: "crayons-icon", aria: true, title: "Twitter logo") %>
|
||||
</figure>
|
||||
<div class="config-authentication__item--container">
|
||||
<div class="config-authentication__item--label">
|
||||
<p class="fw-medium">
|
||||
Facebook
|
||||
</p>
|
||||
</div>
|
||||
<div class="config-authentication__item--body">
|
||||
<fieldset class="config-authentication-form">
|
||||
<div class="crayons-field">
|
||||
<%= admin_config_label :facebook_key %>
|
||||
<p class="crayons-field__description">
|
||||
<%= Constants::SiteConfig::DETAILS[:facebook_key][:description] %>
|
||||
</p>
|
||||
<%= f.text_field :facebook_key,
|
||||
class: "crayons-textfield",
|
||||
value: SiteConfig.facebook_key,
|
||||
placeholder: Constants::SiteConfig::DETAILS[:facebook_key][:placeholder] %>
|
||||
</div>
|
||||
|
||||
<div class="crayons-field">
|
||||
<%= admin_config_label :facebook_secret %>
|
||||
<p class="crayons-field__description">
|
||||
<%= Constants::SiteConfig::DETAILS[:facebook_secret][:description] %>
|
||||
<% authentication_available_providers.each do |provider| %>
|
||||
<section class="config-authentication__item mb-0">
|
||||
<figure class="config-authentication__item--icon">
|
||||
<%= inline_svg_tag("#{provider.provider_name}.svg", class: "crayons-icon", aria: true, title: "#{provider.official_name} logo") %>
|
||||
</figure>
|
||||
<div class="config-authentication__item--container">
|
||||
<div
|
||||
class="config-authentication__item mb-0 flex items-baseline justify-between <%= tooltip_class_on_auth_provider_enablebtn %>"
|
||||
data-tooltip="<%= tooltip_text_email_or_auth_provider_btns %>">
|
||||
<div class="config-authentication__item--label">
|
||||
<p class="crayons-field__label <%= authentication_enabled_providers.include?(provider) ? "pb-0" : "" %>">
|
||||
<%= provider.official_name %>
|
||||
</p>
|
||||
<%= f.text_field :facebook_secret,
|
||||
class: "crayons-textfield",
|
||||
value: SiteConfig.facebook_secret,
|
||||
placeholder: Constants::SiteConfig::DETAILS[:facebook_secret][:placeholder] %>
|
||||
<div
|
||||
id="<%= provider.provider_name %>-enabled-indicator"
|
||||
class="enabled-indicator-hidden <%= authentication_enabled_providers.include?(provider) ? "enabled-indicator-visible" : "" %>">
|
||||
<%= inline_svg_tag("checkmark.svg", aria: true, class: "crayons-icon admin-config-checkmark", title: "Checkmark") %>
|
||||
<small class="crayons-field__description ml-1">Enabled</small>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="crayons-btn crayons-btn--secondary"
|
||||
id="<%= provider.provider_name %>-auth-btn"
|
||||
data-button-text="<%= authentication_enabled_providers.include?(provider) ? "edit" : "enable" %>"
|
||||
data-action="click->config#enableOrEditAuthProvider"
|
||||
data-auth-provider-enable="<%= provider.provider_name %>"
|
||||
data-enable-auth="<%= authentication_enabled_providers.include?(provider) ? "true" : "false" %>"
|
||||
<%= disabled_attr_on_auth_provider_enablebtn %>>
|
||||
<%= authentication_enabled_providers.include?(provider) ? "Edit" : "Enable" %>
|
||||
</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
<div id="<%= provider.provider_name %>-auth-settings" class="config-authentication__item--body hidden">
|
||||
<fieldset class="config-authentication-form">
|
||||
<%= render partial: "auth_provider_settings",
|
||||
locals: {
|
||||
f: f,
|
||||
provider: provider
|
||||
} %>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<hr class="my-0" />
|
||||
<% end %>
|
||||
</section>
|
||||
</section>
|
||||
<div class="crayons-notice crayons-notice--info mb-4">
|
||||
|
|
|
|||
|
|
@ -28,6 +28,16 @@ RSpec.describe AuthenticationHelper, type: :helper do
|
|||
end
|
||||
end
|
||||
|
||||
describe "#available_providers_array" do
|
||||
it "returns array of available providers in lowercase" do
|
||||
provider = Authentication::Providers.available.first
|
||||
allow(Authentication::Providers).to receive(:available).and_return([provider])
|
||||
|
||||
expected_result = provider.to_s
|
||||
expect(helper.available_providers_array).to match_array([expected_result])
|
||||
end
|
||||
end
|
||||
|
||||
describe "#recaptcha_configured_and_enabled?" do
|
||||
context "when recaptcha is enabled" do
|
||||
before do
|
||||
|
|
@ -54,4 +64,55 @@ RSpec.describe AuthenticationHelper, type: :helper do
|
|||
expect(recaptcha_configured_and_enabled?).to be(false)
|
||||
end
|
||||
end
|
||||
|
||||
describe "tooltip classes, attributes and content" do
|
||||
context "when invite-only-mode enabled and no enabled auth providers" do
|
||||
before do
|
||||
allow(SiteConfig).to receive(:invite_only_mode).and_return(true)
|
||||
allow(SiteConfig).to receive(:authentication_providers).and_return([])
|
||||
end
|
||||
|
||||
it "returns 'crayons-tooltip' class for relevant helpers" do
|
||||
expect(tooltip_class_on_auth_provider_enablebtn).to eq("crayons-tooltip")
|
||||
expect(tooltip_class_on_email_auth_disablebtn).to eq("crayons-tooltip")
|
||||
end
|
||||
|
||||
it "returns 'disabled' attribute for relevant helper" do
|
||||
expect(disabled_attr_on_auth_provider_enablebtn).to eq("disabled")
|
||||
expect(disabled_attr_on_email_auth_disablebtn).to eq("disabled")
|
||||
end
|
||||
|
||||
it "returns appropriate text for 'tooltip_text_email_or_auth_provider_btns' helper" do
|
||||
invite_only_mode_warning = "You cannot do this until you disable Invite Only Mode"
|
||||
only_one_auth_method_warning = "You cannot do this until you enable at least one other registration option"
|
||||
|
||||
expect(tooltip_text_email_or_auth_provider_btns).to eq(invite_only_mode_warning)
|
||||
|
||||
allow(SiteConfig).to receive(:invite_only_mode).and_return(false)
|
||||
|
||||
expect(tooltip_text_email_or_auth_provider_btns).to eq(only_one_auth_method_warning)
|
||||
end
|
||||
end
|
||||
|
||||
context "when email login enabled and one enabled auth provider" do
|
||||
before do
|
||||
allow(SiteConfig).to receive(:allow_email_password_login).and_return(false)
|
||||
allow(SiteConfig).to receive(:authentication_providers).and_return(["facebook"])
|
||||
end
|
||||
|
||||
it "returns 'crayons-tooltip' class for relevant helpers" do
|
||||
expect(tooltip_class_on_auth_provider_disablebtn).to eq("crayons-tooltip")
|
||||
end
|
||||
|
||||
it "returns 'disabled' attribute for relevant helper" do
|
||||
expect(disabled_attr_on_auth_rpovider_disablebtn).to eq("disabled")
|
||||
end
|
||||
|
||||
it "returns appropriate text for 'tooltip_text_email_or_auth_provider_btns' helper" do
|
||||
only_one_auth_method_warning = "You cannot do this until you enable at least one other registration option"
|
||||
|
||||
expect(tooltip_text_email_or_auth_provider_btns).to eq(only_one_auth_method_warning)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -74,16 +74,16 @@ RSpec.describe "/admin/config", type: :request do
|
|||
|
||||
describe "Authentication" do
|
||||
it "updates enabled authentication providers" do
|
||||
enabled = Array.wrap(Authentication::Providers.available.first.to_s)
|
||||
post "/admin/config", params: { site_config: { authentication_providers: enabled },
|
||||
enabled = Authentication::Providers.available.first.to_s
|
||||
post "/admin/config", params: { site_config: { auth_providers_to_enable: enabled },
|
||||
confirmation: confirmation_message }
|
||||
expect(SiteConfig.authentication_providers).to eq(enabled)
|
||||
expect(SiteConfig.authentication_providers).to eq([enabled])
|
||||
end
|
||||
|
||||
it "strips empty elements" do
|
||||
provider = Authentication::Providers.available.first.to_s
|
||||
enabled = [provider, "", nil]
|
||||
post "/admin/config", params: { site_config: { authentication_providers: enabled },
|
||||
enabled = "#{provider}, '', nil"
|
||||
post "/admin/config", params: { site_config: { auth_providers_to_enable: enabled },
|
||||
confirmation: confirmation_message }
|
||||
expect(SiteConfig.authentication_providers).to eq([provider])
|
||||
end
|
||||
|
|
|
|||
|
|
@ -76,10 +76,11 @@ RSpec.describe "/admin/podcasts", type: :request do
|
|||
image: fixture_file_upload("files/podcast.png", "image/png"),
|
||||
slug: "postcast-test-url",
|
||||
reachable: true,
|
||||
published: true,
|
||||
published: true
|
||||
}
|
||||
end
|
||||
|
||||
# rubocop:disable RSpec/MultipleExpectations
|
||||
it "updates the podcast" do
|
||||
put admin_podcast_path(podcast), params: { podcast: update_params }
|
||||
podcast.reload
|
||||
|
|
@ -97,6 +98,7 @@ RSpec.describe "/admin/podcasts", type: :request do
|
|||
expect(podcast.reachable).to eq(true)
|
||||
expect(podcast.published).to eq(true)
|
||||
end
|
||||
# rubocop:enable RSpec/MultipleExpectations
|
||||
|
||||
it "updates image & pattern_image" do
|
||||
expect do
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ RSpec.describe "Creating Comment", type: :system, js: true do
|
|||
let(:runkit_comment) { compose_runkit_comment "comment 1" }
|
||||
let(:runkit_comment2) { compose_runkit_comment "comment 2" }
|
||||
|
||||
|
||||
# the article should be created before signing in
|
||||
let!(:article) { create(:article, user_id: user.id, show_comments: true) }
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue