diff --git a/config/routes.rb b/config/routes.rb index 5d20d070c207f9baea1c633391c17dc5be4877f7..a57795bea0cd5a6e5f25a41e4aa1c72febd3f2e7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -170,7 +170,6 @@ Gitlab.ee do draw :security draw :smartcard - draw :username draw :trial draw :trial_registration draw :country diff --git a/ee/app/assets/javascripts/pages/trial_registrations/new/index.js b/ee/app/assets/javascripts/pages/trial_registrations/new/index.js index ff1e0d56073bd9b08aeb2e68392f96c2b0b89583..421256440d7309cbf5e56222883aa8eeae2a24e3 100644 --- a/ee/app/assets/javascripts/pages/trial_registrations/new/index.js +++ b/ee/app/assets/javascripts/pages/trial_registrations/new/index.js @@ -5,12 +5,10 @@ import NoEmojiValidator from '~/emoji/no_emoji_validator'; import LengthValidator from '~/pages/sessions/new/length_validator'; import SigninTabsMemoizer from '~/pages/sessions/new/signin_tabs_memoizer'; import UsernameValidator from '~/pages/sessions/new/username_validator'; -import UsernameSuggester from 'ee/trial_registrations/username_suggester'; new UsernameValidator(); // eslint-disable-line no-new new LengthValidator(); // eslint-disable-line no-new new SigninTabsMemoizer(); // eslint-disable-line no-new new NoEmojiValidator(); // eslint-disable-line no-new -new UsernameSuggester('new_user_username', ['new_user_first_name', 'new_user_last_name']); // eslint-disable-line no-new trackFreeTrialAccountSubmissions(); diff --git a/ee/app/assets/javascripts/trial_registrations/username_suggester.js b/ee/app/assets/javascripts/trial_registrations/username_suggester.js deleted file mode 100644 index 64269e53f3ebf10f1eb773a21e238c4cdba5015d..0000000000000000000000000000000000000000 --- a/ee/app/assets/javascripts/trial_registrations/username_suggester.js +++ /dev/null @@ -1,95 +0,0 @@ -import { debounce } from 'lodash'; -import createFlash from '~/flash'; -import axios from '~/lib/utils/axios_utils'; -import { __ } from '~/locale'; - -const USERNAME_SUGGEST_DEBOUNCE_TIME = 300; - -export default class UsernameSuggester { - /** - * Creates an instance of UsernameSuggester. - * @param {string} targetElement target input element id for suggested username - * @param {string[]} sourceElementsIds array of HTML input element ids used for generating username - */ - constructor(targetElement, sourceElementsIds = []) { - if (!targetElement) { - throw new Error("Required argument 'targetElement' is missing"); - } - - this.usernameElement = document.getElementById(targetElement); - - if (!this.usernameElement) { - // eslint-disable-next-line @gitlab/require-i18n-strings - throw new Error('The target element is missing.'); - } - - this.apiPath = this.usernameElement.dataset.apiPath; - if (!this.apiPath) { - // eslint-disable-next-line @gitlab/require-i18n-strings - throw new Error('The API path was not specified.'); - } - - this.sourceElements = sourceElementsIds - .map((id) => document.getElementById(id)) - .filter(Boolean); - this.isLoading = false; - this.debouncedSuggestWrapper = debounce( - this.suggestUsername.bind(this), - USERNAME_SUGGEST_DEBOUNCE_TIME, - ); - - this.bindEvents(); - this.cleanupWrapper = this.cleanup.bind(this); - window.addEventListener('beforeunload', this.cleanupWrapper); - } - - bindEvents() { - this.sourceElements.forEach((sourceElement) => { - sourceElement.addEventListener('change', this.debouncedSuggestWrapper); - }); - } - - suggestUsername() { - if (this.isLoading) { - return; - } - - const name = this.joinSources(); - - if (!name) { - return; - } - - axios - .get(this.apiPath, { params: { name } }) - .then(({ data }) => { - this.usernameElement.value = data.username; - }) - .catch(() => { - createFlash({ - message: __('An error occurred while generating a username. Please try again.'), - }); - }) - .finally(() => { - this.isLoading = false; - }); - } - - /** - * Joins values from HTML input elements to a string separated by `_` (underscore). - */ - joinSources() { - return this.sourceElements - .map((el) => el.value) - .filter(Boolean) - .join('_'); - } - - cleanup() { - window.removeEventListener('beforeunload', this.cleanupWrapper); - - this.sourceElements.forEach((sourceElement) => - sourceElement.removeEventListener('change', this.debouncedSuggestWrapper), - ); - } -} diff --git a/ee/app/controllers/usernames_controller.rb b/ee/app/controllers/usernames_controller.rb deleted file mode 100644 index 6f220a5ab346c6c25513655e1fd05609c87f2487..0000000000000000000000000000000000000000 --- a/ee/app/controllers/usernames_controller.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -class UsernamesController < ApplicationController - skip_before_action :authenticate_user!, only: [:suggest] - - feature_category :users - - def suggest - if validate_params - username = ::User.username_suggestion(params[:name]) - - render json: { username: username }, status: :ok - else - render json: { message: 'Invalid input provided' }, status: :bad_request - end - end - - private - - def validate_params - !params[:name].blank? - end -end diff --git a/ee/app/helpers/ee/registrations_helper.rb b/ee/app/helpers/ee/registrations_helper.rb index 3e9c6a4a0e0425ba0bff836f37422908c98846c6..e291f2979aa2e3ff3443692a011e7948779dce83 100644 --- a/ee/app/helpers/ee/registrations_helper.rb +++ b/ee/app/helpers/ee/registrations_helper.rb @@ -3,12 +3,6 @@ module EE module RegistrationsHelper include ::Gitlab::Utils::StrongMemoize - extend ::Gitlab::Utils::Override - - override :signup_username_data_attributes - def signup_username_data_attributes - super.merge(api_path: suggestion_path) - end def shuffled_registration_objective_options options = registration_objective_options diff --git a/ee/app/models/ee/user.rb b/ee/app/models/ee/user.rb index 491f370f9ed1775dd9be575e02ac5af1560ce309..f08a49192248949af057138aba790e4bfe030783 100644 --- a/ee/app/models/ee/user.rb +++ b/ee/app/models/ee/user.rb @@ -13,7 +13,6 @@ module User DEFAULT_ROADMAP_LAYOUT = 'months' DEFAULT_GROUP_VIEW = 'details' - MAX_USERNAME_SUGGESTION_ATTEMPTS = 15 prepended do include UsageStatistics @@ -141,19 +140,6 @@ def find_by_smartcard_identity(certificate_subject, certificate_issuer) .find_by(smartcard_identities: { subject: certificate_subject, issuer: certificate_issuer }) end - def username_suggestion(base_name) - suffix = nil - base_name = base_name.parameterize(separator: '_') - MAX_USERNAME_SUGGESTION_ATTEMPTS.times do |attempt| - username = "#{base_name}#{suffix}" - return username unless ::Namespace.find_by_path_or_name(username) - - suffix = attempt + 1 - end - - '' - end - # Limits the users to those who have an identity that belongs to # the given SAML Provider def limit_to_saml_provider(saml_provider_id) diff --git a/ee/config/routes/username.rb b/ee/config/routes/username.rb deleted file mode 100644 index 38a4152fbeac8f70aa379bec3d1276dc3a63c1f3..0000000000000000000000000000000000000000 --- a/ee/config/routes/username.rb +++ /dev/null @@ -1,5 +0,0 @@ -# frozen_string_literal: true - -scope :username do - get 'suggestion', to: 'usernames#suggest' -end diff --git a/ee/spec/controllers/usernames_controller_spec.rb b/ee/spec/controllers/usernames_controller_spec.rb deleted file mode 100644 index dbeee569f54c97da87c2ff577d774ca43b62122c..0000000000000000000000000000000000000000 --- a/ee/spec/controllers/usernames_controller_spec.rb +++ /dev/null @@ -1,37 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe UsernamesController do - describe 'GET #suggest' do - context 'namespace does not exist' do - it 'returns JSON with the suggested username' do - get :suggest, params: { name: 'Arthur' } - - expected_json = { username: 'arthur' }.to_json - expect(response.body).to eq(expected_json) - end - end - - context 'namespace exists' do - before do - create(:user, name: 'disney') - end - - it 'returns JSON with the parameterized username and suffix as a suggestion' do - get :suggest, params: { name: 'Disney' } - - expected_json = { username: 'disney1' }.to_json - expect(response.body).to eq(expected_json) - end - end - - context 'no name provided' do - it 'returns bad request response' do - get :suggest - - expect(response).to have_gitlab_http_status(:bad_request) - end - end - end -end diff --git a/ee/spec/features/trial_registrations/signup_spec.rb b/ee/spec/features/trial_registrations/signup_spec.rb index ee36cf7c708d794cea2112389eef0a62aa5d9a79..5a4e6ca0da9838668d129a7dd91b7d91fd57ef80 100644 --- a/ee/spec/features/trial_registrations/signup_spec.rb +++ b/ee/spec/features/trial_registrations/signup_spec.rb @@ -50,28 +50,5 @@ expect(page).to have_content('Start your Free Ultimate Trial') end end - - context 'entering', :js do - using RSpec::Parameterized::TableSyntax - - where(:case_name, :first_name, :last_name, :suggested_username) do - 'first name' | 'foobar' | nil | 'foobar' - 'last name' | nil | 'foobar' | 'foobar' - 'first name and last name' | 'foo' | 'bar' | 'foo_bar' - end - - with_them do - it 'suggests the username' do - visit new_trial_registration_path - click_on 'Continue' - - fill_in 'new_user_first_name', with: first_name if first_name - fill_in 'new_user_last_name', with: last_name if last_name - find('body').click - - expect(page).to have_field('new_user_username', with: suggested_username) - end - end - end end end diff --git a/ee/spec/frontend/trial_registrations/username_suggester_spec.js b/ee/spec/frontend/trial_registrations/username_suggester_spec.js deleted file mode 100644 index 725646b4cfef188e6fe952dc0703cd0918882421..0000000000000000000000000000000000000000 --- a/ee/spec/frontend/trial_registrations/username_suggester_spec.js +++ /dev/null @@ -1,159 +0,0 @@ -import MockAdapter from 'axios-mock-adapter'; -import UsernameSuggester from 'ee/trial_registrations/username_suggester'; -import { setHTMLFixture } from 'helpers/fixtures'; -import axios from '~/lib/utils/axios_utils'; - -describe('UsernameSuggester', () => { - let axiosMock; - let suggester; - let firstName; - let lastName; - let username; - const usernameEndPoint = '/-/username'; - const expectedUsername = 'foo_bar'; - - const setupSuggester = (dstElement, srcElementIds) => { - suggester = new UsernameSuggester(dstElement, srcElementIds); - }; - - beforeEach(() => { - setHTMLFixture(` - <div class="flash-container"></div> - <input type="text" id="first_name"> - <input type="text" id="last_name"> - - <input type="text" id="username" data-api-path="${usernameEndPoint}"> - `); - firstName = document.getElementById('first_name'); - lastName = document.getElementById('last_name'); - username = document.getElementById('username'); - }); - describe('constructor', () => { - it('sets isLoading to false', () => { - setupSuggester('username', ['first_name']); - - expect(suggester.isLoading).toBe(false); - }); - - it(`sets the apiPath to ${usernameEndPoint}`, () => { - setupSuggester('username', ['first_name']); - - expect(suggester.apiPath).toBe(usernameEndPoint); - }); - - it('throws an error if target element is missing', () => { - expect(() => { - setupSuggester('id_with_that_id_does_not_exist', ['first_name']); - }).toThrow('The target element is missing.'); - }); - - it('throws an error if api path is missing', () => { - setHTMLFixture(` - <input type="text" id="first_name"> - <input type="text" id="last_name"> - - <input type="text" id="username"> - `); - - expect(() => { - setupSuggester('username', ['first_name']); - }).toThrow('The API path was not specified.'); - }); - - it('throws an error when no arguments were provided', () => { - expect(() => { - setupSuggester(); - }).toThrow("Required argument 'targetElement' is missing"); - }); - }); - - describe('joinSources', () => { - it('does not add `_` (underscore) with the only input specified', () => { - setupSuggester('username', ['first_name']); - - firstName.value = 'foo'; - - const name = suggester.joinSources(); - - expect(name).toBe('foo'); - }); - - it('joins values from multiple inputs specified by `_` (underscore)', () => { - setupSuggester('username', ['first_name', 'last_name']); - - firstName.value = 'foo'; - lastName.value = 'bar'; - - const name = suggester.joinSources(); - - expect(name).toBe(expectedUsername); - }); - - it('returns an empty string if 0 inputs specified', () => { - setupSuggester('username', []); - - const name = suggester.joinSources(); - - expect(name).toBe(''); - }); - }); - - describe('suggestUsername', () => { - beforeEach(() => { - axiosMock = new MockAdapter(axios); - setupSuggester('username', ['first_name', 'last_name']); - }); - - afterEach(() => { - axiosMock.restore(); - }); - - it('does not suggests username if suggester is already running', () => { - suggester.isLoading = true; - - expect(axiosMock.history.get).toHaveLength(0); - expect(username).toHaveValue(''); - }); - - it('suggests username successfully', () => { - axiosMock - .onGet(usernameEndPoint, { param: { name: expectedUsername } }) - .reply(200, { username: expectedUsername }); - - expect(suggester.isLoading).toBe(false); - - firstName.value = 'foo'; - lastName.value = 'bar'; - - suggester.suggestUsername(); - - setImmediate(() => { - expect(axiosMock.history.get).toHaveLength(1); - expect(suggester.isLoading).toBe(false); - expect(username).toHaveValue(expectedUsername); - }); - }); - - it('shows a flash message if request fails', (done) => { - axiosMock.onGet(usernameEndPoint).replyOnce(500); - - expect(suggester.isLoading).toBe(false); - - firstName.value = 'foo'; - lastName.value = 'bar'; - - suggester.suggestUsername(); - - setImmediate(() => { - expect(axiosMock.history.get).toHaveLength(1); - expect(suggester.isLoading).toBe(false); - expect(username).toHaveValue(''); - expect(document.querySelector('.flash-container .flash-text').innerText.trim()).toBe( - 'An error occurred while generating a username. Please try again.', - ); - - done(); - }); - }); - }); -}); diff --git a/ee/spec/helpers/ee/registrations_helper_spec.rb b/ee/spec/helpers/ee/registrations_helper_spec.rb index 332dd550a5f8a1d98952ef714a53c611166c9b89..bc79941003caa8788301a7a599e89e9d42963d03 100644 --- a/ee/spec/helpers/ee/registrations_helper_spec.rb +++ b/ee/spec/helpers/ee/registrations_helper_spec.rb @@ -5,12 +5,6 @@ RSpec.describe EE::RegistrationsHelper do include Devise::Test::ControllerHelpers - describe '#signup_username_data_attributes' do - it 'has expected attributes' do - expect(helper.signup_username_data_attributes.keys).to include(:api_path) - end - end - describe '#shuffled_registration_objective_options' do subject(:shuffled_options) { helper.shuffled_registration_objective_options } diff --git a/ee/spec/models/ee/user_spec.rb b/ee/spec/models/ee/user_spec.rb index c898f7da14ec90fecd96ed9a38ad66459fb42a87..fa46d8aed68fccedfd935a6b0bfafeaa81ba7dcf 100644 --- a/ee/spec/models/ee/user_spec.rb +++ b/ee/spec/models/ee/user_spec.rb @@ -1202,63 +1202,6 @@ end end - describe '.username_suggestion' do - context 'namespace with input name does not exist' do - let(:name) { 'Arthur Morgan' } - - it 'returns the parameterized name' do - username = described_class.username_suggestion(name) - - expect(username).to eq('arthur_morgan') - end - end - - context 'namespace with input name exists' do - let(:name) { 'Disney' } - - before do - create(:user, name: 'disney') - end - - it 'returns the parameterized name with a suffix' do - username = described_class.username_suggestion(name) - - expect(username).to eq('disney1') - end - end - - context 'namespace with input name and suffix exists' do - let(:name) { 'Disney' } - - before do - create(:user, name: 'disney') - create(:user, name: 'disney1') - end - - it 'loops through parameterized name with suffixes, until it finds one that does not exist' do - username = described_class.username_suggestion(name) - - expect(username).to eq('disney2') - end - end - - context 'when max attempts for suggestion is exceeded' do - let(:name) { 'Disney' } - let(:max_attempts) { described_class::MAX_USERNAME_SUGGESTION_ATTEMPTS } - - before do - allow(::Namespace).to receive(:find_by_path_or_name).with("disney").and_return(true) - max_attempts.times { |count| allow(::Namespace).to receive(:find_by_path_or_name).with("disney#{count}").and_return(true) } - end - - it 'returns an empty response' do - username = described_class.username_suggestion(name) - - expect(username).to eq('') - end - end - end - describe '#manageable_groups_eligible_for_trial', :saas do let_it_be(:user) { create :user } let_it_be(:non_trialed_group_z) { create :group_with_plan, name: 'Zeta', plan: :free_plan } diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 7a5af14a1bae5a20f2911735174cf7d1aa4ec2f1..3a484f28bd4b0700ed1ac3cbdefcb466dfc72cb8 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -3815,9 +3815,6 @@ msgstr "" msgid "An error occurred while fetching this tab." msgstr "" -msgid "An error occurred while generating a username. Please try again." -msgstr "" - msgid "An error occurred while getting autocomplete data. Please refresh the page and try again." msgstr ""