Commit c49c4c8c authored by Alex Pooley's avatar Alex Pooley

Merge branch 'exit-registration-verification' into 'master'

Exit registration verification

See merge request gitlab-org/gitlab!80286
parents c2c3949a 95ea4682
---
name: exit_registration_verification
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/80286
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/352397
milestone: '14.8'
type: development
group: group::activation
default_enabled: false
...@@ -69,7 +69,10 @@ Rails.application.routes.draw do ...@@ -69,7 +69,10 @@ Rails.application.routes.draw do
resources :groups, only: [:new, :create] resources :groups, only: [:new, :create]
resources :projects, only: [:new, :create] resources :projects, only: [:new, :create]
resources :groups_projects, only: [:new, :create] do resources :groups_projects, only: [:new, :create] do
post :import, on: :collection collection do
post :import
put :exit
end
end end
draw :verification draw :verification
end end
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
import { GlButton } from '@gitlab/ui'; import { GlButton } from '@gitlab/ui';
import Zuora from 'ee/billings/components/zuora.vue'; import Zuora from 'ee/billings/components/zuora.vue';
import { I18N, IFRAME_MINIMUM_HEIGHT } from '../constants'; import { I18N, IFRAME_MINIMUM_HEIGHT } from '../constants';
import eventHub from '../event_hub';
import StaticToggle from './static_toggle.vue'; import StaticToggle from './static_toggle.vue';
export default { export default {
...@@ -18,6 +19,7 @@ export default { ...@@ -18,6 +19,7 @@ export default {
}, },
watch: { watch: {
verificationCompleted() { verificationCompleted() {
eventHub.$emit('verificationCompleted');
this.toggleProjectCreation(); this.toggleProjectCreation();
}, },
}, },
......
<script>
import { GlButton } from '@gitlab/ui';
import { __, s__ } from '~/locale';
import eventHub from '../event_hub';
export default {
components: {
GlButton,
},
inject: ['exitPath'],
data() {
return {
showLink: true,
disabled: false,
};
},
created() {
eventHub.$on('verificationCompleted', this.toggleLink);
},
beforeDestroy() {
eventHub.$off('verificationCompleted', this.toggleLink);
},
methods: {
toggleLink() {
this.showLink = false;
},
disableLink() {
this.disabled = true;
},
},
i18n: {
link: __('Exit.'),
explanation: s__(
'IdentityVerification|You can always verify your account at a later time to create a group.',
),
},
};
</script>
<template>
<div v-if="showLink" class="gl-text-center">
<div class="gl-pt-6 gl-pb-3">
<gl-button
data-testid="exit-link"
variant="link"
:disabled="disabled"
:aria-label="$options.i18n.link"
:href="exitPath"
data-method="put"
rel="nofollow"
@click="disableLink"
>
{{ $options.i18n.link }}
</gl-button>
</div>
<div class="gl-text-secondary gl-font-sm">
{{ $options.i18n.explanation }}
</div>
</div>
</template>
import eventHubFactory from '~/helpers/event_hub_factory';
export default eventHubFactory();
...@@ -6,6 +6,7 @@ import { bindHowToImport } from '~/projects/project_new'; ...@@ -6,6 +6,7 @@ import { bindHowToImport } from '~/projects/project_new';
import { displayGroupPath, displayProjectPath } from './path_display'; import { displayGroupPath, displayProjectPath } from './path_display';
import showTooltip from './show_tooltip'; import showTooltip from './show_tooltip';
import CreditCardVerification from './components/credit_card_verification.vue'; import CreditCardVerification from './components/credit_card_verification.vue';
import ExitLink from './components/exit_link.vue';
const importButtonsSubmit = () => { const importButtonsSubmit = () => {
const buttons = document.querySelectorAll('.js-import-project-buttons a'); const buttons = document.querySelectorAll('.js-import-project-buttons a');
...@@ -58,6 +59,26 @@ const mountVerification = () => { ...@@ -58,6 +59,26 @@ const mountVerification = () => {
}); });
}; };
const mountExitLink = () => {
const el = document.querySelector('.js-exit-registration-verification');
if (!el) {
return null;
}
const { exitPath } = el.dataset;
return new Vue({
el,
provide: {
exitPath,
},
render(createElement) {
return createElement(ExitLink);
},
});
};
export default () => { export default () => {
displayGroupPath('.js-group-path-source', '.js-group-path-display'); displayGroupPath('.js-group-path-source', '.js-group-path-display');
displayGroupPath('.js-import-group-path-source', '.js-import-group-path-display'); displayGroupPath('.js-import-group-path-source', '.js-import-group-path-display');
...@@ -67,4 +88,5 @@ export default () => { ...@@ -67,4 +88,5 @@ export default () => {
bindHowToImport(); bindHowToImport();
setAutofocus(); setAutofocus();
mountVerification(); mountVerification();
mountExitLink();
}; };
...@@ -82,6 +82,16 @@ module Registrations ...@@ -82,6 +82,16 @@ module Registrations
end end
end end
def exit
return not_found unless Feature.enabled?(:exit_registration_verification)
if current_user.requires_credit_card_verification
::Users::UpdateService.new(current_user, user: current_user, requires_credit_card_verification: false).execute!
end
redirect_to root_url
end
private private
def combined_registration_experiment def combined_registration_experiment
......
...@@ -108,3 +108,5 @@ ...@@ -108,3 +108,5 @@
.nothing-here-block .nothing-here-block
%h4= s_('ProjectsNew|No import options available') %h4= s_('ProjectsNew|No import options available')
%p= s_('ProjectsNew|Contact an administrator to enable options for importing your project.') %p= s_('ProjectsNew|Contact an administrator to enable options for importing your project.')
- if verify && Feature.enabled?(:exit_registration_verification, default_enabled: :yaml) && current_user.requires_credit_card_verification
.js-exit-registration-verification{ data: { exit_path: exit_users_sign_up_groups_projects_path } }
...@@ -398,4 +398,39 @@ RSpec.describe Registrations::GroupsProjectsController, :experiment do ...@@ -398,4 +398,39 @@ RSpec.describe Registrations::GroupsProjectsController, :experiment do
end end
end end
end end
describe 'PUT #exit' do
subject(:put_exit) { put :exit }
context 'with an unauthenticated user' do
it { is_expected.to have_gitlab_http_status(:redirect) }
it { is_expected.to redirect_to(new_user_session_path) }
end
context 'with an authenticated user' do
before do
sign_in(user)
allow(::Gitlab).to receive(:dev_env_or_com?).and_return(true)
end
it { is_expected.to have_gitlab_http_status(:redirect) }
it { is_expected.to redirect_to(root_url) }
context 'when requires_credit_card_verification is true' do
let_it_be(:user) { create(:user, requires_credit_card_verification: true) }
it 'sets requires_credit_card_verification to false' do
expect { put_exit }.to change { user.reload.requires_credit_card_verification }.to(false)
end
end
context 'when the `exit_registration_verification` feature flag is disabled' do
before do
stub_feature_flags(exit_registration_verification: false)
end
it { is_expected.to have_gitlab_http_status(:not_found) }
end
end
end
end end
...@@ -73,5 +73,20 @@ RSpec.describe 'Combined registration flow', :js do ...@@ -73,5 +73,20 @@ RSpec.describe 'Combined registration flow', :js do
expect(page).to have_content('To connect GitHub repositories, you first need to authorize GitLab to access the list of your GitHub repositories.') expect(page).to have_content('To connect GitHub repositories, you first need to authorize GitLab to access the list of your GitHub repositories.')
end end
describe 'exiting onboarding' do
it 'does not show a link to exit the page' do
expect(page).not_to have_link('Exit.')
end
context 'when require_verification_for_namespace_creation experiment is enabled' do
let(:experiments) { { combined_registration: :candidate, require_verification_for_namespace_creation: :candidate } }
it 'shows a link to exit the page' do
expect(page).to have_link('Exit.', href: exit_users_sign_up_groups_projects_path)
expect(page).to have_content('You can always verify your account at a later time to create a group.')
end
end
end
end end
end end
...@@ -3,10 +3,12 @@ import { GlButton } from '@gitlab/ui'; ...@@ -3,10 +3,12 @@ import { GlButton } from '@gitlab/ui';
import CreditCardVerification from 'ee/registrations/groups_projects/new/components/credit_card_verification.vue'; import CreditCardVerification from 'ee/registrations/groups_projects/new/components/credit_card_verification.vue';
import { IFRAME_MINIMUM_HEIGHT } from 'ee/registrations/groups_projects/new/constants'; import { IFRAME_MINIMUM_HEIGHT } from 'ee/registrations/groups_projects/new/constants';
import { setHTMLFixture } from 'helpers/fixtures'; import { setHTMLFixture } from 'helpers/fixtures';
import eventHub from 'ee/registrations/groups_projects/new/event_hub';
describe('CreditCardVerification', () => { describe('CreditCardVerification', () => {
let wrapper; let wrapper;
let zuoraSubmitSpy; let zuoraSubmitSpy;
let eventHubSpy;
const IFRAME_URL = 'https://customers.gitlab.com/payment_forms/cc_registration_validation'; const IFRAME_URL = 'https://customers.gitlab.com/payment_forms/cc_registration_validation';
const ALLOWED_ORIGIN = 'https://customers.gitlab.com'; const ALLOWED_ORIGIN = 'https://customers.gitlab.com';
...@@ -95,6 +97,7 @@ describe('CreditCardVerification', () => { ...@@ -95,6 +97,7 @@ describe('CreditCardVerification', () => {
describe('when the Zuora component emits a success event', () => { describe('when the Zuora component emits a success event', () => {
beforeEach(() => { beforeEach(() => {
eventHubSpy = jest.spyOn(eventHub, '$emit');
findZuora().vm.$emit('success'); findZuora().vm.$emit('success');
}); });
...@@ -110,5 +113,9 @@ describe('CreditCardVerification', () => { ...@@ -110,5 +113,9 @@ describe('CreditCardVerification', () => {
it('hides the Zuora component', () => { it('hides the Zuora component', () => {
expect(findZuora().exists()).toBe(false); expect(findZuora().exists()).toBe(false);
}); });
it('emits the verificationCompleted event', () => {
expect(eventHubSpy).toHaveBeenCalledWith('verificationCompleted');
});
}); });
}); });
import { shallowMount } from '@vue/test-utils';
import ExitLink from 'ee/registrations/groups_projects/new/components/exit_link.vue';
import eventHub from 'ee/registrations/groups_projects/new/event_hub';
describe('ExitLink', () => {
let wrapper;
const EXIT_PATH = '/users/sign_up/groups_projects/exit';
const findLink = () => wrapper.find('[data-testid="exit-link"]');
const createComponent = () => {
wrapper = shallowMount(ExitLink, {
provide: {
exitPath: EXIT_PATH,
},
});
};
beforeEach(() => {
createComponent();
});
afterEach(() => {
wrapper.destroy();
});
describe('when the component is mounted', () => {
it('displays a link', () => {
expect(findLink().exists()).toBe(true);
expect(findLink().attributes('href')).toBe(EXIT_PATH);
});
});
describe('when the link is clicked', () => {
beforeEach(() => {
findLink().vm.$emit('click');
});
it('disables the link', () => {
expect(findLink().attributes('disabled')).toBe('true');
});
});
describe('when the `verificationCompleted` event is emitted', () => {
beforeEach(() => {
eventHub.$emit('verificationCompleted');
});
it('hides the link', () => {
expect(findLink().exists()).toBe(false);
});
});
});
...@@ -14670,6 +14670,9 @@ msgstr "" ...@@ -14670,6 +14670,9 @@ msgstr ""
msgid "Existing sign in methods may be removed" msgid "Existing sign in methods may be removed"
msgstr "" msgstr ""
msgid "Exit."
msgstr ""
msgid "Expand" msgid "Expand"
msgstr "" msgstr ""
...@@ -18275,6 +18278,9 @@ msgstr "" ...@@ -18275,6 +18278,9 @@ msgstr ""
msgid "IdentityVerification|Verify your identity" msgid "IdentityVerification|Verify your identity"
msgstr "" msgstr ""
msgid "IdentityVerification|You can always verify your account at a later time to create a group."
msgstr ""
msgid "If any indexed field exceeds this limit, it is truncated to this number of characters. The rest of the content is neither indexed nor searchable. This does not apply to repository and wiki indexing. For unlimited characters, set this to 0." msgid "If any indexed field exceeds this limit, it is truncated to this number of characters. The rest of the content is neither indexed nor searchable. This does not apply to repository and wiki indexing. For unlimited characters, set this to 0."
msgstr "" msgstr ""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment