Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
cf308d87
Commit
cf308d87
authored
Jun 08, 2015
by
Braden MacDonald
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
New Hinted Login View - PR 8591
parent
7437bcfe
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
254 additions
and
4 deletions
+254
-4
common/test/acceptance/pages/lms/fields.py
+9
-0
common/test/acceptance/pages/lms/login_and_register.py
+8
-0
common/test/acceptance/tests/lms/test_lms.py
+35
-1
lms/djangoapps/student_account/test/test_views.py
+5
-0
lms/djangoapps/student_account/views.py
+15
-0
lms/envs/common.py
+1
-0
lms/static/js/spec/main.js
+11
-0
lms/static/js/spec/student_account/hinted_login_spec.js
+71
-0
lms/static/js/student_account/accessApp.js
+1
-0
lms/static/js/student_account/views/AccessView.js
+16
-2
lms/static/js/student_account/views/HintedLoginView.js
+52
-0
lms/templates/student_account/access.underscore
+4
-0
lms/templates/student_account/hinted_login.underscore
+24
-0
lms/templates/student_account/login_and_register.html
+2
-1
No files found.
common/test/acceptance/pages/lms/fields.py
View file @
cf308d87
...
...
@@ -211,6 +211,15 @@ class FieldsMixin(object):
query
=
self
.
q
(
css
=
'.u-field-link-title-{}'
.
format
(
field_id
))
return
query
.
text
[
0
]
if
query
.
present
else
None
def
wait_for_link_title_for_link_field
(
self
,
field_id
,
expected_title
):
"""
Wait until the title of the specified link field equals expected_title.
"""
return
EmptyPromise
(
lambda
:
self
.
link_title_for_link_field
(
field_id
)
==
expected_title
,
"Link field with link title
\"
{0}
\"
is visible."
.
format
(
expected_title
)
)
.
fulfill
()
def
click_on_link_in_link_field
(
self
,
field_id
):
"""
Click the link in a link field.
...
...
common/test/acceptance/pages/lms/login_and_register.py
View file @
cf308d87
...
...
@@ -281,6 +281,8 @@ class CombinedLoginAndRegisterPage(PageObject):
return
"login"
elif
self
.
q
(
css
=
".js-reset"
)
.
visible
:
return
"password-reset"
elif
self
.
q
(
css
=
".proceed-button"
)
.
visible
:
return
"hinted-login"
@property
def
email_value
(
self
):
...
...
@@ -335,3 +337,9 @@ class CombinedLoginAndRegisterPage(PageObject):
return
(
True
,
msg_element
.
text
[
0
])
return
(
False
,
None
)
return
Promise
(
_check_func
,
"Result of third party auth is visible"
)
.
fulfill
()
@property
def
hinted_login_prompt
(
self
):
"""Get the message displayed to the user on the hinted-login form"""
if
self
.
q
(
css
=
".wrapper-other-login .instructions"
)
.
visible
:
return
self
.
q
(
css
=
".wrapper-other-login .instructions"
)
.
text
[
0
]
common/test/acceptance/tests/lms/test_lms.py
View file @
cf308d87
...
...
@@ -164,7 +164,41 @@ class LoginFromCombinedPageTest(UniqueCourseTest):
self
.
dashboard_page
.
wait_for_page
()
# Now unlink the account (To test the account settings view and also to prevent cross-test side effects)
self
.
_unlink_dummy_account
()
def
test_hinted_login
(
self
):
""" Test the login page when coming from course URL that specified which third party provider to use """
# Create a user account and link it to third party auth with the dummy provider:
AutoAuthPage
(
self
.
browser
,
course_id
=
self
.
course_id
)
.
visit
()
self
.
_link_dummy_account
()
LogoutPage
(
self
.
browser
)
.
visit
()
# When not logged in, try to load a course URL that includes the provider hint ?tpa_hint=...
course_page
=
CoursewarePage
(
self
.
browser
,
self
.
course_id
)
self
.
browser
.
get
(
course_page
.
url
+
'?tpa_hint=oa2-dummy'
)
# We should now be redirected to the login page
self
.
login_page
.
wait_for_page
()
self
.
assertIn
(
"Would you like to sign in using your Dummy credentials?"
,
self
.
login_page
.
hinted_login_prompt
)
self
.
login_page
.
click_third_party_dummy_provider
()
# We should now be redirected to the course page
course_page
.
wait_for_page
()
self
.
_unlink_dummy_account
()
def
_link_dummy_account
(
self
):
""" Go to Account Settings page and link the user's account to the Dummy provider """
account_settings
=
AccountSettingsPage
(
self
.
browser
)
.
visit
()
field_id
=
"auth-oa2-dummy"
account_settings
.
wait_for_field
(
field_id
)
self
.
assertEqual
(
"Link"
,
account_settings
.
link_title_for_link_field
(
field_id
))
account_settings
.
click_on_link_in_link_field
(
field_id
)
account_settings
.
wait_for_link_title_for_link_field
(
field_id
,
"Unlink"
)
def
_unlink_dummy_account
(
self
):
""" Verify that the 'Dummy' third party auth provider is linked, then unlink it """
# This must be done after linking the account, or we'll get cross-test side effects
account_settings
=
AccountSettingsPage
(
self
.
browser
)
.
visit
()
field_id
=
"auth-oa2-dummy"
account_settings
.
wait_for_field
(
field_id
)
...
...
lms/djangoapps/student_account/test/test_views.py
View file @
cf308d87
...
...
@@ -329,6 +329,11 @@ class StudentAccountLoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMi
]
self
.
_assert_third_party_auth_data
(
response
,
current_backend
,
current_provider
,
expected_providers
)
def
test_hinted_login
(
self
):
params
=
[(
"next"
,
"/courses/something/?tpa_hint=oa2-google-oauth2"
)]
response
=
self
.
client
.
get
(
reverse
(
'account_login'
),
params
)
self
.
assertContains
(
response
,
"data-third-party-auth-hint='oa2-google-oauth2'"
)
@override_settings
(
SITE_NAME
=
settings
.
MICROSITE_TEST_HOSTNAME
)
def
test_microsite_uses_old_login_page
(
self
):
# Retrieve the login page from a microsite domain
...
...
lms/djangoapps/student_account/views.py
View file @
cf308d87
...
...
@@ -2,6 +2,7 @@
import
logging
import
json
import
urlparse
from
django.conf
import
settings
from
django.contrib
import
messages
...
...
@@ -77,12 +78,26 @@ def login_and_registration_form(request, initial_mode="login"):
if
ext_auth_response
is
not
None
:
return
ext_auth_response
# Our ?next= URL may itself contain a parameter 'tpa_hint=x' that we need to check.
# If present, we display a login page focused on third-party auth with that provider.
third_party_auth_hint
=
None
if
'?'
in
redirect_to
:
try
:
next_args
=
urlparse
.
parse_qs
(
urlparse
.
urlparse
(
redirect_to
)
.
query
)
provider_id
=
next_args
[
'tpa_hint'
][
0
]
if
third_party_auth
.
provider
.
Registry
.
get
(
provider_id
=
provider_id
):
third_party_auth_hint
=
provider_id
initial_mode
=
"hinted_login"
except
(
KeyError
,
ValueError
,
IndexError
):
pass
# Otherwise, render the combined login/registration page
context
=
{
'login_redirect_url'
:
redirect_to
,
# This gets added to the query string of the "Sign In" button in the header
'disable_courseware_js'
:
True
,
'initial_mode'
:
initial_mode
,
'third_party_auth'
:
json
.
dumps
(
_third_party_auth_context
(
request
,
redirect_to
)),
'third_party_auth_hint'
:
third_party_auth_hint
or
''
,
'platform_name'
:
settings
.
PLATFORM_NAME
,
'responsive'
:
True
,
...
...
lms/envs/common.py
View file @
cf308d87
...
...
@@ -1271,6 +1271,7 @@ student_account_js = [
'js/student_account/models/PasswordResetModel.js'
,
'js/student_account/views/FormView.js'
,
'js/student_account/views/LoginView.js'
,
'js/student_account/views/HintedLoginView.js'
,
'js/student_account/views/RegisterView.js'
,
'js/student_account/views/PasswordResetView.js'
,
'js/student_account/views/AccessView.js'
,
...
...
lms/static/js/spec/main.js
View file @
cf308d87
...
...
@@ -90,6 +90,7 @@
'js/student_account/models/RegisterModel'
:
'js/student_account/models/RegisterModel'
,
'js/student_account/views/RegisterView'
:
'js/student_account/views/RegisterView'
,
'js/student_account/views/AccessView'
:
'js/student_account/views/AccessView'
,
'js/student_account/views/HintedLoginView'
:
'js/student_account/views/HintedLoginView'
,
'js/student_profile/profile'
:
'js/student_profile/profile'
,
'js/student_profile/views/learner_profile_fields'
:
'js/student_profile/views/learner_profile_fields'
,
'js/student_profile/views/learner_profile_factory'
:
'js/student_profile/views/learner_profile_factory'
,
...
...
@@ -448,6 +449,15 @@
'js/student_account/views/FormView'
]
},
'js/student_account/views/HintedLoginView'
:
{
exports
:
'edx.student.account.HintedLoginView'
,
deps
:
[
'jquery'
,
'underscore'
,
'backbone'
,
'gettext'
]
},
'js/student_account/views/AccessView'
:
{
exports
:
'edx.student.account.AccessView'
,
deps
:
[
...
...
@@ -622,6 +632,7 @@
'lms/include/js/spec/student_account/account_spec.js'
,
'lms/include/js/spec/student_account/access_spec.js'
,
'lms/include/js/spec/student_account/finish_auth_spec.js'
,
'lms/include/js/spec/student_account/hinted_login_spec.js'
,
'lms/include/js/spec/student_account/login_spec.js'
,
'lms/include/js/spec/student_account/institution_login_spec.js'
,
'lms/include/js/spec/student_account/register_spec.js'
,
...
...
lms/static/js/spec/student_account/hinted_login_spec.js
0 → 100644
View file @
cf308d87
define
([
'jquery'
,
'underscore'
,
'common/js/spec_helpers/template_helpers'
,
'common/js/spec_helpers/ajax_helpers'
,
'js/student_account/views/HintedLoginView'
,
],
function
(
$
,
_
,
TemplateHelpers
,
AjaxHelpers
,
HintedLoginView
)
{
'use strict'
;
describe
(
'edx.student.account.HintedLoginView'
,
function
()
{
var
view
=
null
,
requests
=
null
,
PLATFORM_NAME
=
'edX'
,
THIRD_PARTY_AUTH
=
{
currentProvider
:
null
,
providers
:
[
{
id
:
'oa2-google-oauth2'
,
name
:
'Google'
,
iconClass
:
'fa-google-plus'
,
loginUrl
:
'/auth/login/google-oauth2/?auth_entry=account_login'
,
registerUrl
:
'/auth/login/google-oauth2/?auth_entry=account_register'
},
{
id
:
'oa2-facebook'
,
name
:
'Facebook'
,
iconClass
:
'fa-facebook'
,
loginUrl
:
'/auth/login/facebook/?auth_entry=account_login'
,
registerUrl
:
'/auth/login/facebook/?auth_entry=account_register'
}
]
},
HINTED_PROVIDER
=
"oa2-google-oauth2"
;
var
createHintedLoginView
=
function
(
test
)
{
// Initialize the login view
view
=
new
HintedLoginView
({
thirdPartyAuth
:
THIRD_PARTY_AUTH
,
hintedProvider
:
HINTED_PROVIDER
,
platformName
:
PLATFORM_NAME
});
// Mock the redirect call
spyOn
(
view
,
'redirect'
).
andCallFake
(
function
()
{}
);
view
.
render
();
};
beforeEach
(
function
()
{
setFixtures
(
'<div id="hinted-login-form"></div>'
);
TemplateHelpers
.
installTemplate
(
'templates/student_account/hinted_login'
);
});
it
(
'displays a choice as two buttons'
,
function
()
{
createHintedLoginView
(
this
);
expect
(
$
(
'.proceed-button.button-oa2-google-oauth2'
)).
toBeVisible
();
expect
(
$
(
'.form-toggle'
)).
toBeVisible
();
expect
(
$
(
'.proceed-button.button-oa2-facebook'
)).
not
.
toBeVisible
();
});
it
(
'redirects the user to the hinted provider if the user clicks the proceed button'
,
function
()
{
createHintedLoginView
(
this
);
// Click the "Yes, proceed" button
$
(
'.proceed-button'
).
click
();
expect
(
view
.
redirect
).
toHaveBeenCalledWith
(
'/auth/login/google-oauth2/?auth_entry=account_login'
);
});
});
});
lms/static/js/student_account/accessApp.js
View file @
cf308d87
...
...
@@ -11,6 +11,7 @@ var edx = edx || {};
return
new
edx
.
student
.
account
.
AccessView
({
mode
:
container
.
data
(
'initial-mode'
),
thirdPartyAuth
:
container
.
data
(
'third-party-auth'
),
thirdPartyAuthHint
:
container
.
data
(
'third-party-auth-hint'
),
nextUrl
:
container
.
data
(
'next-url'
),
platformName
:
container
.
data
(
'platform-name'
),
loginFormDesc
:
container
.
data
(
'login-form-desc'
),
...
...
lms/static/js/student_account/views/AccessView.js
View file @
cf308d87
...
...
@@ -19,7 +19,8 @@ var edx = edx || {};
login
:
{},
register
:
{},
passwordHelp
:
{},
institutionLogin
:
{}
institutionLogin
:
{},
hintedLogin
:
{}
},
nextUrl
:
'/dashboard'
,
...
...
@@ -43,6 +44,8 @@ var edx = edx || {};
providers
:
[]
};
this
.
thirdPartyAuthHint
=
obj
.
thirdPartyAuthHint
||
null
;
if
(
obj
.
nextUrl
)
{
// Ensure that the next URL is internal for security reasons
if
(
!
window
.
isExternal
(
obj
.
nextUrl
)
)
{
...
...
@@ -54,7 +57,8 @@ var edx = edx || {};
login
:
obj
.
loginFormDesc
,
register
:
obj
.
registrationFormDesc
,
reset
:
obj
.
passwordResetFormDesc
,
institution_login
:
null
institution_login
:
null
,
hinted_login
:
null
};
this
.
platformName
=
obj
.
platformName
;
...
...
@@ -160,6 +164,16 @@ var edx = edx || {};
});
this
.
subview
.
institutionLogin
.
render
();
},
hinted_login
:
function
(
unused
)
{
this
.
subview
.
hintedLogin
=
new
edx
.
student
.
account
.
HintedLoginView
({
thirdPartyAuth
:
this
.
thirdPartyAuth
,
hintedProvider
:
this
.
thirdPartyAuthHint
,
platformName
:
this
.
platformName
});
this
.
subview
.
hintedLogin
.
render
();
}
},
...
...
lms/static/js/student_account/views/HintedLoginView.js
0 → 100644
View file @
cf308d87
var
edx
=
edx
||
{};
(
function
(
$
,
_
,
gettext
)
{
'use strict'
;
edx
.
student
=
edx
.
student
||
{};
edx
.
student
.
account
=
edx
.
student
.
account
||
{};
edx
.
student
.
account
.
HintedLoginView
=
Backbone
.
View
.
extend
({
el
:
'#hinted-login-form'
,
tpl
:
'#hinted_login-tpl'
,
events
:
{
'click .proceed-button'
:
'proceedWithHintedAuth'
},
formType
:
'hinted-login'
,
initialize
:
function
(
data
)
{
this
.
tpl
=
$
(
this
.
tpl
).
html
();
this
.
providers
=
data
.
thirdPartyAuth
.
providers
||
[];
this
.
hintedProvider
=
_
.
findWhere
(
this
.
providers
,
{
id
:
data
.
hintedProvider
})
this
.
platformName
=
data
.
platformName
;
},
render
:
function
()
{
$
(
this
.
el
).
html
(
_
.
template
(
this
.
tpl
,
{
// We pass the context object to the template so that
// we can perform variable interpolation using sprintf
providers
:
this
.
providers
,
platformName
:
this
.
platformName
,
hintedProvider
:
this
.
hintedProvider
}));
return
this
;
},
proceedWithHintedAuth
:
function
(
event
)
{
this
.
redirect
(
this
.
hintedProvider
.
loginUrl
);
},
/**
* Redirect to a URL. Mainly useful for mocking out in tests.
* @param {string} url The URL to redirect to.
*/
redirect
:
function
(
url
)
{
window
.
location
.
href
=
url
;
}
});
})(
jQuery
,
_
,
gettext
);
lms/templates/student_account/access.underscore
View file @
cf308d87
...
...
@@ -13,3 +13,7 @@
<section id="institution_login-anchor" class="form-type">
<div id="institution_login-form" class="form-wrapper hidden" aria-hidden="true"></div>
</section>
<section id="hinted-login-anchor" class="form-type">
<div id="hinted-login-form" class="form-wrapper <% if ( mode !== 'hinted_login' ) { %>hidden<% } %>"></div>
</section>
lms/templates/student_account/hinted_login.underscore
0 → 100644
View file @
cf308d87
<div class="wrapper-other-login">
<div class="section-title lines">
<h2>
<span class="text"><%- gettext("Sign in") %></span>
</h2>
</div>
<p class="instructions"><%- _.sprintf( gettext("Would you like to sign in using your %(providerName)s credentials?"), { providerName: hintedProvider.name } ) %></p>
<button class="action action-primary action-update proceed-button button-<%- hintedProvider.id %> hinted-login-<%- hintedProvider.id %>">
<div class="icon fa <%- hintedProvider.iconClass %>" aria-hidden="true"></div>
<%- _.sprintf( gettext("Sign in using %(providerName)s"), { providerName: hintedProvider.name } ) %>
</button>
<div class="section-title lines">
<h2>
<span class="text"><%- gettext("or") %></span>
</h2>
</div>
<div class="toggle-form">
<button class="nav-btn form-toggle" data-type="login"><%- gettext("Show me other ways to sign in or register") %></button>
</div>
</div>
lms/templates/student_account/login_and_register.html
View file @
cf308d87
...
...
@@ -15,7 +15,7 @@
</
%
block>
<
%
block
name=
"header_extras"
>
% for template_name in ["account", "access", "form_field", "login", "register", "institution_login", "institution_register", "password_reset"]:
% for template_name in ["account", "access", "form_field", "login", "register", "institution_login", "institution_register", "password_reset"
, "hinted_login"
]:
<script
type=
"text/template"
id=
"${template_name}-tpl"
>
<%
static
:
include
path
=
"student_account/${template_name}.underscore"
/>
</script>
...
...
@@ -27,6 +27,7 @@
class=
"login-register"
data-initial-mode=
"${initial_mode}"
data-third-party-auth=
'${third_party_auth|h}'
data-third-party-auth-hint=
'${third_party_auth_hint}'
data-next-url=
'${login_redirect_url|h}'
data-platform-name=
'${platform_name}'
data-login-form-desc=
'${login_form_desc|h}'
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment