updated the login flow for multiple enterprise

This commit is contained in:
irfanuddinahmad
2019-11-01 16:26:38 +05:00
parent 75031d765d
commit 8b5e8968ed
8 changed files with 205 additions and 6 deletions

View File

@@ -0,0 +1,79 @@
define([
'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers',
'js/student_account/multiple_enterprise',
'js/student_account/utils'
],
function(AjaxHelpers, MultipleEnterpriseInterface, Utils) {
'use strict';
describe('MultipleEnterpriseInterface', function() {
var LEARNER_URL = '/enterprise/api/v1/enterprise-learner/?username=test-learner',
NEXT_URL = '/dashboard',
REDIRECT_URL = '/enterprise/select/active/?success_url=/dashboard';
beforeEach(function() {
// Mock the redirect call
spyOn(MultipleEnterpriseInterface, 'redirect').and.callFake(function() {});
spyOn(Utils, 'userFromEdxUserCookie').and.returnValue({username: 'test-learner'});
});
it('gets learner information and checks redirect to enterprise selection page', function() {
// Spy on Ajax requests
var requests = AjaxHelpers.requests(this);
// Attempt to fetch a learner
MultipleEnterpriseInterface.check(NEXT_URL);
// Expect that the correct request was made to the server
AjaxHelpers.expectRequest(
requests,
'GET',
LEARNER_URL,
null
);
// Simulate a successful response from the server
AjaxHelpers.respondWithJson(requests, {count: 2});
// Verify that the user was redirected correctly
expect(MultipleEnterpriseInterface.redirect).toHaveBeenCalledWith(REDIRECT_URL);
});
it('gets learner information and checks that enterprise selection page is bypassed', function() {
// Spy on Ajax requests
var requests = AjaxHelpers.requests(this);
// Attempt to fetch a learner
MultipleEnterpriseInterface.check(NEXT_URL);
// Expect that the correct request was made to the server
AjaxHelpers.expectRequest(
requests,
'GET',
LEARNER_URL,
null
);
// Simulate a successful response from the server
AjaxHelpers.respondWithJson(requests, {count: 1});
// Verify that the user was redirected correctly
expect(MultipleEnterpriseInterface.redirect).toHaveBeenCalledWith(NEXT_URL);
});
it('correctly redirects the user if learner information call fails', function() {
// Spy on Ajax requests
var requests = AjaxHelpers.requests(this);
// Attempt to fetch a learner
MultipleEnterpriseInterface.check(NEXT_URL);
// Simulate an error response from the server
AjaxHelpers.respondWithError(requests);
// Verify that the user was redirected
expect(MultipleEnterpriseInterface.redirect).toHaveBeenCalledWith(NEXT_URL);
});
});
}
);

View File

@@ -0,0 +1,52 @@
(function(define) {
'use strict';
define(['jquery', 'js/student_account/utils', 'jquery.cookie'], function($, Utils) {
var MultipleEnterpriseInterface = {
urls: {
learners: '/enterprise/api/v1/enterprise-learner/',
multipleEnterpriseUrl: '/enterprise/select/active/?success_url='
},
headers: {
'X-CSRFToken': $.cookie('csrftoken')
},
/**
* Fetch the learner data, then redirect the user to a enterprise selection page if multiple
* enterprises were found.
* @param {string} nextUrl The URL to redirect to after multiple enterprise selection.
*/
check: function(nextUrl) {
var redirectUrl = this.urls.multipleEnterpriseUrl + encodeURI(nextUrl);
var username = Utils.userFromEdxUserCookie().username;
var next = nextUrl || '/';
$.ajax({
url: this.urls.learners + '?username=' + username,
type: 'GET',
contentType: 'application/json; charset=utf-8',
headers: this.headers,
context: this
}).fail(function() {
this.redirect(next);
}).done(function(response) {
if (response.count > 1 && redirectUrl) {
this.redirect(redirectUrl);
} else {
this.redirect(next);
}
});
},
/**
* Redirect to a URL.
* @param {string} url The URL to redirect to.
*/
redirect: function(url) {
window.location.href = url;
}
};
return MultipleEnterpriseInterface;
});
}).call(this, define || RequireJS.define);

View File

@@ -0,0 +1,28 @@
(function(define) {
'use strict';
define(['jquery'], function($) {
var userFromEdxUserCookie = function() {
var hostname = window.location.hostname;
var isLocalhost = hostname.indexOf('localhost') >= 0;
var isStage = hostname.indexOf('stage') >= 0;
var edxUserCookie, prefix, user;
if (isLocalhost) {
// localhost doesn't have prefixes
edxUserCookie = 'edx-user-info';
} else {
// does not take sandboxes into account
prefix = isStage ? 'stage' : 'prod';
edxUserCookie = prefix + '-edx-user-info';
}
// returns the user object from cookie. Replaces '054' with ',' and removes '\'
user = $.cookie(edxUserCookie).replace(/\\/g, '').replace(/054/g, ',');
user = user.substring(1, user.length - 1);
return JSON.parse(user);
};
return {
userFromEdxUserCookie: userFromEdxUserCookie
};
});
}).call(this, define || RequireJS.define);

View File

@@ -16,10 +16,12 @@
'js/student_account/views/InstitutionLoginView',
'js/student_account/views/HintedLoginView',
'edx-ui-toolkit/js/utils/html-utils',
'js/student_account/multiple_enterprise',
'js/vendor/history'
],
function($, utility, _, _s, Backbone, LoginModel, PasswordResetModel, RegisterModel, AccountRecoveryModel,
LoginView, PasswordResetView, RegisterView, InstitutionLoginView, HintedLoginView, HtmlUtils) {
LoginView, PasswordResetView, RegisterView, InstitutionLoginView, HintedLoginView, HtmlUtils,
multipleEnterpriseInterface) {
return Backbone.View.extend({
tpl: '#access-tpl',
events: {
@@ -43,7 +45,6 @@
* Underscore namespace
*/
_.mixin(_s.exports());
this.tpl = $(this.tpl).html();
this.activeForm = options.initial_mode || 'login';
@@ -70,7 +71,6 @@
institution_login: null,
hinted_login: null
};
this.platformName = options.platform_name;
this.supportURL = options.support_link;
this.passwordResetSupportUrl = options.password_reset_support_link;
@@ -79,6 +79,8 @@
this.pipelineUserDetails = options.third_party_auth.pipeline_user_details;
this.enterpriseName = options.enterprise_name || '';
this.isAccountRecoveryFeatureEnabled = options.is_account_recovery_feature_enabled || false;
this.isMultipleUserEnterprisesFeatureEnabled =
options.is_multiple_user_enterprises_feature_enabled || false;
// The login view listens for 'sync' events from the reset model
this.resetModel = new PasswordResetModel({}, {
@@ -158,7 +160,11 @@
this.listenTo(this.subview.login, 'password-help', this.resetPassword);
// Listen for 'auth-complete' event so we can enroll/redirect the user appropriately.
this.listenTo(this.subview.login, 'auth-complete', this.authComplete);
if (this.isMultipleUserEnterprisesFeatureEnabled === true) {
this.listenTo(this.subview.login, 'auth-complete', this.loginComplete);
} else {
this.listenTo(this.subview.login, 'auth-complete', this.authComplete);
}
},
reset: function(data) {
@@ -286,6 +292,20 @@
}
},
/**
/**
* Take a learner attached to multiple enterprises to the enterprise selection page:
*
*/
loginComplete: function() {
if (this.thirdPartyAuth && this.thirdPartyAuth.finishAuthUrl) {
multipleEnterpriseInterface.check(this.thirdPartyAuth.finishAuthUrl);
// Note: the third party auth URL likely contains another redirect URL embedded inside
} else {
multipleEnterpriseInterface.check(this.nextUrl);
}
},
/**
* Redirect to a URL. Mainly useful for mocking out in tests.
* @param {string} url The URL to redirect to.

View File

@@ -786,6 +786,7 @@
'js/spec/student_account/institution_login_spec.js',
'js/spec/student_account/login_spec.js',
'js/spec/student_account/logistration_factory_spec.js',
'js/spec/student_account/multiple_enterprise_spec.js',
'js/spec/student_account/password_reset_spec.js',
'js/spec/student_account/register_spec.js',
'js/spec/student_account/shoppingcart_spec.js',

View File

@@ -18,6 +18,10 @@ from six.moves.urllib.parse import urlparse # pylint: disable=import-error
from openedx.core.djangoapps.site_configuration.models import SiteConfiguration
from openedx.core.djangoapps.theming.helpers import get_config_value_from_site_or_settings, get_current_site
from openedx.core.djangoapps.user_api.config.waffle import (
ENABLE_MULTIPLE_USER_ENTERPRISES_FEATURE,
waffle as user_api_waffle
)
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.exceptions import ItemNotFoundError
@@ -214,3 +218,13 @@ def is_secondary_email_feature_enabled_for_user(user):
# import is placed here to avoid cyclic import.
from openedx.features.enterprise_support.utils import is_enterprise_learner
return is_secondary_email_feature_enabled() and is_enterprise_learner(user)
def is_multiple_user_enterprises_feature_enabled():
"""
Checks to see if the django-waffle switch for enabling the multiple user enterprises feature is active
Returns:
Boolean value representing switch status
"""
return user_api_waffle().is_enabled(ENABLE_MULTIPLE_USER_ENTERPRISES_FEATURE)

View File

@@ -12,6 +12,7 @@ WAFFLE_NAMESPACE = u'user_api'
# Switches
PREVENT_AUTH_USER_WRITES = u'prevent_auth_user_writes'
ENABLE_MULTIPLE_USER_ENTERPRISES_FEATURE = u'enable_multiple_user_enterprises_feature'
def waffle():

View File

@@ -17,7 +17,10 @@ from django.views.decorators.http import require_http_methods
import third_party_auth
from edxmako.shortcuts import render_to_response
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from openedx.core.djangoapps.user_api.accounts.utils import is_secondary_email_feature_enabled
from openedx.core.djangoapps.user_api.accounts.utils import (
is_secondary_email_feature_enabled,
is_multiple_user_enterprises_feature_enabled
)
from openedx.core.djangoapps.user_api.api import (
get_login_session_form,
)
@@ -124,7 +127,8 @@ def login_and_registration_form(request, initial_mode="login"):
'password_reset_form_desc': json.loads(form_descriptions['password_reset']),
'account_creation_allowed': configuration_helpers.get_value(
'ALLOW_PUBLIC_ACCOUNT_CREATION', settings.FEATURES.get('ALLOW_PUBLIC_ACCOUNT_CREATION', True)),
'is_account_recovery_feature_enabled': is_secondary_email_feature_enabled()
'is_account_recovery_feature_enabled': is_secondary_email_feature_enabled(),
'is_multiple_user_enterprises_feature_enabled': is_multiple_user_enterprises_feature_enabled()
},
'login_redirect_url': redirect_to, # This gets added to the query string of the "Sign In" button in header
'responsive': True,