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
284e78c2
Commit
284e78c2
authored
Jan 20, 2015
by
Will Daly
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #6690 from edx/will/inline-user-api-forms
Inline the user api form description calls
parents
349a02e4
0a9f9130
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
113 additions
and
111 deletions
+113
-111
lms/djangoapps/student_account/test/test_views.py
+7
-2
lms/djangoapps/student_account/views.py
+62
-2
lms/static/js/spec/student_account/access_spec.js
+4
-55
lms/static/js/student_account/accessApp.js
+8
-3
lms/static/js/student_account/views/AccessView.js
+28
-42
lms/templates/student_account/access.underscore
+0
-6
lms/templates/student_account/login_and_register.html
+4
-1
No files found.
lms/djangoapps/student_account/test/test_views.py
View file @
284e78c2
...
@@ -8,6 +8,7 @@ import json
...
@@ -8,6 +8,7 @@ import json
import
mock
import
mock
import
ddt
import
ddt
import
markupsafe
from
django.test
import
TestCase
from
django.test
import
TestCase
from
django.conf
import
settings
from
django.conf
import
settings
from
django.core.urlresolvers
import
reverse
from
django.core.urlresolvers
import
reverse
...
@@ -551,12 +552,16 @@ class StudentAccountLoginAndRegistrationTest(ModuleStoreTestCase):
...
@@ -551,12 +552,16 @@ class StudentAccountLoginAndRegistrationTest(ModuleStoreTestCase):
def
_assert_third_party_auth_data
(
self
,
response
,
current_provider
,
providers
):
def
_assert_third_party_auth_data
(
self
,
response
,
current_provider
,
providers
):
"""Verify that third party auth info is rendered correctly in a DOM data attribute. """
"""Verify that third party auth info is rendered correctly in a DOM data attribute. """
expected_data
=
u"data-third-party-auth='{auth_info}'"
.
format
(
auth_info
=
markupsafe
.
escape
(
auth_info
=
json
.
dumps
({
json
.
dumps
({
"currentProvider"
:
current_provider
,
"currentProvider"
:
current_provider
,
"providers"
:
providers
"providers"
:
providers
})
})
)
)
expected_data
=
u"data-third-party-auth='{auth_info}'"
.
format
(
auth_info
=
auth_info
)
self
.
assertContains
(
response
,
expected_data
)
self
.
assertContains
(
response
,
expected_data
)
def
_third_party_login_url
(
self
,
backend_name
,
auth_entry
,
course_id
=
None
,
redirect_url
=
None
):
def
_third_party_login_url
(
self
,
backend_name
,
auth_entry
,
course_id
=
None
,
redirect_url
=
None
):
...
...
lms/djangoapps/student_account/views.py
View file @
284e78c2
...
@@ -7,7 +7,8 @@ from django.http import (
...
@@ -7,7 +7,8 @@ from django.http import (
HttpResponse
,
HttpResponseBadRequest
,
HttpResponseForbidden
HttpResponse
,
HttpResponseBadRequest
,
HttpResponseForbidden
)
)
from
django.shortcuts
import
redirect
from
django.shortcuts
import
redirect
from
django.core.urlresolvers
import
reverse
from
django.http
import
HttpRequest
from
django.core.urlresolvers
import
reverse
,
resolve
from
django.core.mail
import
send_mail
from
django.core.mail
import
send_mail
from
django.utils.translation
import
ugettext
as
_
from
django.utils.translation
import
ugettext
as
_
from
django_future.csrf
import
ensure_csrf_cookie
from
django_future.csrf
import
ensure_csrf_cookie
...
@@ -68,13 +69,24 @@ def login_and_registration_form(request, initial_mode="login"):
...
@@ -68,13 +69,24 @@ def login_and_registration_form(request, initial_mode="login"):
if
request
.
user
.
is_authenticated
():
if
request
.
user
.
is_authenticated
():
return
redirect
(
reverse
(
'dashboard'
))
return
redirect
(
reverse
(
'dashboard'
))
# Retrieve the form descriptions from the user API
form_descriptions
=
_get_form_descriptions
(
request
)
# Otherwise, render the combined login/registration page
# Otherwise, render the combined login/registration page
context
=
{
context
=
{
'disable_courseware_js'
:
True
,
'disable_courseware_js'
:
True
,
'initial_mode'
:
initial_mode
,
'initial_mode'
:
initial_mode
,
'third_party_auth'
:
json
.
dumps
(
_third_party_auth_context
(
request
)),
'third_party_auth'
:
json
.
dumps
(
_third_party_auth_context
(
request
)),
'platform_name'
:
settings
.
PLATFORM_NAME
,
'platform_name'
:
settings
.
PLATFORM_NAME
,
'responsive'
:
True
'responsive'
:
True
,
# Include form descriptions retrieved from the user API.
# We could have the JS client make these requests directly,
# but we include them in the initial page load to avoid
# the additional round-trip to the server.
'login_form_desc'
:
form_descriptions
[
'login'
],
'registration_form_desc'
:
form_descriptions
[
'registration'
],
'password_reset_form_desc'
:
form_descriptions
[
'password_reset'
],
}
}
return
render_to_response
(
'student_account/login_and_register.html'
,
context
)
return
render_to_response
(
'student_account/login_and_register.html'
,
context
)
...
@@ -317,3 +329,51 @@ def _third_party_auth_context(request):
...
@@ -317,3 +329,51 @@ def _third_party_auth_context(request):
context
[
"currentProvider"
]
=
current_provider
.
NAME
context
[
"currentProvider"
]
=
current_provider
.
NAME
return
context
return
context
def
_get_form_descriptions
(
request
):
"""Retrieve form descriptions from the user API.
Arguments:
request (HttpRequest): The original request, used to retrieve session info.
Returns:
dict: Keys are 'login', 'registration', and 'password_reset';
values are the JSON-serialized form descriptions.
"""
return
{
'login'
:
_local_server_get
(
'/user_api/v1/account/login_session/'
,
request
.
session
),
'registration'
:
_local_server_get
(
'/user_api/v1/account/registration/'
,
request
.
session
),
'password_reset'
:
_local_server_get
(
'/user_api/v1/account/password_reset/'
,
request
.
session
)
}
def
_local_server_get
(
url
,
session
):
"""Simulate a server-server GET request for an in-process API.
Arguments:
url (str): The URL of the request (excluding the protocol and domain)
session (SessionStore): The session of the original request,
used to get past the CSRF checks.
Returns:
str: The content of the response
"""
# Since the user API is currently run in-process,
# we simulate the server-server API call by constructing
# our own request object. We don't need to include much
# information in the request except for the session
# (to get past through CSRF validation)
request
=
HttpRequest
()
request
.
method
=
"GET"
request
.
session
=
session
# Call the Django view function, simulating
# the server-server API call
view
,
args
,
kwargs
=
resolve
(
url
)
response
=
view
(
request
,
*
args
,
**
kwargs
)
# Return the content of the response
return
response
.
content
lms/static/js/spec/student_account/access_spec.js
View file @
284e78c2
...
@@ -13,20 +13,6 @@ define([
...
@@ -13,20 +13,6 @@ define([
var
requests
=
null
,
var
requests
=
null
,
view
=
null
,
view
=
null
,
AJAX_INFO
=
{
register
:
{
url
:
'/user_api/v1/account/registration/'
,
requestIndex
:
1
},
login
:
{
url
:
'/user_api/v1/account/login_session/'
,
requestIndex
:
0
},
password_reset
:
{
url
:
'/user_api/v1/account/password_reset/'
,
requestIndex
:
1
}
},
FORM_DESCRIPTION
=
{
FORM_DESCRIPTION
=
{
method
:
'post'
,
method
:
'post'
,
submit_url
:
'/submit'
,
submit_url
:
'/submit'
,
...
@@ -58,16 +44,6 @@ define([
...
@@ -58,16 +44,6 @@ define([
FORWARD_URL
=
'/courseware/next'
,
FORWARD_URL
=
'/courseware/next'
,
COURSE_KEY
=
'edx/DemoX/Fall'
;
COURSE_KEY
=
'edx/DemoX/Fall'
;
var
ajaxAssertAndRespond
=
function
(
url
,
requestIndex
)
{
// Verify that the client contacts the server as expected
AjaxHelpers
.
expectJsonRequest
(
requests
,
'GET'
,
url
,
null
,
requestIndex
);
/* Simulate a response from the server containing
/* a dummy form description
*/
AjaxHelpers
.
respondWithJson
(
requests
,
FORM_DESCRIPTION
);
};
var
ajaxSpyAndInitialize
=
function
(
that
,
mode
)
{
var
ajaxSpyAndInitialize
=
function
(
that
,
mode
)
{
// Spy on AJAX requests
// Spy on AJAX requests
requests
=
AjaxHelpers
.
requests
(
that
);
requests
=
AjaxHelpers
.
requests
(
that
);
...
@@ -79,7 +55,10 @@ define([
...
@@ -79,7 +55,10 @@ define([
currentProvider
:
null
,
currentProvider
:
null
,
providers
:
[]
providers
:
[]
},
},
platformName
:
'edX'
platformName
:
'edX'
,
loginFormDesc
:
FORM_DESCRIPTION
,
registrationFormDesc
:
FORM_DESCRIPTION
,
passwordResetFormDesc
:
FORM_DESCRIPTION
});
});
// Mock the redirect call
// Mock the redirect call
...
@@ -88,9 +67,6 @@ define([
...
@@ -88,9 +67,6 @@ define([
// Mock the enrollment and shopping cart interfaces
// Mock the enrollment and shopping cart interfaces
spyOn
(
EnrollmentInterface
,
'enroll'
).
andCallFake
(
function
()
{}
);
spyOn
(
EnrollmentInterface
,
'enroll'
).
andCallFake
(
function
()
{}
);
spyOn
(
ShoppingCartInterface
,
'addCourseToCart'
).
andCallFake
(
function
()
{}
);
spyOn
(
ShoppingCartInterface
,
'addCourseToCart'
).
andCallFake
(
function
()
{}
);
// Initialize the subview
ajaxAssertAndRespond
(
AJAX_INFO
[
mode
].
url
);
};
};
var
assertForms
=
function
(
visibleType
,
hiddenType
)
{
var
assertForms
=
function
(
visibleType
,
hiddenType
)
{
...
@@ -106,8 +82,6 @@ define([
...
@@ -106,8 +82,6 @@ define([
// Load form corresponding to the change event
// Load form corresponding to the change event
view
.
toggleForm
(
changeEvent
);
view
.
toggleForm
(
changeEvent
);
ajaxAssertAndRespond
(
AJAX_INFO
[
type
].
url
,
AJAX_INFO
[
type
].
requestIndex
);
};
};
/**
/**
...
@@ -175,11 +149,6 @@ define([
...
@@ -175,11 +149,6 @@ define([
// Simulate a click on the reset password link
// Simulate a click on the reset password link
view
.
resetPassword
();
view
.
resetPassword
();
ajaxAssertAndRespond
(
AJAX_INFO
.
password_reset
.
url
,
AJAX_INFO
.
password_reset
.
requestIndex
);
// Verify that the password reset wrapper is populated
// Verify that the password reset wrapper is populated
expect
(
$
(
'#password-reset-wrapper'
)).
not
.
toBeEmpty
();
expect
(
$
(
'#password-reset-wrapper'
)).
not
.
toBeEmpty
();
});
});
...
@@ -253,26 +222,6 @@ define([
...
@@ -253,26 +222,6 @@ define([
expect
(
view
.
redirect
).
toHaveBeenCalledWith
(
"/dashboard"
);
expect
(
view
.
redirect
).
toHaveBeenCalledWith
(
"/dashboard"
);
});
});
it
(
'displays an error if a form definition could not be loaded'
,
function
()
{
// Spy on AJAX requests
requests
=
AjaxHelpers
.
requests
(
this
);
// Init AccessView
view
=
new
AccessView
({
mode
:
'login'
,
thirdPartyAuth
:
{
currentProvider
:
null
,
providers
:
[]
},
platformName
:
'edX'
});
// Simulate an error from the LMS servers
AjaxHelpers
.
respondWithError
(
requests
);
// Error message should be displayed
expect
(
$
(
'#form-load-fail'
).
hasClass
(
'hidden'
)
).
toBe
(
false
);
});
});
});
}
}
);
);
lms/static/js/student_account/accessApp.js
View file @
284e78c2
...
@@ -6,9 +6,14 @@ var edx = edx || {};
...
@@ -6,9 +6,14 @@ var edx = edx || {};
edx
.
student
=
edx
.
student
||
{};
edx
.
student
=
edx
.
student
||
{};
edx
.
student
.
account
=
edx
.
student
.
account
||
{};
edx
.
student
.
account
=
edx
.
student
.
account
||
{};
var
container
=
$
(
'#login-and-registration-container'
);
return
new
edx
.
student
.
account
.
AccessView
({
return
new
edx
.
student
.
account
.
AccessView
({
mode
:
$
(
'#login-and-registration-container'
).
data
(
'initial-mode'
),
mode
:
container
.
data
(
'initial-mode'
),
thirdPartyAuth
:
$
(
'#login-and-registration-container'
).
data
(
'third-party-auth'
),
thirdPartyAuth
:
container
.
data
(
'third-party-auth'
),
platformName
:
$
(
'#login-and-registration-container'
).
data
(
'platform-name'
)
platformName
:
container
.
data
(
'platform-name'
),
loginFormDesc
:
container
.
data
(
'login-form-desc'
),
registrationFormDesc
:
container
.
data
(
'registration-form-desc'
),
passwordResetFormDesc
:
container
.
data
(
'password-reset-form-desc'
)
});
});
})(
jQuery
);
})(
jQuery
);
lms/static/js/student_account/views/AccessView.js
View file @
284e78c2
...
@@ -40,12 +40,20 @@ var edx = edx || {};
...
@@ -40,12 +40,20 @@ var edx = edx || {};
_
.
mixin
(
_s
.
exports
()
);
_
.
mixin
(
_s
.
exports
()
);
this
.
tpl
=
$
(
this
.
tpl
).
html
();
this
.
tpl
=
$
(
this
.
tpl
).
html
();
this
.
activeForm
=
obj
.
mode
||
'login'
;
this
.
activeForm
=
obj
.
mode
||
'login'
;
this
.
thirdPartyAuth
=
obj
.
thirdPartyAuth
||
{
this
.
thirdPartyAuth
=
obj
.
thirdPartyAuth
||
{
currentProvider
:
null
,
currentProvider
:
null
,
providers
:
[]
providers
:
[]
};
};
this
.
formDescriptions
=
{
login
:
obj
.
loginFormDesc
,
register
:
obj
.
registrationFormDesc
,
reset
:
obj
.
passwordResetFormDesc
};
this
.
platformName
=
obj
.
platformName
;
this
.
platformName
=
obj
.
platformName
;
// The login view listens for 'sync' events from the reset model
// The login view listens for 'sync' events from the reset model
...
@@ -73,82 +81,64 @@ var edx = edx || {};
...
@@ -73,82 +81,64 @@ var edx = edx || {};
},
},
loadForm
:
function
(
type
)
{
loadForm
:
function
(
type
)
{
this
.
getFormData
(
type
,
this
);
var
loadFunc
=
_
.
bind
(
this
.
load
[
type
],
this
);
loadFunc
(
this
.
formDescriptions
[
type
]
);
},
},
load
:
{
load
:
{
login
:
function
(
data
,
context
)
{
login
:
function
(
data
)
{
var
model
=
new
edx
.
student
.
account
.
LoginModel
({},
{
var
model
=
new
edx
.
student
.
account
.
LoginModel
({},
{
method
:
data
.
method
,
method
:
data
.
method
,
url
:
data
.
submit_url
url
:
data
.
submit_url
});
});
context
.
subview
.
login
=
new
edx
.
student
.
account
.
LoginView
({
this
.
subview
.
login
=
new
edx
.
student
.
account
.
LoginView
({
fields
:
data
.
fields
,
fields
:
data
.
fields
,
model
:
model
,
model
:
model
,
resetModel
:
context
.
resetModel
,
resetModel
:
this
.
resetModel
,
thirdPartyAuth
:
context
.
thirdPartyAuth
,
thirdPartyAuth
:
this
.
thirdPartyAuth
,
platformName
:
context
.
platformName
platformName
:
this
.
platformName
});
});
// Listen for 'password-help' event to toggle sub-views
// Listen for 'password-help' event to toggle sub-views
context
.
listenTo
(
context
.
subview
.
login
,
'password-help'
,
context
.
resetPassword
);
this
.
listenTo
(
this
.
subview
.
login
,
'password-help'
,
this
.
resetPassword
);
// Listen for 'auth-complete' event so we can enroll/redirect the user appropriately.
// Listen for 'auth-complete' event so we can enroll/redirect the user appropriately.
context
.
listenTo
(
context
.
subview
.
login
,
'auth-complete'
,
context
.
authComplete
);
this
.
listenTo
(
this
.
subview
.
login
,
'auth-complete'
,
this
.
authComplete
);
},
},
reset
:
function
(
data
,
context
)
{
reset
:
function
(
data
)
{
context
.
resetModel
.
ajaxType
=
data
.
method
;
this
.
resetModel
.
ajaxType
=
data
.
method
;
context
.
resetModel
.
urlRoot
=
data
.
submit_url
;
this
.
resetModel
.
urlRoot
=
data
.
submit_url
;
context
.
subview
.
passwordHelp
=
new
edx
.
student
.
account
.
PasswordResetView
({
this
.
subview
.
passwordHelp
=
new
edx
.
student
.
account
.
PasswordResetView
({
fields
:
data
.
fields
,
fields
:
data
.
fields
,
model
:
context
.
resetModel
model
:
this
.
resetModel
});
});
// Listen for 'password-email-sent' event to toggle sub-views
// Listen for 'password-email-sent' event to toggle sub-views
context
.
listenTo
(
context
.
subview
.
passwordHelp
,
'password-email-sent'
,
context
.
passwordEmailSent
);
this
.
listenTo
(
this
.
subview
.
passwordHelp
,
'password-email-sent'
,
this
.
passwordEmailSent
);
},
},
register
:
function
(
data
,
context
)
{
register
:
function
(
data
)
{
var
model
=
new
edx
.
student
.
account
.
RegisterModel
({},
{
var
model
=
new
edx
.
student
.
account
.
RegisterModel
({},
{
method
:
data
.
method
,
method
:
data
.
method
,
url
:
data
.
submit_url
url
:
data
.
submit_url
});
});
context
.
subview
.
register
=
new
edx
.
student
.
account
.
RegisterView
({
this
.
subview
.
register
=
new
edx
.
student
.
account
.
RegisterView
({
fields
:
data
.
fields
,
fields
:
data
.
fields
,
model
:
model
,
model
:
model
,
thirdPartyAuth
:
context
.
thirdPartyAuth
,
thirdPartyAuth
:
this
.
thirdPartyAuth
,
platformName
:
context
.
platformName
platformName
:
this
.
platformName
});
});
// Listen for 'auth-complete' event so we can enroll/redirect the user appropriately.
// Listen for 'auth-complete' event so we can enroll/redirect the user appropriately.
context
.
listenTo
(
context
.
subview
.
register
,
'auth-complete'
,
context
.
authComplete
);
this
.
listenTo
(
this
.
subview
.
register
,
'auth-complete'
,
this
.
authComplete
);
}
}
},
},
getFormData
:
function
(
type
,
context
)
{
var
urls
=
{
login
:
'login_session'
,
register
:
'registration'
,
reset
:
'password_reset'
};
$
.
ajax
({
url
:
'/user_api/v1/account/'
+
urls
[
type
]
+
'/'
,
type
:
'GET'
,
dataType
:
'json'
,
context
:
this
,
success
:
function
(
data
)
{
this
.
load
[
type
](
data
,
context
);
},
error
:
this
.
showFormError
});
},
passwordEmailSent
:
function
()
{
passwordEmailSent
:
function
()
{
this
.
element
.
hide
(
$
(
this
.
el
).
find
(
'#password-reset-anchor'
)
);
this
.
element
.
hide
(
$
(
this
.
el
).
find
(
'#password-reset-anchor'
)
);
this
.
element
.
show
(
$
(
'#login-anchor'
)
);
this
.
element
.
show
(
$
(
'#login-anchor'
)
);
...
@@ -165,10 +155,6 @@ var edx = edx || {};
...
@@ -165,10 +155,6 @@ var edx = edx || {};
this
.
element
.
scrollTop
(
$
(
'#password-reset-anchor'
)
);
this
.
element
.
scrollTop
(
$
(
'#password-reset-anchor'
)
);
},
},
showFormError
:
function
()
{
this
.
element
.
show
(
$
(
'#form-load-fail'
)
);
},
toggleForm
:
function
(
e
)
{
toggleForm
:
function
(
e
)
{
var
type
=
$
(
e
.
currentTarget
).
data
(
'type'
),
var
type
=
$
(
e
.
currentTarget
).
data
(
'type'
),
$form
=
$
(
'#'
+
type
+
'-form'
),
$form
=
$
(
'#'
+
type
+
'-form'
),
...
...
lms/templates/student_account/access.underscore
View file @
284e78c2
<section id="form-load-fail" class="form-type hidden">
<div class="status submission-error">
<p class="message-copy"><%- gettext("Sorry, we're having some technical problems. Wait a few minutes and try again.") %></p>
</div>
</section>
<section id="login-anchor" class="form-type">
<section id="login-anchor" class="form-type">
<div id="login-form" class="form-wrapper <% if ( mode !== 'login' ) { %>hidden<% } %>"></div>
<div id="login-form" class="form-wrapper <% if ( mode !== 'login' ) { %>hidden<% } %>"></div>
</section>
</section>
...
...
lms/templates/student_account/login_and_register.html
View file @
284e78c2
...
@@ -26,8 +26,11 @@
...
@@ -26,8 +26,11 @@
<div
id=
"login-and-registration-container"
<div
id=
"login-and-registration-container"
class=
"login-register"
class=
"login-register"
data-initial-mode=
"${initial_mode}"
data-initial-mode=
"${initial_mode}"
data-third-party-auth=
'${third_party_auth}'
data-third-party-auth=
'${third_party_auth
|h
}'
data-platform-name=
'${platform_name}'
data-platform-name=
'${platform_name}'
data-login-form-desc=
'${login_form_desc|h}'
data-registration-form-desc=
'${registration_form_desc|h}'
data-password-reset-form-desc=
'${password_reset_form_desc|h}'
/>
/>
</div>
</div>
...
...
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