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
95a435ab
Commit
95a435ab
authored
Nov 10, 2014
by
Will Daly
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Include course ID in analytics events for logistration
parent
a13f4f2f
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
573 additions
and
449 deletions
+573
-449
common/djangoapps/user_api/helpers.py
+14
-0
common/djangoapps/user_api/tests/test_helpers.py
+11
-0
common/djangoapps/user_api/views.py
+15
-1
lms/static/js/spec/student_account/login_spec.js
+202
-173
lms/static/js/spec/student_account/register_spec.js
+297
-267
lms/static/js/student_account/models/LoginModel.js
+17
-4
lms/static/js/student_account/models/RegisterModel.js
+17
-4
No files found.
common/djangoapps/user_api/helpers.py
View file @
95a435ab
...
...
@@ -343,6 +343,20 @@ def shim_student_view(view_func, check_logged_in=False):
if
"course_id"
in
request
.
POST
:
del
request
.
POST
[
"course_id"
]
# Include the course ID if it's specified in the analytics info
# so it can be included in analytics events.
if
"analytics"
in
request
.
POST
:
try
:
analytics
=
json
.
loads
(
request
.
POST
[
"analytics"
])
if
"enroll_course_id"
in
analytics
:
request
.
POST
[
"course_id"
]
=
analytics
.
get
(
"enroll_course_id"
)
except
(
ValueError
,
TypeError
):
LOGGER
.
error
(
u"Could not parse analytics object sent to user API: {analytics}"
.
format
(
analytics
=
analytics
)
)
# Backwards compatibility: the student view expects both
# terms of service and honor code values. Since we're combining
# these into a single checkbox, the only value we may get
...
...
common/djangoapps/user_api/tests/test_helpers.py
View file @
95a435ab
...
...
@@ -150,6 +150,17 @@ class StudentViewShimTest(TestCase):
self
.
assertNotIn
(
"enrollment_action"
,
self
.
captured_request
.
POST
)
self
.
assertNotIn
(
"course_id"
,
self
.
captured_request
.
POST
)
def
test_include_analytics_info
(
self
):
view
=
self
.
_shimmed_view
(
HttpResponse
())
request
=
HttpRequest
()
request
.
POST
[
"analytics"
]
=
json
.
dumps
({
"enroll_course_id"
:
"edX/DemoX/Fall"
})
view
(
request
)
# Expect that the analytics course ID was passed to the view
self
.
assertEqual
(
self
.
captured_request
.
POST
.
get
(
"course_id"
),
"edX/DemoX/Fall"
)
def
test_third_party_auth_login_failure
(
self
):
view
=
self
.
_shimmed_view
(
HttpResponse
(
status
=
403
),
...
...
common/djangoapps/user_api/views.py
View file @
95a435ab
...
...
@@ -133,6 +133,13 @@ class LoginSessionView(APIView):
def
post
(
self
,
request
):
"""Log in a user.
You must send all required form fields with the request.
You can optionally send an `analytics` param with a JSON-encoded
object with additional info to include in the login analytics event.
Currently, the only supported field is "enroll_course_id" to indicate
that the user logged in while enrolling in a particular course.
Arguments:
request (HttpRequest)
...
...
@@ -148,7 +155,7 @@ class LoginSessionView(APIView):
Example Usage:
POST /user_api/v1/login_session
with POST params `email`
and `password`
with POST params `email`
, `password`, and `remember`.
200 OK
...
...
@@ -246,6 +253,13 @@ class RegistrationView(APIView):
def
post
(
self
,
request
):
"""Create the user's account.
You must send all required form fields with the request.
You can optionally send an `analytics` param with a JSON-encoded
object with additional info to include in the registration analytics event.
Currently, the only supported field is "enroll_course_id" to indicate
that the user registered while enrolling in a particular course.
Arguments:
request (HTTPRequest)
...
...
lms/static/js/spec/student_account/login_spec.js
View file @
95a435ab
...
...
@@ -6,208 +6,237 @@ define([
'js/student_account/models/LoginModel'
,
'js/student_account/views/LoginView'
],
function
(
$
,
_
,
TemplateHelpers
,
AjaxHelpers
,
LoginModel
,
LoginView
)
{
describe
(
'edx.student.account.LoginView'
,
function
()
{
'use strict'
;
var
model
=
null
,
view
=
null
,
requests
=
null
,
authComplete
=
false
,
PLATFORM_NAME
=
'edX'
,
USER_DATA
=
{
email
:
'xsy@edx.org'
,
password
:
'xsyisawesome'
,
remember
:
true
},
THIRD_PARTY_AUTH
=
{
currentProvider
:
null
,
providers
:
[
{
name
:
'Google'
,
iconClass
:
'icon-google-plus'
,
loginUrl
:
'/auth/login/google-oauth2/?auth_entry=account_login'
,
registerUrl
:
'/auth/login/google-oauth2/?auth_entry=account_register'
},
{
name
:
'Facebook'
,
iconClass
:
'icon-facebook'
,
loginUrl
:
'/auth/login/facebook/?auth_entry=account_login'
,
registerUrl
:
'/auth/login/facebook/?auth_entry=account_register'
}
]
},
FORM_DESCRIPTION
=
{
method
:
'post'
,
submit_url
:
'/user_api/v1/account/login_session/'
,
fields
:
[
{
name
:
'email'
,
label
:
'Email'
,
defaultValue
:
''
,
type
:
'email'
,
required
:
true
,
placeholder
:
'place@holder.org'
,
instructions
:
'Enter your email.'
,
restrictions
:
{}
},
{
name
:
'password'
,
label
:
'Password'
,
defaultValue
:
''
,
type
:
'password'
,
required
:
true
,
instructions
:
'Enter your password.'
,
restrictions
:
{}
},
{
name
:
'remember'
,
label
:
'Remember me'
,
defaultValue
:
''
,
type
:
'checkbox'
,
required
:
true
,
instructions
:
"Agree to the terms of service."
,
restrictions
:
{}
}
]
};
var
createLoginView
=
function
(
test
)
{
// Initialize the login model
model
=
new
LoginModel
({},
{
url
:
FORM_DESCRIPTION
.
submit_url
,
method
:
FORM_DESCRIPTION
.
method
});
'use strict'
;
describe
(
'edx.student.account.LoginView'
,
function
()
{
var
model
=
null
,
view
=
null
,
requests
=
null
,
authComplete
=
false
,
PLATFORM_NAME
=
'edX'
,
USER_DATA
=
{
email
:
'xsy@edx.org'
,
password
:
'xsyisawesome'
,
remember
:
true
},
THIRD_PARTY_AUTH
=
{
currentProvider
:
null
,
providers
:
[
{
name
:
'Google'
,
iconClass
:
'icon-google-plus'
,
loginUrl
:
'/auth/login/google-oauth2/?auth_entry=account_login'
,
registerUrl
:
'/auth/login/google-oauth2/?auth_entry=account_register'
},
{
name
:
'Facebook'
,
iconClass
:
'icon-facebook'
,
loginUrl
:
'/auth/login/facebook/?auth_entry=account_login'
,
registerUrl
:
'/auth/login/facebook/?auth_entry=account_register'
}
]
},
FORM_DESCRIPTION
=
{
method
:
'post'
,
submit_url
:
'/user_api/v1/account/login_session/'
,
fields
:
[
{
name
:
'email'
,
label
:
'Email'
,
defaultValue
:
''
,
type
:
'email'
,
required
:
true
,
placeholder
:
'place@holder.org'
,
instructions
:
'Enter your email.'
,
restrictions
:
{}
},
{
name
:
'password'
,
label
:
'Password'
,
defaultValue
:
''
,
type
:
'password'
,
required
:
true
,
instructions
:
'Enter your password.'
,
restrictions
:
{}
},
{
name
:
'remember'
,
label
:
'Remember me'
,
defaultValue
:
''
,
type
:
'checkbox'
,
required
:
true
,
instructions
:
"Agree to the terms of service."
,
restrictions
:
{}
}
]
},
COURSE_ID
=
"edX/demoX/Fall"
;
var
createLoginView
=
function
(
test
)
{
// Initialize the login model
model
=
new
LoginModel
({},
{
url
:
FORM_DESCRIPTION
.
submit_url
,
method
:
FORM_DESCRIPTION
.
method
});
// Initialize the login view
view
=
new
LoginView
({
fields
:
FORM_DESCRIPTION
.
fields
,
model
:
model
,
thirdPartyAuth
:
THIRD_PARTY_AUTH
,
platformName
:
PLATFORM_NAME
});
// Initialize the login view
view
=
new
LoginView
({
fields
:
FORM_DESCRIPTION
.
fields
,
model
:
model
,
thirdPartyAuth
:
THIRD_PARTY_AUTH
,
platformName
:
PLATFORM_NAME
});
// Spy on AJAX requests
requests
=
AjaxHelpers
.
requests
(
test
);
// Spy on AJAX requests
requests
=
AjaxHelpers
.
requests
(
test
);
// Intercept events from the view
authComplete
=
false
;
view
.
on
(
"auth-complete"
,
function
()
{
authComplete
=
true
;
// Intercept events from the view
authComplete
=
false
;
view
.
on
(
"auth-complete"
,
function
()
{
authComplete
=
true
;
});
};
var
submitForm
=
function
(
validationSuccess
)
{
// Simulate manual entry of login form data
$
(
'#login-email'
).
val
(
USER_DATA
.
email
);
$
(
'#login-password'
).
val
(
USER_DATA
.
password
);
// Check the "Remember me" checkbox
$
(
'#login-remember'
).
prop
(
'checked'
,
USER_DATA
.
remember
);
// Create a fake click event
var
clickEvent
=
$
.
Event
(
'click'
);
// If validationSuccess isn't passed, we avoid
// spying on `view.validate` twice
if
(
!
_
.
isUndefined
(
validationSuccess
)
)
{
// Force validation to return as expected
spyOn
(
view
,
'validate'
).
andReturn
({
isValid
:
validationSuccess
,
message
:
'Submission was validated.'
});
};
var
submitForm
=
function
(
validationSuccess
)
{
// Simulate manual entry of login form data
$
(
'#login-email'
).
val
(
USER_DATA
.
email
);
$
(
'#login-password'
).
val
(
USER_DATA
.
password
);
// Check the "Remember me" checkbox
$
(
'#login-remember'
).
prop
(
'checked'
,
USER_DATA
.
remember
);
// Create a fake click event
var
clickEvent
=
$
.
Event
(
'click'
);
// If validationSuccess isn't passed, we avoid
// spying on `view.validate` twice
if
(
!
_
.
isUndefined
(
validationSuccess
)
)
{
// Force validation to return as expected
spyOn
(
view
,
'validate'
).
andReturn
({
isValid
:
validationSuccess
,
message
:
'Submission was validated.'
});
}
}
// Submit the email address
view
.
submitForm
(
clickEvent
);
};
// Submit the email address
view
.
submitForm
(
clickEvent
);
};
beforeEach
(
function
()
{
setFixtures
(
'<div id="login-form"></div>'
);
TemplateHelpers
.
installTemplate
(
'templates/student_account/login'
);
TemplateHelpers
.
installTemplate
(
'templates/student_account/form_field'
);
});
beforeEach
(
function
()
{
setFixtures
(
'<div id="login-form"></div>'
);
TemplateHelpers
.
installTemplate
(
'templates/student_account/login'
);
TemplateHelpers
.
installTemplate
(
'templates/student_account/form_field'
);
});
it
(
'logs the user in'
,
function
()
{
createLoginView
(
this
);
it
(
'logs the user in'
,
function
()
{
createLoginView
(
this
);
// Submit the form, with successful validation
submitForm
(
true
);
// Submit the form, with successful validation
submitForm
(
true
);
// Verify that the client contacts the server with the expected data
AjaxHelpers
.
expectRequest
(
requests
,
'POST'
,
FORM_DESCRIPTION
.
submit_url
,
$
.
param
(
USER_DATA
)
);
// Verify that the client contacts the server with the expected data
AjaxHelpers
.
expectRequest
(
requests
,
'POST'
,
FORM_DESCRIPTION
.
submit_url
,
$
.
param
(
USER_DATA
)
);
// Respond with status code 200
AjaxHelpers
.
respondWithJson
(
requests
,
{});
// Respond with status code 200
AjaxHelpers
.
respondWithJson
(
requests
,
{});
// Verify that auth-complete is triggered
expect
(
authComplete
).
toBe
(
true
);
});
// Verify that auth-complete is triggered
expect
(
authComplete
).
toBe
(
true
);
});
it
(
'displays third-party auth login buttons
'
,
function
()
{
createLoginView
(
this
);
it
(
'sends analytics info containing the enrolled course ID
'
,
function
()
{
createLoginView
(
this
);
// Verify that Google and Facebook registration buttons are displayed
expect
(
$
(
'.button-Google'
)).
toBeVisible
();
expect
(
$
(
'.button-Facebook'
)).
toBeVisible
();
// Simulate that the user is attempting to enroll in a course
// by setting the course_id query string param.
spyOn
(
$
,
'url'
).
andCallFake
(
function
(
param
)
{
if
(
param
===
"?course_id"
)
{
return
encodeURIComponent
(
COURSE_ID
);
}
});
it
(
'displays a link to the password reset form'
,
function
()
{
createLoginView
(
this
);
// Attempt to login
submitForm
(
true
);
// Verify that the password reset link is displayed
expect
(
$
(
'.forgot-password'
)).
toBeVisible
();
// Verify that the client sent the course ID for analytics
var
expectedData
=
{};
$
.
extend
(
expectedData
,
USER_DATA
,
{
analytics
:
JSON
.
stringify
({
enroll_course_id
:
COURSE_ID
})
});
it
(
'validates login form fields'
,
function
()
{
createLoginView
(
this
);
AjaxHelpers
.
expectRequest
(
requests
,
'POST'
,
FORM_DESCRIPTION
.
submit_url
,
$
.
param
(
expectedData
)
);
});
it
(
'displays third-party auth login buttons'
,
function
()
{
createLoginView
(
this
);
submitForm
(
true
);
// Verify that Google and Facebook registration buttons are displayed
expect
(
$
(
'.button-Google'
)).
toBeVisible
();
expect
(
$
(
'.button-Facebook'
)).
toBeVisible
();
});
// Verify that validation of form fields occurred
expect
(
view
.
validate
).
toHaveBeenCalledWith
(
$
(
'#login-email'
)[
0
]);
expect
(
view
.
validate
).
toHaveBeenCalledWith
(
$
(
'#login-password'
)[
0
]);
});
it
(
'displays a link to the password reset form'
,
function
()
{
createLoginView
(
this
);
it
(
'displays login form validation errors'
,
function
()
{
createLoginView
(
this
);
// Verify that the password reset link is displayed
expect
(
$
(
'.forgot-password'
)).
toBeVisible
();
});
// Submit the form, with failed validation
submitForm
(
false
);
it
(
'validates login form fields'
,
function
()
{
createLoginView
(
this
);
// Verify that submission errors are visible
expect
(
view
.
$errors
).
not
.
toHaveClass
(
'hidden'
);
submitForm
(
true
);
// Expect auth complete NOT to have been triggered
expect
(
authComplete
).
toBe
(
false
);
});
// Verify that validation of form fields occurred
expect
(
view
.
validate
).
toHaveBeenCalledWith
(
$
(
'#login-email'
)[
0
]);
expect
(
view
.
validate
).
toHaveBeenCalledWith
(
$
(
'#login-password'
)[
0
]);
});
it
(
'displays an error if the server returns an error while logging in
'
,
function
()
{
createLoginView
(
this
);
it
(
'displays login form validation errors
'
,
function
()
{
createLoginView
(
this
);
// Submit the form, with successful
validation
submitForm
(
tru
e
);
// Submit the form, with failed
validation
submitForm
(
fals
e
);
// Simulate an error from the LMS servers
AjaxHelpers
.
respondWithError
(
requests
);
// Verify that submission errors are visible
expect
(
view
.
$errors
).
not
.
toHaveClass
(
'hidden'
);
// Expect that an error is displayed and that auth complete is not
triggered
expect
(
view
.
$errors
).
not
.
toHaveClass
(
'hidden'
);
expect
(
authComplete
).
toBe
(
false
);
// Expect auth complete NOT to have been
triggered
expect
(
authComplete
).
toBe
(
false
);
}
);
// If we try again and succeed, the error should go away
submitForm
(
);
it
(
'displays an error if the server returns an error while logging in'
,
function
()
{
createLoginView
(
this
);
// This time, respond with status code 200
AjaxHelpers
.
respondWithJson
(
requests
,
{}
);
// Submit the form, with successful validation
submitForm
(
true
);
// Expect that the error is hidden and auth complete is triggered
expect
(
view
.
$errors
).
toHaveClass
(
'hidden'
);
expect
(
authComplete
).
toBe
(
true
);
});
// Simulate an error from the LMS servers
AjaxHelpers
.
respondWithError
(
requests
);
// Expect that an error is displayed and that auth complete is not triggered
expect
(
view
.
$errors
).
not
.
toHaveClass
(
'hidden'
);
expect
(
authComplete
).
toBe
(
false
);
// If we try again and succeed, the error should go away
submitForm
();
// This time, respond with status code 200
AjaxHelpers
.
respondWithJson
(
requests
,
{});
// Expect that the error is hidden and auth complete is triggered
expect
(
view
.
$errors
).
toHaveClass
(
'hidden'
);
expect
(
authComplete
).
toBe
(
true
);
});
}
);
}
);
}
);
lms/static/js/spec/student_account/register_spec.js
View file @
95a435ab
...
...
@@ -6,302 +6,332 @@ define([
'js/student_account/models/RegisterModel'
,
'js/student_account/views/RegisterView'
],
function
(
$
,
_
,
TemplateHelpers
,
AjaxHelpers
,
RegisterModel
,
RegisterView
)
{
describe
(
'edx.student.account.RegisterView'
,
function
()
{
'use strict'
;
var
model
=
null
,
view
=
null
,
requests
=
null
,
authComplete
=
false
,
PLATFORM_NAME
=
'edX'
,
USER_DATA
=
{
email
:
'xsy@edx.org'
,
name
:
'Xsy M. Education'
,
username
:
'Xsy'
,
password
:
'xsyisawesome'
,
level_of_education
:
'p'
,
gender
:
'm'
,
year_of_birth
:
2014
,
mailing_address
:
'141 Portland'
,
goals
:
'To boldly learn what no letter of the alphabet has learned before'
,
honor_code
:
true
},
THIRD_PARTY_AUTH
=
{
currentProvider
:
null
,
providers
:
[
{
name
:
'Google'
,
iconClass
:
'icon-google-plus'
,
loginUrl
:
'/auth/login/google-oauth2/?auth_entry=account_login'
,
registerUrl
:
'/auth/login/google-oauth2/?auth_entry=account_register'
},
{
name
:
'Facebook'
,
iconClass
:
'icon-facebook'
,
loginUrl
:
'/auth/login/facebook/?auth_entry=account_login'
,
registerUrl
:
'/auth/login/facebook/?auth_entry=account_register'
}
]
},
FORM_DESCRIPTION
=
{
method
:
'post'
,
submit_url
:
'/user_api/v1/account/registration/'
,
fields
:
[
{
name
:
'email'
,
label
:
'Email'
,
defaultValue
:
''
,
type
:
'email'
,
required
:
true
,
placeholder
:
'place@holder.org'
,
instructions
:
'Enter your email.'
,
restrictions
:
{}
},
{
name
:
'name'
,
label
:
'Full Name'
,
defaultValue
:
''
,
type
:
'text'
,
required
:
true
,
instructions
:
'Enter your username.'
,
restrictions
:
{}
},
{
name
:
'username'
,
label
:
'Username'
,
defaultValue
:
''
,
type
:
'text'
,
required
:
true
,
instructions
:
'Enter your username.'
,
restrictions
:
{}
},
{
name
:
'password'
,
label
:
'Password'
,
defaultValue
:
''
,
type
:
'password'
,
required
:
true
,
instructions
:
'Enter your password.'
,
restrictions
:
{}
},
{
name
:
'level_of_education'
,
label
:
'Highest Level of Education Completed'
,
defaultValue
:
''
,
type
:
'select'
,
options
:
[
{
value
:
""
,
name
:
"--"
},
{
value
:
"p"
,
name
:
"Doctorate"
},
{
value
:
"m"
,
name
:
"Master's or professional degree"
},
{
value
:
"b"
,
name
:
"Bachelor's degree"
},
],
required
:
false
,
instructions
:
'Select your education level.'
,
restrictions
:
{}
},
{
name
:
'gender'
,
label
:
'Gender'
,
defaultValue
:
''
,
type
:
'select'
,
options
:
[
{
value
:
""
,
name
:
"--"
},
{
value
:
"m"
,
name
:
"Male"
},
{
value
:
"f"
,
name
:
"Female"
},
{
value
:
"o"
,
name
:
"Other"
},
],
required
:
false
,
instructions
:
'Select your gender.'
,
restrictions
:
{}
},
{
name
:
'year_of_birth'
,
label
:
'Year of Birth'
,
defaultValue
:
''
,
type
:
'select'
,
options
:
[
{
value
:
""
,
name
:
"--"
},
{
value
:
1900
,
name
:
"1900"
},
{
value
:
1950
,
name
:
"1950"
},
{
value
:
2014
,
name
:
"2014"
},
],
required
:
false
,
instructions
:
'Select your year of birth.'
,
restrictions
:
{}
},
{
name
:
'mailing_address'
,
label
:
'Mailing Address'
,
defaultValue
:
''
,
type
:
'textarea'
,
required
:
false
,
instructions
:
'Enter your mailing address.'
,
restrictions
:
{}
},
{
name
:
'goals'
,
label
:
'Goals'
,
defaultValue
:
''
,
type
:
'textarea'
,
required
:
false
,
instructions
:
"If you'd like, tell us why you're interested in edX."
,
restrictions
:
{}
},
{
name
:
'honor_code'
,
label
:
'I agree to the <a href="/honor">Terms of Service and Honor Code</a>'
,
defaultValue
:
''
,
type
:
'checkbox'
,
required
:
true
,
instructions
:
''
,
restrictions
:
{}
}
]
};
var
createRegisterView
=
function
(
that
)
{
// Initialize the register model
model
=
new
RegisterModel
({},
{
url
:
FORM_DESCRIPTION
.
submit_url
,
method
:
FORM_DESCRIPTION
.
method
});
'use strict'
;
describe
(
'edx.student.account.RegisterView'
,
function
()
{
var
model
=
null
,
view
=
null
,
requests
=
null
,
authComplete
=
false
,
PLATFORM_NAME
=
'edX'
,
COURSE_ID
=
"edX/DemoX/Fall"
,
USER_DATA
=
{
email
:
'xsy@edx.org'
,
name
:
'Xsy M. Education'
,
username
:
'Xsy'
,
password
:
'xsyisawesome'
,
level_of_education
:
'p'
,
gender
:
'm'
,
year_of_birth
:
2014
,
mailing_address
:
'141 Portland'
,
goals
:
'To boldly learn what no letter of the alphabet has learned before'
,
honor_code
:
true
},
THIRD_PARTY_AUTH
=
{
currentProvider
:
null
,
providers
:
[
{
name
:
'Google'
,
iconClass
:
'icon-google-plus'
,
loginUrl
:
'/auth/login/google-oauth2/?auth_entry=account_login'
,
registerUrl
:
'/auth/login/google-oauth2/?auth_entry=account_register'
},
{
name
:
'Facebook'
,
iconClass
:
'icon-facebook'
,
loginUrl
:
'/auth/login/facebook/?auth_entry=account_login'
,
registerUrl
:
'/auth/login/facebook/?auth_entry=account_register'
}
]
},
FORM_DESCRIPTION
=
{
method
:
'post'
,
submit_url
:
'/user_api/v1/account/registration/'
,
fields
:
[
{
name
:
'email'
,
label
:
'Email'
,
defaultValue
:
''
,
type
:
'email'
,
required
:
true
,
placeholder
:
'place@holder.org'
,
instructions
:
'Enter your email.'
,
restrictions
:
{}
},
{
name
:
'name'
,
label
:
'Full Name'
,
defaultValue
:
''
,
type
:
'text'
,
required
:
true
,
instructions
:
'Enter your username.'
,
restrictions
:
{}
},
{
name
:
'username'
,
label
:
'Username'
,
defaultValue
:
''
,
type
:
'text'
,
required
:
true
,
instructions
:
'Enter your username.'
,
restrictions
:
{}
},
{
name
:
'password'
,
label
:
'Password'
,
defaultValue
:
''
,
type
:
'password'
,
required
:
true
,
instructions
:
'Enter your password.'
,
restrictions
:
{}
},
{
name
:
'level_of_education'
,
label
:
'Highest Level of Education Completed'
,
defaultValue
:
''
,
type
:
'select'
,
options
:
[
{
value
:
""
,
name
:
"--"
},
{
value
:
"p"
,
name
:
"Doctorate"
},
{
value
:
"m"
,
name
:
"Master's or professional degree"
},
{
value
:
"b"
,
name
:
"Bachelor's degree"
},
],
required
:
false
,
instructions
:
'Select your education level.'
,
restrictions
:
{}
},
{
name
:
'gender'
,
label
:
'Gender'
,
defaultValue
:
''
,
type
:
'select'
,
options
:
[
{
value
:
""
,
name
:
"--"
},
{
value
:
"m"
,
name
:
"Male"
},
{
value
:
"f"
,
name
:
"Female"
},
{
value
:
"o"
,
name
:
"Other"
},
],
required
:
false
,
instructions
:
'Select your gender.'
,
restrictions
:
{}
},
{
name
:
'year_of_birth'
,
label
:
'Year of Birth'
,
defaultValue
:
''
,
type
:
'select'
,
options
:
[
{
value
:
""
,
name
:
"--"
},
{
value
:
1900
,
name
:
"1900"
},
{
value
:
1950
,
name
:
"1950"
},
{
value
:
2014
,
name
:
"2014"
},
],
required
:
false
,
instructions
:
'Select your year of birth.'
,
restrictions
:
{}
},
{
name
:
'mailing_address'
,
label
:
'Mailing Address'
,
defaultValue
:
''
,
type
:
'textarea'
,
required
:
false
,
instructions
:
'Enter your mailing address.'
,
restrictions
:
{}
},
{
name
:
'goals'
,
label
:
'Goals'
,
defaultValue
:
''
,
type
:
'textarea'
,
required
:
false
,
instructions
:
"If you'd like, tell us why you're interested in edX."
,
restrictions
:
{}
},
{
name
:
'honor_code'
,
label
:
'I agree to the <a href="/honor">Terms of Service and Honor Code</a>'
,
defaultValue
:
''
,
type
:
'checkbox'
,
required
:
true
,
instructions
:
''
,
restrictions
:
{}
}
]
};
// Initialize the register view
view
=
new
RegisterView
({
fields
:
FORM_DESCRIPTION
.
fields
,
model
:
model
,
thirdPartyAuth
:
THIRD_PARTY_AUTH
,
platformName
:
PLATFORM_NAME
});
var
createRegisterView
=
function
(
that
)
{
// Initialize the register model
model
=
new
RegisterModel
({},
{
url
:
FORM_DESCRIPTION
.
submit_url
,
method
:
FORM_DESCRIPTION
.
method
});
// Spy on AJAX requests
requests
=
AjaxHelpers
.
requests
(
that
);
// Initialize the register view
view
=
new
RegisterView
({
fields
:
FORM_DESCRIPTION
.
fields
,
model
:
model
,
thirdPartyAuth
:
THIRD_PARTY_AUTH
,
platformName
:
PLATFORM_NAME
});
// Spy on AJAX requests
requests
=
AjaxHelpers
.
requests
(
that
);
// Intercept events from the view
authComplete
=
false
;
view
.
on
(
"auth-complete"
,
function
()
{
authComplete
=
true
;
// Intercept events from the view
authComplete
=
false
;
view
.
on
(
"auth-complete"
,
function
()
{
authComplete
=
true
;
});
};
var
submitForm
=
function
(
validationSuccess
)
{
// Simulate manual entry of registration form data
$
(
'#register-email'
).
val
(
USER_DATA
.
email
);
$
(
'#register-name'
).
val
(
USER_DATA
.
name
);
$
(
'#register-username'
).
val
(
USER_DATA
.
username
);
$
(
'#register-password'
).
val
(
USER_DATA
.
password
);
$
(
'#register-level_of_education'
).
val
(
USER_DATA
.
level_of_education
);
$
(
'#register-gender'
).
val
(
USER_DATA
.
gender
);
$
(
'#register-year_of_birth'
).
val
(
USER_DATA
.
year_of_birth
);
$
(
'#register-mailing_address'
).
val
(
USER_DATA
.
mailing_address
);
$
(
'#register-goals'
).
val
(
USER_DATA
.
goals
);
// Check the honor code checkbox
$
(
'#register-honor_code'
).
prop
(
'checked'
,
USER_DATA
.
honor_code
);
// Create a fake click event
var
clickEvent
=
$
.
Event
(
'click'
);
// If validationSuccess isn't passed, we avoid
// spying on `view.validate` twice
if
(
!
_
.
isUndefined
(
validationSuccess
)
)
{
// Force validation to return as expected
spyOn
(
view
,
'validate'
).
andReturn
({
isValid
:
validationSuccess
,
message
:
'Submission was validated.'
});
}
;
}
var
submitForm
=
function
(
validationSuccess
)
{
// Simulate manual entry of registration form data
$
(
'#register-email'
).
val
(
USER_DATA
.
email
);
$
(
'#register-name'
).
val
(
USER_DATA
.
name
);
$
(
'#register-username'
).
val
(
USER_DATA
.
username
);
$
(
'#register-password'
).
val
(
USER_DATA
.
password
);
$
(
'#register-level_of_education'
).
val
(
USER_DATA
.
level_of_education
);
$
(
'#register-gender'
).
val
(
USER_DATA
.
gender
);
$
(
'#register-year_of_birth'
).
val
(
USER_DATA
.
year_of_birth
);
$
(
'#register-mailing_address'
).
val
(
USER_DATA
.
mailing_address
);
$
(
'#register-goals'
).
val
(
USER_DATA
.
goals
);
// Check the honor code checkbox
$
(
'#register-honor_code'
).
prop
(
'checked'
,
USER_DATA
.
honor_code
);
// Create a fake click event
var
clickEvent
=
$
.
Event
(
'click'
);
// If validationSuccess isn't passed, we avoid
// spying on `view.validate` twice
if
(
!
_
.
isUndefined
(
validationSuccess
)
)
{
// Force validation to return as expected
spyOn
(
view
,
'validate'
).
andReturn
({
isValid
:
validationSuccess
,
message
:
'Submission was validated.'
});
}
// Submit the email address
view
.
submitForm
(
clickEvent
);
};
// Submit the email address
view
.
submitForm
(
clickEvent
);
};
beforeEach
(
function
()
{
setFixtures
(
'<div id="register-form"></div>'
);
TemplateHelpers
.
installTemplate
(
'templates/student_account/register'
);
TemplateHelpers
.
installTemplate
(
'templates/student_account/form_field'
);
});
beforeEach
(
function
()
{
setFixtures
(
'<div id="register-form"></div>'
);
TemplateHelpers
.
installTemplate
(
'templates/student_account/register'
);
TemplateHelpers
.
installTemplate
(
'templates/student_account/form_field'
);
});
it
(
'registers a new user'
,
function
()
{
createRegisterView
(
this
);
it
(
'registers a new user'
,
function
()
{
createRegisterView
(
this
);
// Submit the form, with successful validation
submitForm
(
true
);
// Submit the form, with successful validation
submitForm
(
true
);
// Verify that the client contacts the server with the expected data
AjaxHelpers
.
expectRequest
(
requests
,
'POST'
,
FORM_DESCRIPTION
.
submit_url
,
$
.
param
(
USER_DATA
)
);
// Verify that the client contacts the server with the expected data
AjaxHelpers
.
expectRequest
(
requests
,
'POST'
,
FORM_DESCRIPTION
.
submit_url
,
$
.
param
(
USER_DATA
)
);
// Respond with status code 200
AjaxHelpers
.
respondWithJson
(
requests
,
{});
// Respond with status code 200
AjaxHelpers
.
respondWithJson
(
requests
,
{});
// Verify that auth complete is triggered
expect
(
authComplete
).
toBe
(
true
);
});
// Verify that auth complete is triggered
expect
(
authComplete
).
toBe
(
true
);
it
(
'sends analytics info containing the enrolled course ID'
,
function
()
{
createRegisterView
(
this
);
// Simulate that the user is attempting to enroll in a course
// by setting the course_id query string param.
spyOn
(
$
,
'url'
).
andCallFake
(
function
(
param
)
{
if
(
param
===
"?course_id"
)
{
return
encodeURIComponent
(
COURSE_ID
);
}
});
it
(
'displays third-party auth registration buttons'
,
function
()
{
createRegisterView
(
this
);
// Attempt to register
submitForm
(
true
);
// Verify that Google and Facebook registration buttons are displayed
expect
(
$
(
'.button-Google'
)).
toBeVisible
();
expect
(
$
(
'.button-Facebook'
)).
toBeVisible
();
// Verify that the client sent the course ID for analytics
var
expectedData
=
{};
$
.
extend
(
expectedData
,
USER_DATA
,
{
analytics
:
JSON
.
stringify
({
enroll_course_id
:
COURSE_ID
})
});
it
(
'validates registration form fields'
,
function
()
{
createRegisterView
(
this
);
AjaxHelpers
.
expectRequest
(
requests
,
'POST'
,
FORM_DESCRIPTION
.
submit_url
,
$
.
param
(
expectedData
)
);
});
it
(
'displays third-party auth registration buttons'
,
function
()
{
createRegisterView
(
this
);
// Submit the form, with successful validation
submitForm
(
true
);
// Verify that Google and Facebook registration buttons are displayed
expect
(
$
(
'.button-Google'
)).
toBeVisible
();
expect
(
$
(
'.button-Facebook'
)).
toBeVisible
();
});
// Verify that validation of form fields occurred
expect
(
view
.
validate
).
toHaveBeenCalledWith
(
$
(
'#register-email'
)[
0
]);
expect
(
view
.
validate
).
toHaveBeenCalledWith
(
$
(
'#register-name'
)[
0
]);
expect
(
view
.
validate
).
toHaveBeenCalledWith
(
$
(
'#register-username'
)[
0
]);
expect
(
view
.
validate
).
toHaveBeenCalledWith
(
$
(
'#register-password'
)[
0
]);
it
(
'validates registration form fields'
,
function
()
{
createRegisterView
(
this
);
// Verify that no submission errors are visible
expect
(
view
.
$errors
).
toHaveClass
(
'hidden'
);
});
// Submit the form, with successful validation
submitForm
(
true
);
it
(
'displays registration form validation errors'
,
function
()
{
createRegisterView
(
this
);
// Verify that validation of form fields occurred
expect
(
view
.
validate
).
toHaveBeenCalledWith
(
$
(
'#register-email'
)[
0
]);
expect
(
view
.
validate
).
toHaveBeenCalledWith
(
$
(
'#register-name'
)[
0
]);
expect
(
view
.
validate
).
toHaveBeenCalledWith
(
$
(
'#register-username'
)[
0
]);
expect
(
view
.
validate
).
toHaveBeenCalledWith
(
$
(
'#register-password'
)[
0
]);
// Submit the form, with failed validation
submitForm
(
false
);
// Verify that no submission errors are visible
expect
(
view
.
$errors
).
toHaveClass
(
'hidden'
);
});
// Verify that submission errors are visible
expect
(
view
.
$errors
).
not
.
toHaveClass
(
'hidden'
);
it
(
'displays registration form validation errors'
,
function
()
{
createRegisterView
(
this
);
// Expect that auth complete is NOT triggered
expect
(
authComplete
).
toBe
(
false
);
});
// Submit the form, with failed validation
submitForm
(
false
);
// Verify that submission errors are visible
expect
(
view
.
$errors
).
not
.
toHaveClass
(
'hidden'
);
it
(
'displays an error if the server returns an error while registering'
,
function
()
{
createRegisterView
(
this
);
// Expect that auth complete is NOT triggered
expect
(
authComplete
).
toBe
(
false
);
});
// Submit the form, with successful validation
submitForm
(
true
);
it
(
'displays an error if the server returns an error while registering'
,
function
()
{
createRegisterView
(
this
);
// Simulate an error from the LMS servers
AjaxHelpers
.
respondWithError
(
requests
);
// Submit the form, with successful validation
submitForm
(
true
);
// Expect that an error is displayed and that auth complete is NOT triggered
expect
(
view
.
$errors
).
not
.
toHaveClass
(
'hidden'
);
expect
(
authComplete
).
toBe
(
false
);
// Simulate an error from the LMS servers
AjaxHelpers
.
respondWithError
(
requests
);
// If we try again and succeed, the error should go away
submitForm
();
// Expect that an error is displayed and that auth complete is NOT triggered
expect
(
view
.
$errors
).
not
.
toHaveClass
(
'hidden'
);
expect
(
authComplete
).
toBe
(
false
);
// This time, respond with status code 200
AjaxHelpers
.
respondWithJson
(
requests
,
{}
);
// If we try again and succeed, the error should go away
submitForm
(
);
// Expect that the error is hidden and that auth complete is triggered
expect
(
view
.
$errors
).
toHaveClass
(
'hidden'
);
expect
(
authComplete
).
toBe
(
true
);
});
// This time, respond with status code 200
AjaxHelpers
.
respondWithJson
(
requests
,
{});
// Expect that the error is hidden and that auth complete is triggered
expect
(
view
.
$errors
).
toHaveClass
(
'hidden'
);
expect
(
authComplete
).
toBe
(
true
);
});
}
);
}
);
}
);
lms/static/js/student_account/models/LoginModel.js
View file @
95a435ab
...
...
@@ -24,14 +24,27 @@ var edx = edx || {};
},
sync
:
function
(
method
,
model
)
{
var
headers
=
{
'X-CSRFToken'
:
$
.
cookie
(
'csrftoken'
)
};
var
headers
=
{
'X-CSRFToken'
:
$
.
cookie
(
'csrftoken'
)
},
data
=
{},
analytics
,
courseId
=
$
.
url
(
'?course_id'
);
// If there is a course ID in the query string param,
// send that to the server as well so it can be included
// in analytics events.
if
(
courseId
)
{
analytics
=
JSON
.
stringify
({
enroll_course_id
:
decodeURIComponent
(
courseId
)
});
}
// Include all form fields and analytics info in the data sent to the server
$
.
extend
(
data
,
model
.
attributes
,
{
analytics
:
analytics
});
$
.
ajax
({
url
:
model
.
urlRoot
,
type
:
model
.
ajaxType
,
data
:
model
.
attributes
,
data
:
data
,
headers
:
headers
,
success
:
function
()
{
model
.
trigger
(
'sync'
);
...
...
lms/static/js/student_account/models/RegisterModel.js
View file @
95a435ab
...
...
@@ -30,14 +30,27 @@ var edx = edx || {};
},
sync
:
function
(
method
,
model
)
{
var
headers
=
{
'X-CSRFToken'
:
$
.
cookie
(
'csrftoken'
)
};
var
headers
=
{
'X-CSRFToken'
:
$
.
cookie
(
'csrftoken'
)
},
data
=
{},
analytics
,
courseId
=
$
.
url
(
'?course_id'
);
// If there is a course ID in the query string param,
// send that to the server as well so it can be included
// in analytics events.
if
(
courseId
)
{
analytics
=
JSON
.
stringify
({
enroll_course_id
:
decodeURIComponent
(
courseId
)
});
}
// Include all form fields and analytics info in the data sent to the server
$
.
extend
(
data
,
model
.
attributes
,
{
analytics
:
analytics
});
$
.
ajax
({
url
:
model
.
urlRoot
,
type
:
model
.
ajaxType
,
data
:
model
.
attributes
,
data
:
data
,
headers
:
headers
,
success
:
function
()
{
model
.
trigger
(
'sync'
);
...
...
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