diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/assets/javascripts/pages/admin/application_settings/account_and_limits.js | 25 | ||||
-rw-r--r-- | app/assets/javascripts/pages/admin/index.js | 6 | ||||
-rw-r--r-- | app/assets/javascripts/pages/admin/users/new/index.js | 49 | ||||
-rw-r--r-- | app/helpers/application_settings_helper.rb | 1 | ||||
-rw-r--r-- | app/helpers/users_helper.rb | 11 | ||||
-rw-r--r-- | app/models/application_setting.rb | 11 | ||||
-rw-r--r-- | app/services/users/build_service.rb | 12 | ||||
-rw-r--r-- | app/validators/js_regex_validator.rb | 15 | ||||
-rw-r--r-- | app/views/admin/application_settings/_account_and_limit.html.haml | 7 | ||||
-rw-r--r-- | app/views/admin/users/_access_levels.html.haml | 4 |
10 files changed, 140 insertions, 1 deletions
diff --git a/app/assets/javascripts/pages/admin/application_settings/account_and_limits.js b/app/assets/javascripts/pages/admin/application_settings/account_and_limits.js new file mode 100644 index 00000000000..7281f907ec7 --- /dev/null +++ b/app/assets/javascripts/pages/admin/application_settings/account_and_limits.js @@ -0,0 +1,25 @@ +import { __ } from '~/locale'; + +export const PLACEHOLDER_USER_EXTERNAL_DEFAULT_TRUE = __('Regex pattern'); +export const PLACEHOLDER_USER_EXTERNAL_DEFAULT_FALSE = __('To define internal users, first enable new users set to external'); + +function setUserInternalRegexPlaceholder(checkbox) { + const userInternalRegex = document.getElementById('application_setting_user_default_internal_regex'); + if (checkbox && userInternalRegex) { + if (checkbox.checked) { + userInternalRegex.readOnly = false; + userInternalRegex.placeholder = PLACEHOLDER_USER_EXTERNAL_DEFAULT_TRUE; + } else { + userInternalRegex.readOnly = true; + userInternalRegex.placeholder = PLACEHOLDER_USER_EXTERNAL_DEFAULT_FALSE; + } + } +} + +export default function initUserInternalRegexPlaceholder() { + const checkbox = document.getElementById('application_setting_user_default_external'); + setUserInternalRegexPlaceholder(checkbox); + checkbox.addEventListener('change', () => { + setUserInternalRegexPlaceholder(checkbox); + }); +} diff --git a/app/assets/javascripts/pages/admin/index.js b/app/assets/javascripts/pages/admin/index.js index e50b61f09e2..3aa793e47b9 100644 --- a/app/assets/javascripts/pages/admin/index.js +++ b/app/assets/javascripts/pages/admin/index.js @@ -1,3 +1,7 @@ import initAdmin from './admin'; +import initUserInternalRegexPlaceholder from './application_settings/account_and_limits'; -document.addEventListener('DOMContentLoaded', initAdmin); +document.addEventListener('DOMContentLoaded', () => { + initAdmin(); + initUserInternalRegexPlaceholder(); +}); diff --git a/app/assets/javascripts/pages/admin/users/new/index.js b/app/assets/javascripts/pages/admin/users/new/index.js new file mode 100644 index 00000000000..58bfa8d64e7 --- /dev/null +++ b/app/assets/javascripts/pages/admin/users/new/index.js @@ -0,0 +1,49 @@ +import $ from 'jquery'; + +export default class UserInternalRegexHandler { + constructor() { + this.regexPattern = $('[data-user-internal-regex-pattern]').data('user-internal-regex-pattern'); + if (this.regexPattern && this.regexPattern !== '') { + this.regexOptions = $('[data-user-internal-regex-options]').data('user-internal-regex-options'); + this.external = $('#user_external'); + this.warningMessage = $('#warning_external_automatically_set'); + this.addListenerToEmailField(); + this.addListenerToUserExternalCheckbox(); + } + } + + addListenerToEmailField() { + $('#user_email').on('input', (event) => { + this.setExternalCheckbox(event.currentTarget.value); + }); + } + + addListenerToUserExternalCheckbox() { + this.external.on('click', () => { + this.warningMessage.addClass('hidden'); + }); + } + + isEmailInternal(email) { + const regex = new RegExp(this.regexPattern, this.regexOptions); + return regex.test(email); + } + + setExternalCheckbox(email) { + const isChecked = this.external.prop('checked'); + if (this.isEmailInternal(email)) { + if (isChecked) { + this.external.prop('checked', false); + this.warningMessage.removeClass('hidden'); + } + } else if (!isChecked) { + this.external.prop('checked', true); + this.warningMessage.addClass('hidden'); + } + } +} + +document.addEventListener('DOMContentLoaded', () => { + // eslint-disable-next-line + new UserInternalRegexHandler(); +}); diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 1e05f07e676..684c84c3006 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -255,6 +255,7 @@ module ApplicationSettingsHelper :instance_statistics_visibility_private, :user_default_external, :user_show_add_ssh_key_message, + :user_default_internal_regex, :user_oauth_applications, :version_check_enabled, :web_ide_clientside_preview_enabled diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb index ceea4384f91..2c0c4254a0c 100644 --- a/app/helpers/users_helper.rb +++ b/app/helpers/users_helper.rb @@ -23,6 +23,17 @@ module UsersHelper profile_tabs.include?(tab) end + def user_internal_regex_data + settings = Gitlab::CurrentSettings.current_application_settings + + pattern, options = if settings.user_default_internal_regex_enabled? + regex = settings.user_default_internal_regex_instance + JsRegex.new(regex).to_h.slice(:source, :options).values + end + + { user_internal_regex_pattern: pattern, user_internal_regex_options: options } + end + def current_user_menu_items @current_user_menu_items ||= get_current_user_menu_items end diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index c77faa4b71d..03bd7fa016e 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -192,6 +192,8 @@ class ApplicationSetting < ActiveRecord::Base numericality: { less_than_or_equal_to: :gitaly_timeout_default }, if: :gitaly_timeout_default + validates :user_default_internal_regex, js_regex: true, allow_nil: true + SUPPORTED_KEY_TYPES.each do |type| validates :"#{type}_key_restriction", presence: true, key_restriction: { type: type } end @@ -299,6 +301,7 @@ class ApplicationSetting < ActiveRecord::Base usage_ping_enabled: Settings.gitlab['usage_ping_enabled'], instance_statistics_visibility_private: false, user_default_external: false, + user_default_internal_regex: nil, user_show_add_ssh_key_message: true } end @@ -435,6 +438,14 @@ class ApplicationSetting < ActiveRecord::Base password_authentication_enabled_for_web? || password_authentication_enabled_for_git? end + def user_default_internal_regex_enabled? + user_default_external? && user_default_internal_regex.present? + end + + def user_default_internal_regex_instance + Regexp.new(user_default_internal_regex, Regexp::IGNORECASE) + end + delegate :terms, to: :latest_terms, allow_nil: true def latest_terms @latest_terms ||= Term.latest diff --git a/app/services/users/build_service.rb b/app/services/users/build_service.rb index acc2fa153ae..9417c63c43a 100644 --- a/app/services/users/build_service.rb +++ b/app/services/users/build_service.rb @@ -2,6 +2,10 @@ module Users class BuildService < BaseService + delegate :user_default_internal_regex_enabled?, + :user_default_internal_regex_instance, + to: :'Gitlab::CurrentSettings.current_application_settings' + def initialize(current_user, params = {}) @current_user = current_user @params = params.dup @@ -89,6 +93,10 @@ module Users if params[:reset_password] user_params.merge!(force_random_password: true, password_expires_at: nil) end + + if user_default_internal_regex_enabled? && !user_params.key?(:external) + user_params[:external] = user_external? + end else allowed_signup_params = signup_params allowed_signup_params << :skip_confirmation if skip_authorization @@ -105,5 +113,9 @@ module Users def skip_user_confirmation_email_from_setting !Gitlab::CurrentSettings.send_user_confirmation_email end + + def user_external? + user_default_internal_regex_instance.match(params[:email]).nil? + end end end diff --git a/app/validators/js_regex_validator.rb b/app/validators/js_regex_validator.rb new file mode 100644 index 00000000000..a515af7b919 --- /dev/null +++ b/app/validators/js_regex_validator.rb @@ -0,0 +1,15 @@ +class JsRegexValidator < ActiveModel::EachValidator + def validate_each(record, attribute, value) + return true if value.blank? + + parsed_regex = JsRegex.new(Regexp.new(value, Regexp::IGNORECASE)) + + if parsed_regex.source.empty? + record.errors.add(attribute, "Regex Pattern #{value} can not be expressed in Javascript") + else + parsed_regex.warnings.each { |warning| record.errors.add(attribute, warning) } + end + rescue RegexpError => regex_error + record.errors.add(attribute, regex_error.to_s) + end +end diff --git a/app/views/admin/application_settings/_account_and_limit.html.haml b/app/views/admin/application_settings/_account_and_limit.html.haml index 622cb11010e..9121e44d31b 100644 --- a/app/views/admin/application_settings/_account_and_limit.html.haml +++ b/app/views/admin/application_settings/_account_and_limit.html.haml @@ -29,6 +29,13 @@ = f.check_box :user_default_external, class: 'form-check-input' = f.label :user_default_external, class: 'form-check-label' do Newly registered users will by default be external + .prepend-top-10 + = _('Internal users') + = f.text_field :user_default_internal_regex, placeholder: _('Regex pattern'), class: 'form-control prepend-top-5' + .help-block + = _('Specify an e-mail address regex pattern to identify default internal users.') + = link_to _('More information'), help_page_path('user/permissions', anchor: 'external-users-permissions'), + target: '_blank' .form-group = f.label :user_show_add_ssh_key_message, 'Prompt users to upload SSH keys', class: 'label-bold' .form-check diff --git a/app/views/admin/users/_access_levels.html.haml b/app/views/admin/users/_access_levels.html.haml index 5f68163163e..12e24ddef02 100644 --- a/app/views/admin/users/_access_levels.html.haml +++ b/app/views/admin/users/_access_levels.html.haml @@ -34,8 +34,12 @@ .form-group.row .col-sm-2.text-right = f.label :external, class: 'col-form-label' + .hidden{ data: user_internal_regex_data } .col-sm-10 = f.check_box :external do External %p.light External users cannot see internal or private projects unless access is explicitly granted. Also, external users cannot create projects or groups. + %row.hidden#warning_external_automatically_set.hidden + .badge.badge-warning.text-white + = _('Automatically marked as default internal user') |