Merge pull request #4915 from edx/flowerhack/redo-third-party
Facebook auth support.
This commit is contained in:
@@ -46,7 +46,8 @@ from student.models import (
|
||||
Registration, UserProfile, PendingNameChange,
|
||||
PendingEmailChange, CourseEnrollment, unique_id_for_user,
|
||||
CourseEnrollmentAllowed, UserStanding, LoginFailures,
|
||||
create_comments_service_user, PasswordHistory, UserSignupSource
|
||||
create_comments_service_user, PasswordHistory, UserSignupSource,
|
||||
anonymous_id_for_user
|
||||
)
|
||||
from student.forms import PasswordResetFormNoActive
|
||||
|
||||
@@ -92,6 +93,9 @@ from util.password_policy_validators import (
|
||||
from third_party_auth import pipeline, provider
|
||||
from xmodule.error_module import ErrorDescriptor
|
||||
|
||||
import analytics
|
||||
from eventtracking import tracker
|
||||
|
||||
|
||||
log = logging.getLogger("edx.student")
|
||||
AUDIT_LOG = logging.getLogger("audit")
|
||||
@@ -381,6 +385,10 @@ def register_user(request, extra_context=None):
|
||||
'username': '',
|
||||
}
|
||||
|
||||
# We save this so, later on, we can determine what course motivated a user's signup
|
||||
# if they actually complete the registration process
|
||||
request.session['registration_course_id'] = context['course_id']
|
||||
|
||||
if extra_context is not None:
|
||||
context.update(extra_context)
|
||||
|
||||
@@ -951,6 +959,31 @@ def login_user(request, error=""): # pylint: disable-msg=too-many-statements,un
|
||||
if LoginFailures.is_feature_enabled():
|
||||
LoginFailures.clear_lockout_counter(user)
|
||||
|
||||
# Track the user's sign in
|
||||
if settings.FEATURES.get('SEGMENT_IO_LMS') and hasattr(settings, 'SEGMENT_IO_LMS_KEY'):
|
||||
tracking_context = tracker.get_tracker().resolve_context()
|
||||
analytics.identify(anonymous_id_for_user(user, None), {
|
||||
'email': email,
|
||||
'username': username,
|
||||
})
|
||||
|
||||
# If the user entered the flow via a specific course page, we track that
|
||||
registration_course_id = request.session.get('registration_course_id')
|
||||
analytics.track(
|
||||
user.id,
|
||||
"edx.bi.user.account.authenticated",
|
||||
{
|
||||
'category': "conversion",
|
||||
'label': registration_course_id
|
||||
},
|
||||
context={
|
||||
'Google Analytics': {
|
||||
'clientId': tracking_context.get('client_id')
|
||||
}
|
||||
}
|
||||
)
|
||||
request.session['registration_course_id'] = None
|
||||
|
||||
if user is not None and user.is_active:
|
||||
try:
|
||||
# We do not log here, because we have a handler registered
|
||||
@@ -1398,6 +1431,33 @@ def create_account(request, post_override=None): # pylint: disable-msg=too-many
|
||||
(user, profile, registration) = ret
|
||||
|
||||
dog_stats_api.increment("common.student.account_created")
|
||||
|
||||
email = post_vars['email']
|
||||
|
||||
# Track the user's registration
|
||||
if settings.FEATURES.get('SEGMENT_IO_LMS') and hasattr(settings, 'SEGMENT_IO_LMS_KEY'):
|
||||
tracking_context = tracker.get_tracker().resolve_context()
|
||||
analytics.identify(anonymous_id_for_user(user, None), {
|
||||
email: email,
|
||||
username: username,
|
||||
})
|
||||
|
||||
registration_course_id = request.session.get('registration_course_id')
|
||||
analytics.track(
|
||||
user.id,
|
||||
"edx.bi.user.account.registered",
|
||||
{
|
||||
"category": "conversion",
|
||||
"label": registration_course_id
|
||||
},
|
||||
context={
|
||||
'Google Analytics': {
|
||||
'clientId': tracking_context.get('client_id')
|
||||
}
|
||||
}
|
||||
)
|
||||
request.session['registration_course_id'] = None
|
||||
|
||||
create_comments_service_user(user)
|
||||
|
||||
context = {
|
||||
|
||||
@@ -4,7 +4,7 @@ Loaded by Django's settings mechanism. Consequently, this module must not
|
||||
invoke the Django armature.
|
||||
"""
|
||||
|
||||
from social.backends import google, linkedin
|
||||
from social.backends import google, linkedin, facebook
|
||||
|
||||
_DEFAULT_ICON_CLASS = 'icon-signin'
|
||||
|
||||
@@ -150,6 +150,26 @@ class LinkedInOauth2(BaseProvider):
|
||||
return provider_details.get('fullname')
|
||||
|
||||
|
||||
class FacebookOauth2(BaseProvider):
|
||||
"""Provider for LinkedIn's Oauth2 auth system."""
|
||||
|
||||
BACKEND_CLASS = facebook.FacebookOAuth2
|
||||
ICON_CLASS = 'icon-facebook'
|
||||
NAME = 'Facebook'
|
||||
SETTINGS = {
|
||||
'SOCIAL_AUTH_FACEBOOK_KEY': None,
|
||||
'SOCIAL_AUTH_FACEBOOK_SECRET': None,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def get_email(cls, provider_details):
|
||||
return provider_details.get('email')
|
||||
|
||||
@classmethod
|
||||
def get_name(cls, provider_details):
|
||||
return provider_details.get('fullname')
|
||||
|
||||
|
||||
class Registry(object):
|
||||
"""Singleton registry of third-party auth providers.
|
||||
|
||||
|
||||
@@ -282,7 +282,7 @@ class IntegrationTest(testutil.TestCase, test.TestCase):
|
||||
def assert_register_response_before_pipeline_looks_correct(self, response):
|
||||
"""Asserts a GET of /register not in the pipeline looks correct."""
|
||||
self.assertEqual(200, response.status_code)
|
||||
self.assertIn('Sign in with ' + self.PROVIDER_CLASS.NAME, response.content)
|
||||
self.assertIn('Sign up with ' + self.PROVIDER_CLASS.NAME, response.content)
|
||||
self.assert_signin_button_looks_functional(response.content, pipeline.AUTH_ENTRY_REGISTER)
|
||||
|
||||
def assert_signin_button_looks_functional(self, content, auth_entry):
|
||||
|
||||
@@ -91,75 +91,7 @@ window.parseQueryString = function(queryString) {
|
||||
return parameters
|
||||
};
|
||||
|
||||
// Check if the user recently enrolled in a course by looking at a referral URL
|
||||
window.checkRecentEnrollment = function(referrer) {
|
||||
var enrolledIn = null;
|
||||
|
||||
// Check if the referrer URL contains a query string
|
||||
if (referrer.indexOf("?") > -1) {
|
||||
referrerQueryString = referrer.split("?")[1];
|
||||
} else {
|
||||
referrerQueryString = "";
|
||||
}
|
||||
|
||||
if (referrerQueryString != "") {
|
||||
// Convert a non-empty query string into a key/value object
|
||||
var referrerParameters = window.parseQueryString(referrerQueryString);
|
||||
if ("course_id" in referrerParameters && "enrollment_action" in referrerParameters) {
|
||||
if (referrerParameters.enrollment_action == "enroll") {
|
||||
enrolledIn = referrerParameters.course_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return enrolledIn
|
||||
};
|
||||
|
||||
window.assessUserSignIn = function(parameters, userID, email, username) {
|
||||
// Check if the user has logged in to enroll in a course - designed for when "Register" button registers users on click (currently, this could indicate a course registration when there may not have yet been one)
|
||||
var enrolledIn = window.checkRecentEnrollment(document.referrer);
|
||||
|
||||
// Check if the user has just registered
|
||||
if (parameters.signin == "initial") {
|
||||
window.trackAccountRegistration(enrolledIn, userID, email, username);
|
||||
} else {
|
||||
window.trackReturningUserSignIn(enrolledIn, userID, email, username);
|
||||
}
|
||||
};
|
||||
|
||||
window.trackAccountRegistration = function(enrolledIn, userID, email, username) {
|
||||
// Alias the user's anonymous history with the user's new identity (for Mixpanel)
|
||||
analytics.alias(userID);
|
||||
|
||||
// Map the user's activity to their newly assigned ID
|
||||
analytics.identify(userID, {
|
||||
email: email,
|
||||
username: username
|
||||
});
|
||||
|
||||
// Track the user's account creation
|
||||
analytics.track("edx.bi.user.account.registered", {
|
||||
category: "conversion",
|
||||
label: enrolledIn != null ? enrolledIn : "none"
|
||||
});
|
||||
};
|
||||
|
||||
window.trackReturningUserSignIn = function(enrolledIn, userID, email, username) {
|
||||
// Map the user's activity to their assigned ID
|
||||
analytics.identify(userID, {
|
||||
email: email,
|
||||
username: username
|
||||
});
|
||||
|
||||
// Track the user's sign in
|
||||
analytics.track("edx.bi.user.account.authenticated", {
|
||||
category: "conversion",
|
||||
label: enrolledIn != null ? enrolledIn : "none"
|
||||
});
|
||||
};
|
||||
|
||||
window.identifyUser = function(userID, email, username) {
|
||||
// If the signin parameter isn't present but the query string is non-empty, map the user's activity to their assigned ID
|
||||
analytics.identify(userID, {
|
||||
email: email,
|
||||
username: username
|
||||
|
||||
@@ -44,12 +44,6 @@ FEEDBACK_SUBMISSION_EMAIL = "dummy@example.com"
|
||||
|
||||
WIKI_ENABLED = True
|
||||
|
||||
LOGGING = get_logger_config(ENV_ROOT / "log",
|
||||
logging_env="dev",
|
||||
local_loglevel="DEBUG",
|
||||
dev_env=True,
|
||||
debug=True)
|
||||
|
||||
DJFS = {
|
||||
'type': 'osfs',
|
||||
'directory_root': 'lms/static/djpyfs',
|
||||
|
||||
@@ -37,7 +37,7 @@ def run():
|
||||
|
||||
# Initialize Segment.io analytics module. Flushes first time a message is received and
|
||||
# every 50 messages thereafter, or if 10 seconds have passed since last flush
|
||||
if settings.FEATURES.get('SEGMENT_IO_LMS') and settings.SEGMENT_IO_LMS_KEY:
|
||||
if settings.FEATURES.get('SEGMENT_IO_LMS') and hasattr(settings, 'SEGMENT_IO_LMS_KEY'):
|
||||
analytics.init(settings.SEGMENT_IO_LMS_KEY, flush_at=50)
|
||||
|
||||
|
||||
|
||||
@@ -237,6 +237,54 @@
|
||||
}
|
||||
}
|
||||
|
||||
// blue secondary button outline style
|
||||
%btn-secondary-blue-outline {
|
||||
@extend %t-action2;
|
||||
@extend %btn;
|
||||
@extend %btn-edged;
|
||||
box-shadow: none;
|
||||
border: 1px solid $m-blue-d3;
|
||||
padding: ($baseline/2) $baseline;
|
||||
background: transparent;
|
||||
color: $m-blue-d3;
|
||||
|
||||
&:hover, &:active, &:focus {
|
||||
box-shadow: 0 2px 1px 0 $m-blue-d4;
|
||||
background: $m-blue-d1;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
&.current, &.active {
|
||||
box-shadow: inset 0 2px 1px 1px $m-blue-d2;
|
||||
background: $m-blue;
|
||||
color: $m-blue-d2;
|
||||
|
||||
&:hover, &:active, &:focus {
|
||||
box-shadow: inset 0 2px 1px 1px $m-blue-d3;
|
||||
color: $m-blue-d3;
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled, &[disabled] {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
// grey secondary button outline style
|
||||
%btn-secondary-grey-outline {
|
||||
@extend %btn-secondary-blue-outline;
|
||||
border: 1px solid $gray-l4;
|
||||
|
||||
&:hover, &:active, &:focus {
|
||||
box-shadow: none;
|
||||
border: 1px solid $m-blue-d3;
|
||||
}
|
||||
|
||||
&.disabled, &[disabled] {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
// ====================
|
||||
|
||||
// application: canned actions
|
||||
|
||||
@@ -230,6 +230,21 @@
|
||||
margin: 0 0 ($baseline/4) 0;
|
||||
}
|
||||
}
|
||||
|
||||
.cta-login {
|
||||
|
||||
h3.title,
|
||||
.instructions {
|
||||
display: inline-block;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.cta-login-action {
|
||||
@extend %btn-secondary-grey-outline;
|
||||
padding: ($baseline/10) ($baseline*.75);
|
||||
margin-left: ($baseline/4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// forms
|
||||
@@ -275,6 +290,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
.group-form-personalinformation {
|
||||
|
||||
.field-education-level,
|
||||
.field-gender,
|
||||
.field-yob {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// individual fields
|
||||
.field {
|
||||
margin: 0 0 $baseline 0;
|
||||
@@ -304,6 +330,16 @@
|
||||
font-size: em(13);
|
||||
}
|
||||
|
||||
&.password {
|
||||
position: relative;
|
||||
|
||||
.tip {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
input, textarea {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
@@ -432,9 +468,7 @@
|
||||
}
|
||||
|
||||
.action-primary {
|
||||
float: left;
|
||||
width: flex-grid(8,8);
|
||||
margin-right: flex-gutter(0);
|
||||
}
|
||||
|
||||
.action-secondary {
|
||||
@@ -452,16 +486,71 @@
|
||||
}
|
||||
|
||||
// forms - third-party auth
|
||||
.form-third-party-auth {
|
||||
|
||||
// UI: deco - divider
|
||||
.deco-divider {
|
||||
position: relative;
|
||||
display: block;
|
||||
margin: ($baseline*1.5) 0;
|
||||
border-top: ($baseline/5) solid $m-gray-l4;
|
||||
|
||||
.copy {
|
||||
@extend %t-copy-lead1;
|
||||
@extend %t-weight4;
|
||||
position: absolute;
|
||||
top: -($baseline);
|
||||
left: 43%;
|
||||
padding: ($baseline/4) ($baseline*1.5);
|
||||
background: white;
|
||||
text-align: center;
|
||||
color: $m-gray-l2;
|
||||
}
|
||||
}
|
||||
|
||||
// downplay required note
|
||||
.instructions .note {
|
||||
@extend %t-copy-sub2;
|
||||
display: block;
|
||||
font-weight: normal;
|
||||
color: $gray;
|
||||
}
|
||||
|
||||
.form-actions.form-third-party-auth {
|
||||
width: flex-grid(8,8);
|
||||
margin-bottom: $baseline;
|
||||
|
||||
button {
|
||||
margin-right: $baseline;
|
||||
button[type="submit"] {
|
||||
@extend %btn-secondary-blue-outline;
|
||||
width: flex-grid(4,8);
|
||||
margin-right: ($baseline/2);
|
||||
|
||||
.icon {
|
||||
color: inherit;
|
||||
margin-right: $baseline/2;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
&.button-Google:hover {
|
||||
box-shadow: 0 2px 1px 0 #8D3024;
|
||||
background-color: #dd4b39;
|
||||
border: 1px solid #A5382B;
|
||||
}
|
||||
|
||||
&.button-Facebook:hover {
|
||||
box-shadow: 0 2px 1px 0 #30487C;
|
||||
background-color: #3b5998;
|
||||
border: 1px solid #263A62;
|
||||
}
|
||||
|
||||
&.button-LinkedIn:hover {
|
||||
box-shadow: 0 2px 1px 0 #005D8E;
|
||||
background-color: #0077b5;
|
||||
border: 1px solid #06527D;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -536,7 +625,6 @@
|
||||
.introduction {
|
||||
header {
|
||||
height: 120px;
|
||||
border-bottom: 1px solid $m-gray;
|
||||
background: transparent $login-banner-image 0 0 no-repeat;
|
||||
}
|
||||
}
|
||||
@@ -548,7 +636,6 @@
|
||||
.introduction {
|
||||
header {
|
||||
height: 120px;
|
||||
border-bottom: 1px solid $m-gray;
|
||||
background: transparent $register-banner-image 0 0 no-repeat;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,17 +110,40 @@
|
||||
.third-party-auth {
|
||||
color: inherit;
|
||||
font-weight: inherit;
|
||||
}
|
||||
|
||||
.control {
|
||||
float: right;
|
||||
}
|
||||
.auth-provider {
|
||||
width: flex-grid(12);
|
||||
display: block;
|
||||
margin-top: ($baseline/4);
|
||||
|
||||
.icon {
|
||||
margin-top: 4px;
|
||||
.status {
|
||||
width: flex-grid(1);
|
||||
display: inline-block;
|
||||
color: $gray-l2;
|
||||
|
||||
.icon-link {
|
||||
color: $base-font-color;
|
||||
}
|
||||
|
||||
.copy {
|
||||
@extend %text-sr;
|
||||
}
|
||||
}
|
||||
|
||||
.provider {
|
||||
display: inline;
|
||||
width: flex-grid(9);
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.control {
|
||||
width: flex-grid(2);
|
||||
display: inline-block;
|
||||
text-align: right;
|
||||
|
||||
a:link, a:visited {
|
||||
@extend %t-copy-sub2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@
|
||||
% if duplicate_provider:
|
||||
<section class="dashboard-banner third-party-auth">
|
||||
## Translators: this message is displayed when a user tries to link their account with a third-party authentication provider (for example, Google or LinkedIn) with a given edX account, but their third-party account is already associated with another edX account. provider_name is the name of the third-party authentication provider, and platform_name is the name of the edX deployment.
|
||||
${_('The selected {provider_name} account is already linked to another {platform_name} account. Please {link_start}log out{link_end}, then log in with your {provider_name} account.').format(link_end='</a>', link_start='<a href="%s">' % logout_url, provider_name='<strong>%s</strong>' % duplicate_provider.NAME, platform_name=platform_name)}
|
||||
<p>${_('The {provider_name} account you selected is already linked to another {platform_name} account.').format(provider_name='<strong>%s</strong>' % duplicate_provider.NAME, platform_name=platform_name)}
|
||||
</section>
|
||||
% endif
|
||||
|
||||
@@ -226,22 +226,23 @@
|
||||
% if settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH'):
|
||||
<li class="controls--account">
|
||||
<span class="title">
|
||||
<div class="icon icon-gears"></div>
|
||||
## Translators: this section lists all the third-party authentication providers (for example, Google and LinkedIn) the user can link with or unlink from their edX account.
|
||||
${_("Account Links")}
|
||||
${_("Connected Accounts")}
|
||||
</span>
|
||||
|
||||
<span class="data">
|
||||
<span class="third-party-auth">
|
||||
|
||||
% for state in provider_user_states:
|
||||
<div>
|
||||
<div class="auth-provider">
|
||||
|
||||
% if state.has_account:
|
||||
<span class="icon icon-link pull-left"></span>
|
||||
% else:
|
||||
<span class="icon icon-unlink pull-left"></span>
|
||||
% endif
|
||||
<div class="status">
|
||||
% if state.has_account:
|
||||
<i class="icon icon-link"></i> <span class="copy">${_('Linked')}</span>
|
||||
% else:
|
||||
<i class="icon icon-unlink"></i><span class="copy">${_('Not Linked')}</span>
|
||||
% endif
|
||||
</div>
|
||||
|
||||
<span class="provider">${state.provider.NAME}</span>
|
||||
<span class="control">
|
||||
@@ -252,17 +253,19 @@
|
||||
method="post"
|
||||
name="${state.get_unlink_form_name()}">
|
||||
<input type="hidden" name="csrfmiddlewaretoken" value="${csrf_token}">
|
||||
</form>
|
||||
<a href="#" onclick="document.${state.get_unlink_form_name()}.submit()">
|
||||
## Translators: clicking on this removes the link between a user's edX account and their account with an external authentication provider (like Google or LinkedIn).
|
||||
${_("unlink")}
|
||||
</a>
|
||||
% else:
|
||||
<a href="${pipeline.get_login_url(state.provider.NAME, pipeline.AUTH_ENTRY_DASHBOARD)}">
|
||||
## Translators: clicking on this creates a link between a user's edX account and their account with an external authentication provider (like Google or LinkedIn).
|
||||
${_("link")}
|
||||
</a>
|
||||
|
||||
<a href="#" onclick="document.${state.get_unlink_form_name()}.submit()">
|
||||
## Translators: clicking on this removes the link between a user's edX account and their account with an external authentication provider (like Google or LinkedIn).
|
||||
${_("Unlink")}
|
||||
</a>
|
||||
% else:
|
||||
<a href="${pipeline.get_login_url(state.provider.NAME, pipeline.AUTH_ENTRY_DASHBOARD)}">
|
||||
## Translators: clicking on this creates a link between a user's edX account and their account with an external authentication provider (like Google or LinkedIn).
|
||||
${_("Link")}
|
||||
</a>
|
||||
% endif
|
||||
</form>
|
||||
|
||||
</span>
|
||||
</div>
|
||||
% endfor
|
||||
|
||||
@@ -190,19 +190,17 @@
|
||||
|
||||
% if settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH'):
|
||||
|
||||
<hr />
|
||||
|
||||
<p class="instructions">
|
||||
## Developers: this is a sentence fragment, which is usually frowned upon. The design of the pags uses this fragment to provide an "else" clause underneath a number of choices. It's OK to leave it.
|
||||
## Translators: this is the last choice of a number of choices of how to log in to the site.
|
||||
${_('or, if you have connected one of these providers, log in below.')}
|
||||
</p>
|
||||
<span class="deco-divider">
|
||||
## Developers: this is a sentence fragment, which is usually frowned upon. The design of the pags uses this fragment to provide an "else" clause underneath a number of choices. It's OK to leave it.
|
||||
## Translators: this is the last choice of a number of choices of how to log in to the site.
|
||||
<span class="copy">${_('or')}</span>
|
||||
</span>
|
||||
|
||||
<div class="form-actions form-third-party-auth">
|
||||
|
||||
% for enabled in provider.Registry.enabled():
|
||||
## Translators: provider_name is the name of an external, third-party user authentication provider (like Google or LinkedIn).
|
||||
<button type="submit" class="button button-primary" onclick="thirdPartySignin(event, '${pipeline.get_login_url(enabled.NAME, pipeline.AUTH_ENTRY_LOGIN)}');"><span class="icon ${enabled.ICON_CLASS}"></span>${_('Sign in with {provider_name}').format(provider_name=enabled.NAME)}</button>
|
||||
<button type="submit" class="button button-primary button-${enabled.NAME}" onclick="thirdPartySignin(event, '${pipeline.get_login_url(enabled.NAME, pipeline.AUTH_ENTRY_LOGIN)}');"><span class="icon ${enabled.ICON_CLASS}"></span>${_('Sign in with {provider_name}').format(provider_name=enabled.NAME)}</button>
|
||||
% endfor
|
||||
|
||||
</div>
|
||||
|
||||
@@ -12,11 +12,11 @@ from django.core.urlresolvers import reverse
|
||||
|
||||
% if has_extauth_info is UNDEFINED:
|
||||
|
||||
<div class="cta">
|
||||
<h3>${_("Already registered?")}</h3>
|
||||
<div class="cta cta-login">
|
||||
<h3 class="title">${_("Already registered?")}</h3>
|
||||
<p class="instructions">
|
||||
<a href="${reverse('signin_user')}${login_query()}">
|
||||
${_("Click here to log in.")}
|
||||
<a class="cta-login-action" href="${reverse('signin_user')}${login_query()}">
|
||||
${_("Log in")}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -120,23 +120,27 @@
|
||||
|
||||
% if not running_pipeline:
|
||||
|
||||
<p class="instructions">
|
||||
${_("Register to start learning today!")}
|
||||
</p>
|
||||
|
||||
<div class="form-actions form-third-party-auth">
|
||||
|
||||
% for enabled in provider.Registry.enabled():
|
||||
## Translators: provider_name is the name of an external, third-party user authentication service (like Google or LinkedIn).
|
||||
<button type="submit" class="button button-primary" onclick="thirdPartySignin(event, '${pipeline.get_login_url(enabled.NAME, pipeline.AUTH_ENTRY_REGISTER)}');"><span class="icon ${enabled.ICON_CLASS}"></span>${_('Sign in with {provider_name}').format(provider_name=enabled.NAME)}</button>
|
||||
<button type="submit" class="button button-primary button-${enabled.NAME}" onclick="thirdPartySignin(event, '${pipeline.get_login_url(enabled.NAME, pipeline.AUTH_ENTRY_REGISTER)}');"><span class="icon ${enabled.ICON_CLASS}"></span>${_('Sign up with {provider_name}').format(provider_name=enabled.NAME)}</button>
|
||||
% endfor
|
||||
|
||||
</div>
|
||||
|
||||
<span class="deco-divider">
|
||||
## Developers: this is a sentence fragment, which is usually frowned upon. The design of the pags uses this fragment to provide an "else" clause underneath a number of choices. It's OK to leave it.
|
||||
## Translators: this is the last choice of a number of choices of how to log in to the site.
|
||||
<span class="copy">${_('or')}</span>
|
||||
</span>
|
||||
|
||||
<p class="instructions">
|
||||
${_('or create your own {platform_name} account by completing all <strong>required*</strong> fields below.').format(platform_name=platform_name)}
|
||||
${_('Create your own {platform_name} account below').format(platform_name=platform_name)}
|
||||
<span class="note">${_('Required fields are noted by <strong class="indicator">bold text and an asterisk (*)</strong>.')}</span>
|
||||
</p>
|
||||
|
||||
|
||||
% else:
|
||||
|
||||
<p class="instructions">
|
||||
@@ -235,7 +239,7 @@
|
||||
</div>
|
||||
|
||||
<div class="group group-form group-form-secondary group-form-personalinformation">
|
||||
<h2 class="sr">${_("Extra Personal Information")}</h2>
|
||||
<h2 class="sr">${_("Additional Personal Information")}</h2>
|
||||
|
||||
<ol class="list-input">
|
||||
% if settings.REGISTRATION_EXTRA_FIELDS['city'] != 'hidden':
|
||||
@@ -258,7 +262,7 @@
|
||||
</li>
|
||||
% endif
|
||||
% if settings.REGISTRATION_EXTRA_FIELDS['level_of_education'] != 'hidden':
|
||||
<li class="field-group">
|
||||
<li class="field-group field-education-level">
|
||||
<div class="field ${settings.REGISTRATION_EXTRA_FIELDS['level_of_education']} select" id="field-education-level">
|
||||
<label for="education-level">${_("Highest Level of Education Completed")}</label>
|
||||
<select id="education-level" name="level_of_education" ${'required aria-required="true"' if settings.REGISTRATION_EXTRA_FIELDS['level_of_education'] == 'required' else ''}>
|
||||
@@ -271,7 +275,7 @@
|
||||
</li>
|
||||
% endif
|
||||
% if settings.REGISTRATION_EXTRA_FIELDS['gender'] != 'hidden':
|
||||
<li class="field-group">
|
||||
<li class="field-group field-gender">
|
||||
<div class="field ${settings.REGISTRATION_EXTRA_FIELDS['gender']} select" id="field-gender">
|
||||
<label for="gender">${_("Gender")}</label>
|
||||
<select id="gender" name="gender" ${'required aria-required="true"' if settings.REGISTRATION_EXTRA_FIELDS['gender'] == 'required' else ''}>
|
||||
@@ -284,7 +288,7 @@
|
||||
</li>
|
||||
% endif
|
||||
% if settings.REGISTRATION_EXTRA_FIELDS['year_of_birth'] != 'hidden':
|
||||
<li class="field-group">
|
||||
<li class="field-group field-yob">
|
||||
<div class="field ${settings.REGISTRATION_EXTRA_FIELDS['year_of_birth']} select" id="field-yob">
|
||||
<label for="yob">${_("Year of Birth")}</label>
|
||||
<select id="yob" name="year_of_birth" ${'required aria-required="true"' if settings.REGISTRATION_EXTRA_FIELDS['year_of_birth'] == 'required' else ''}>
|
||||
@@ -300,8 +304,6 @@
|
||||
</div>
|
||||
|
||||
<div class="group group-form group-form-personalinformation2">
|
||||
<h2 class="sr">${_("Extra Personal Information")}</h2>
|
||||
|
||||
<ol class="list-input">
|
||||
% if settings.REGISTRATION_EXTRA_FIELDS['mailing_address'] != 'hidden':
|
||||
<li class="field ${settings.REGISTRATION_EXTRA_FIELDS['mailing_address']} text" id="field-address-mailing">
|
||||
|
||||
@@ -12,18 +12,8 @@
|
||||
// Access the query string, stripping the leading "?"
|
||||
var queryString = window.location.search.substring(1);
|
||||
|
||||
if (queryString != "") {
|
||||
// Convert the query string to a key/value object
|
||||
var parameters = window.parseQueryString(queryString);
|
||||
window.identifyUser("${user.id}", "${user.email}", "${user.username}");
|
||||
|
||||
if ("signin" in parameters) {
|
||||
window.assessUserSignIn(parameters, "${user.id}", "${user.email}", "${user.username}");
|
||||
} else {
|
||||
window.identifyUser("${user.id}", "${user.email}", "${user.username}");
|
||||
}
|
||||
} else {
|
||||
window.identifyUser("${user.id}", "${user.email}", "${user.username}");
|
||||
}
|
||||
% endif
|
||||
|
||||
// Get current page URL
|
||||
|
||||
Reference in New Issue
Block a user