From 3599e2eec7facdee2451e29155d9044215765286 Mon Sep 17 00:00:00 2001 From: Renzo Lucioni Date: Wed, 30 Jul 2014 17:01:52 -0400 Subject: [PATCH] Revert "Revert "Merge pull request #4545 from edx/renzo/bi-analytics-overhaul"" This reverts commit 079808ee474031e47ed7c83a61b407e5ab5bb7ab. --- common/djangoapps/student/models.py | 17 ++- .../xmodule/js/src/capa/display.coffee | 3 +- .../xmodule/js/src/sequence/display.coffee | 8 +- common/static/js/spec/utility_spec.js | 23 ++++ common/static/js/src/utility.js | 127 +++++++++++++++++- .../class_dashboard/dashboard_data.py | 2 +- lms/djangoapps/instructor/views/api.py | 26 ++-- .../__init__.py | 0 .../basic.py | 0 .../csvs.py | 0 .../distributions.py | 0 .../management/__init__.py | 0 .../management/commands/__init__.py | 0 .../tests/__init__.py | 0 .../tests/test_basic.py | 2 +- .../tests/test_csvs.py | 2 +- .../tests/test_distributions.py | 2 +- lms/envs/dev.py | 7 +- lms/startup.py | 6 + .../src/instructor_dashboard_tracking.coffee | 3 +- lms/templates/login.html | 10 +- lms/templates/main.html | 4 +- lms/templates/register.html | 2 +- lms/templates/widgets/segment-io.html | 54 +++++--- lms/urls.py | 1 - requirements/edx/base.txt | 3 + 26 files changed, 244 insertions(+), 58 deletions(-) rename lms/djangoapps/{analytics => instructor_analytics}/__init__.py (100%) rename lms/djangoapps/{analytics => instructor_analytics}/basic.py (100%) rename lms/djangoapps/{analytics => instructor_analytics}/csvs.py (100%) rename lms/djangoapps/{analytics => instructor_analytics}/distributions.py (100%) rename lms/djangoapps/{analytics => instructor_analytics}/management/__init__.py (100%) rename lms/djangoapps/{analytics => instructor_analytics}/management/commands/__init__.py (100%) rename lms/djangoapps/{analytics => instructor_analytics}/tests/__init__.py (100%) rename lms/djangoapps/{analytics => instructor_analytics}/tests/test_basic.py (94%) rename lms/djangoapps/{analytics => instructor_analytics}/tests/test_csvs.py (98%) rename lms/djangoapps/{analytics => instructor_analytics}/tests/test_distributions.py (97%) diff --git a/common/djangoapps/student/models.py b/common/djangoapps/student/models.py index e34828b547..a78b4effe5 100644 --- a/common/djangoapps/student/models.py +++ b/common/djangoapps/student/models.py @@ -47,6 +47,8 @@ from course_modes.models import CourseMode from ratelimitbackend import admin +import analytics + unenroll_done = Signal(providing_args=["course_enrollment"]) log = logging.getLogger(__name__) AUDIT_LOG = logging.getLogger("audit") @@ -706,6 +708,7 @@ class CourseEnrollment(models.Model): if activation_changed or mode_changed: self.save() + if activation_changed: if self.is_active: self.emit_event(EVENT_NAME_ENROLLMENT_ACTIVATED) @@ -719,7 +722,7 @@ class CourseEnrollment(models.Model): else: unenroll_done.send(sender=None, course_enrollment=self) - + self.emit_event(EVENT_NAME_ENROLLMENT_DEACTIVATED) dog_stats_api.increment( @@ -749,6 +752,16 @@ class CourseEnrollment(models.Model): with tracker.get_tracker().context(event_name, context): tracker.emit(event_name, data) + + if settings.FEATURES.get('SEGMENT_IO_LMS') and settings.SEGMENT_IO_LMS_KEY: + analytics.track(self.user_id, event_name, { + 'category': 'conversion', + 'label': self.course_id.to_deprecated_string(), + 'org': self.course_id.org, + 'course': self.course_id.course, + 'run': self.course_id.run, + 'mode': self.mode, + }) except: # pylint: disable=bare-except if event_name and self.course_id: log.exception('Unable to emit event %s for user %s and course %s', event_name, self.user.username, self.course_id) @@ -773,6 +786,8 @@ class CourseEnrollment(models.Model): It is expected that this method is called from a method which has already verified the user authentication and access. + + Also emits relevant events for analytics purposes. """ enrollment = cls.get_or_create_enrollment(user, course_key) enrollment.update_enrollment(is_active=True, mode=mode) diff --git a/common/lib/xmodule/xmodule/js/src/capa/display.coffee b/common/lib/xmodule/xmodule/js/src/capa/display.coffee index e8326f55e9..592c9b3a0c 100644 --- a/common/lib/xmodule/xmodule/js/src/capa/display.coffee +++ b/common/lib/xmodule/xmodule/js/src/capa/display.coffee @@ -300,7 +300,8 @@ class @Problem Logger.log 'problem_check', @answers # Segment.io - analytics.track "Problem Checked", + analytics.track "edx.bi.course.problem.checked", + category: "courseware" problem_id: @id answers: @answers diff --git a/common/lib/xmodule/xmodule/js/src/sequence/display.coffee b/common/lib/xmodule/xmodule/js/src/sequence/display.coffee index 76557a517c..784075a355 100644 --- a/common/lib/xmodule/xmodule/js/src/sequence/display.coffee +++ b/common/lib/xmodule/xmodule/js/src/sequence/display.coffee @@ -128,7 +128,8 @@ class @Sequence analytics.pageview @id # navigation by clicking the tab directly - analytics.track "Accessed Sequential Directly", + analytics.track "edx.bi.course.sequential.direct.clicked", + category: "courseware" sequence_id: @id current_sequential: @position target_sequential: new_position @@ -167,9 +168,10 @@ class @Sequence # navigation using the next or previous arrow button. tracking_messages = - seq_prev: "Accessed Previous Sequential" - seq_next: "Accessed Next Sequential" + seq_prev: "edx.bi.course.sequential.previous.clicked" + seq_next: "edx.bi.course.sequential.next.clicked" analytics.track tracking_messages[direction], + category: "courseware" sequence_id: @id current_sequential: @position target_sequential: new_position diff --git a/common/static/js/spec/utility_spec.js b/common/static/js/spec/utility_spec.js index c44d36e893..c268d816dc 100644 --- a/common/static/js/spec/utility_spec.js +++ b/common/static/js/spec/utility_spec.js @@ -16,3 +16,26 @@ describe('utility.rewriteStaticLinks', function () { ).toBe('') }); }); + +describe('utility.appendParameter', function() { + it('creates and populates query string with provided parameter', function() { + expect(appendParameter('/cambridge', 'season', 'fall')).toBe('/cambridge?season=fall') + }); + it('appends provided parameter to existing query string parameters', function() { + expect(appendParameter('/cambridge?season=fall', 'color', 'red')).toBe('/cambridge?season=fall&color=red') + }); + it('appends provided parameter to existing query string with a trailing ampersand', function() { + expect(appendParameter('/cambridge?season=fall&', 'color', 'red')).toBe('/cambridge?season=fall&color=red') + }); + it('overwrites existing parameter with provided value', function() { + expect(appendParameter('/cambridge?season=fall', 'season', 'winter')).toBe('/cambridge?season=winter'); + expect(appendParameter('/cambridge?season=fall&color=red', 'color', 'orange')).toBe('/cambridge?season=fall&color=orange'); + }); +}); + +describe('utility.parseQueryString', function() { + it('converts a non-empty query string into a key/value object', function() { + expect(JSON.stringify(parseQueryString('season=fall'))).toBe(JSON.stringify({season:'fall'})); + expect(JSON.stringify(parseQueryString('season=fall&color=red'))).toBe(JSON.stringify({season:'fall', color:'red'})); + }); +}); diff --git a/common/static/js/src/utility.js b/common/static/js/src/utility.js index 7b5dd5a6bb..ab899711f8 100644 --- a/common/static/js/src/utility.js +++ b/common/static/js/src/utility.js @@ -38,4 +38,129 @@ window.rewriteStaticLinks = function(content, from, to) { // note: add other protocols here var regex = new RegExp("(https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}([-a-zA-Z0-9@:%_\+.~#?&//=]*))?"+from, 'g'); return content.replace(regex, replacer); -}; \ No newline at end of file +}; + +// Appends a parameter to a path; useful for indicating initial or return signin, for example +window.appendParameter = function(path, key, value) { + // Check if the given path already contains a query string by looking for the ampersand separator + if (path.indexOf("?") > -1) { + var splitPath = path.split("?"); + var parameters = window.parseQueryString(splitPath[1]); + // Check if the provided key already exists in the query string + if (key in parameters) { + // Overwrite the existing key's value with the provided value + parameters[key] = value; + + // Reconstruct the path, including the overwritten key/value pair + var reconstructedPath = splitPath[0] + "?"; + for (var k in parameters) { + reconstructedPath = reconstructedPath + k + "=" + parameters[k] + "&"; + } + // Strip the trailing ampersand + return reconstructedPath.slice(0, -1); + } else { + // Check for a trailing ampersand + if (path[path.length - 1] != "&") { + // Append signin parameter to the existing query string + return path + "&" + key + "=" + value; + } else { + // Append signin parameter to the existing query string, excluding the ampersand + return path + key + "=" + value; + } + } + } else { + // Append new query string containing the provided parameter + return path + "?" + key + "=" + value; + } +}; + +// Convert a query string to a key/value object +window.parseQueryString = function(queryString) { + var parameters = {}, queries, pair, i, l; + + // Split the query string into key/value pairs + queries = queryString.split("&"); + + // Break the array of strings into an object + for (i = 0, l = queries.length; i < l; i++) { + pair = queries[i].split('='); + parameters[pair[0]] = pair[1]; + } + + 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 + }); +}; diff --git a/lms/djangoapps/class_dashboard/dashboard_data.py b/lms/djangoapps/class_dashboard/dashboard_data.py index bd203a0ad5..5a4ba202aa 100644 --- a/lms/djangoapps/class_dashboard/dashboard_data.py +++ b/lms/djangoapps/class_dashboard/dashboard_data.py @@ -10,7 +10,7 @@ from django.utils.translation import ugettext as _ from xmodule.modulestore.django import modulestore from xmodule.modulestore.inheritance import own_metadata -from analytics.csvs import create_csv_response +from instructor_analytics.csvs import create_csv_response from opaque_keys.edx.locations import Location diff --git a/lms/djangoapps/instructor/views/api.py b/lms/djangoapps/instructor/views/api.py index b9516b8f19..67e2eaa84c 100644 --- a/lms/djangoapps/instructor/views/api.py +++ b/lms/djangoapps/instructor/views/api.py @@ -47,9 +47,9 @@ from instructor.enrollment import ( ) from instructor.access import list_with_level, allow_access, revoke_access, update_forum_role from instructor.offline_gradecalc import student_grades -import analytics.basic -import analytics.distributions -import analytics.csvs +import instructor_analytics.basic +import instructor_analytics.distributions +import instructor_analytics.csvs import csv from submissions import api as sub_api # installed from the edx-submissions repository @@ -538,7 +538,7 @@ def get_grading_config(request, course_id): course = get_course_with_access( request.user, 'staff', course_id, depth=None ) - grading_config_summary = analytics.basic.dump_grading_context(course) + grading_config_summary = instructor_analytics.basic.dump_grading_context(course) response_payload = { 'course_id': course_id.to_deprecated_string(), @@ -561,14 +561,14 @@ def get_students_features(request, course_id, csv=False): # pylint: disable=W06 """ course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id) - available_features = analytics.basic.AVAILABLE_FEATURES + available_features = instructor_analytics.basic.AVAILABLE_FEATURES query_features = [ 'id', 'username', 'name', 'email', 'language', 'location', 'year_of_birth', 'gender', 'level_of_education', 'mailing_address', 'goals', ] - student_data = analytics.basic.enrolled_students_features(course_id, query_features) + student_data = instructor_analytics.basic.enrolled_students_features(course_id, query_features) # Provide human-friendly and translatable names for these features. These names # will be displayed in the table generated in data_download.coffee. It is not (yet) @@ -598,8 +598,8 @@ def get_students_features(request, course_id, csv=False): # pylint: disable=W06 } return JsonResponse(response_payload) else: - header, datarows = analytics.csvs.format_dictlist(student_data, query_features) - return analytics.csvs.create_csv_response("enrolled_profiles.csv", header, datarows) + header, datarows = instructor_analytics.csvs.format_dictlist(student_data, query_features) + return instructor_analytics.csvs.create_csv_response("enrolled_profiles.csv", header, datarows) @ensure_csrf_cookie @@ -610,8 +610,8 @@ def get_anon_ids(request, course_id): # pylint: disable=W0613 Respond with 2-column CSV output of user-id, anonymized-user-id """ # TODO: the User.objects query and CSV generation here could be - # centralized into analytics. Currently analytics has similar functionality - # but not quite what's needed. + # centralized into instructor_analytics. Currently instructor_analytics + # has similar functionality but not quite what's needed. course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id) def csv_response(filename, header, rows): """Returns a CSV http response for the given header and rows (excel/utf-8).""" @@ -655,7 +655,7 @@ def get_distribution(request, course_id): else: feature = str(feature) - available_features = analytics.distributions.AVAILABLE_PROFILE_FEATURES + available_features = instructor_analytics.distributions.AVAILABLE_PROFILE_FEATURES # allow None so that requests for no feature can list available features if not feature in available_features + (None,): return HttpResponseBadRequest(strip_tags( @@ -666,12 +666,12 @@ def get_distribution(request, course_id): 'course_id': course_id.to_deprecated_string(), 'queried_feature': feature, 'available_features': available_features, - 'feature_display_names': analytics.distributions.DISPLAY_NAMES, + 'feature_display_names': instructor_analytics.distributions.DISPLAY_NAMES, } p_dist = None if not feature is None: - p_dist = analytics.distributions.profile_distribution(course_id, feature) + p_dist = instructor_analytics.distributions.profile_distribution(course_id, feature) response_payload['feature_results'] = { 'feature': p_dist.feature, 'feature_display_name': p_dist.feature_display_name, diff --git a/lms/djangoapps/analytics/__init__.py b/lms/djangoapps/instructor_analytics/__init__.py similarity index 100% rename from lms/djangoapps/analytics/__init__.py rename to lms/djangoapps/instructor_analytics/__init__.py diff --git a/lms/djangoapps/analytics/basic.py b/lms/djangoapps/instructor_analytics/basic.py similarity index 100% rename from lms/djangoapps/analytics/basic.py rename to lms/djangoapps/instructor_analytics/basic.py diff --git a/lms/djangoapps/analytics/csvs.py b/lms/djangoapps/instructor_analytics/csvs.py similarity index 100% rename from lms/djangoapps/analytics/csvs.py rename to lms/djangoapps/instructor_analytics/csvs.py diff --git a/lms/djangoapps/analytics/distributions.py b/lms/djangoapps/instructor_analytics/distributions.py similarity index 100% rename from lms/djangoapps/analytics/distributions.py rename to lms/djangoapps/instructor_analytics/distributions.py diff --git a/lms/djangoapps/analytics/management/__init__.py b/lms/djangoapps/instructor_analytics/management/__init__.py similarity index 100% rename from lms/djangoapps/analytics/management/__init__.py rename to lms/djangoapps/instructor_analytics/management/__init__.py diff --git a/lms/djangoapps/analytics/management/commands/__init__.py b/lms/djangoapps/instructor_analytics/management/commands/__init__.py similarity index 100% rename from lms/djangoapps/analytics/management/commands/__init__.py rename to lms/djangoapps/instructor_analytics/management/commands/__init__.py diff --git a/lms/djangoapps/analytics/tests/__init__.py b/lms/djangoapps/instructor_analytics/tests/__init__.py similarity index 100% rename from lms/djangoapps/analytics/tests/__init__.py rename to lms/djangoapps/instructor_analytics/tests/__init__.py diff --git a/lms/djangoapps/analytics/tests/test_basic.py b/lms/djangoapps/instructor_analytics/tests/test_basic.py similarity index 94% rename from lms/djangoapps/analytics/tests/test_basic.py rename to lms/djangoapps/instructor_analytics/tests/test_basic.py index 5aae8d524f..3cb70033db 100644 --- a/lms/djangoapps/analytics/tests/test_basic.py +++ b/lms/djangoapps/instructor_analytics/tests/test_basic.py @@ -7,7 +7,7 @@ from student.models import CourseEnrollment from student.tests.factories import UserFactory from opaque_keys.edx.locations import SlashSeparatedCourseKey -from analytics.basic import enrolled_students_features, AVAILABLE_FEATURES, STUDENT_FEATURES, PROFILE_FEATURES +from instructor_analytics.basic import enrolled_students_features, AVAILABLE_FEATURES, STUDENT_FEATURES, PROFILE_FEATURES class TestAnalyticsBasic(TestCase): diff --git a/lms/djangoapps/analytics/tests/test_csvs.py b/lms/djangoapps/instructor_analytics/tests/test_csvs.py similarity index 98% rename from lms/djangoapps/analytics/tests/test_csvs.py rename to lms/djangoapps/instructor_analytics/tests/test_csvs.py index d6673b95a4..41c0426cc9 100644 --- a/lms/djangoapps/analytics/tests/test_csvs.py +++ b/lms/djangoapps/instructor_analytics/tests/test_csvs.py @@ -3,7 +3,7 @@ from django.test import TestCase from nose.tools import raises -from analytics.csvs import create_csv_response, format_dictlist, format_instances +from instructor_analytics.csvs import create_csv_response, format_dictlist, format_instances class TestAnalyticsCSVS(TestCase): diff --git a/lms/djangoapps/analytics/tests/test_distributions.py b/lms/djangoapps/instructor_analytics/tests/test_distributions.py similarity index 97% rename from lms/djangoapps/analytics/tests/test_distributions.py rename to lms/djangoapps/instructor_analytics/tests/test_distributions.py index 2975186b29..ce75d47fc6 100644 --- a/lms/djangoapps/analytics/tests/test_distributions.py +++ b/lms/djangoapps/instructor_analytics/tests/test_distributions.py @@ -6,7 +6,7 @@ from student.models import CourseEnrollment from student.tests.factories import UserFactory from opaque_keys.edx.locations import SlashSeparatedCourseKey -from analytics.distributions import profile_distribution, AVAILABLE_PROFILE_FEATURES +from instructor_analytics.distributions import profile_distribution, AVAILABLE_PROFILE_FEATURES class TestAnalyticsDistributions(TestCase): diff --git a/lms/envs/dev.py b/lms/envs/dev.py index 83484cbfbf..074dcf5092 100644 --- a/lms/envs/dev.py +++ b/lms/envs/dev.py @@ -268,22 +268,21 @@ ANALYTICS_DATA_URL = "http://127.0.0.1:8080" ANALYTICS_DATA_TOKEN = "" FEATURES['ENABLE_ANALYTICS_ACTIVE_COUNT'] = False -##### segment-io ###### +##### Segment.io ###### # If there's an environment variable set, grab it and turn on Segment.io SEGMENT_IO_LMS_KEY = os.environ.get('SEGMENT_IO_LMS_KEY') if SEGMENT_IO_LMS_KEY: FEATURES['SEGMENT_IO_LMS'] = True -###################### Payment ##############################3 +###################### Payment ###################### CC_PROCESSOR['CyberSource']['SHARED_SECRET'] = os.environ.get('CYBERSOURCE_SHARED_SECRET', '') CC_PROCESSOR['CyberSource']['MERCHANT_ID'] = os.environ.get('CYBERSOURCE_MERCHANT_ID', '') CC_PROCESSOR['CyberSource']['SERIAL_NUMBER'] = os.environ.get('CYBERSOURCE_SERIAL_NUMBER', '') CC_PROCESSOR['CyberSource']['PURCHASE_ENDPOINT'] = os.environ.get('CYBERSOURCE_PURCHASE_ENDPOINT', '') - -########################## USER API ######################## +########################## USER API ########################## EDX_API_KEY = None ####################### Shoppingcart ########################### diff --git a/lms/startup.py b/lms/startup.py index 8487c52186..b073a16334 100644 --- a/lms/startup.py +++ b/lms/startup.py @@ -10,6 +10,7 @@ settings.INSTALLED_APPS # pylint: disable=W0104 from django_startup import autostartup import edxmako import logging +import analytics log = logging.getLogger(__name__) @@ -31,6 +32,11 @@ def run(): if settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH', False): enable_third_party_auth() + # 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: + analytics.init(settings.SEGMENT_IO_LMS_KEY, flush_at=50) + def add_mimetypes(): """ diff --git a/lms/static/coffee/src/instructor_dashboard_tracking.coffee b/lms/static/coffee/src/instructor_dashboard_tracking.coffee index eaeb3a4862..e32f5f57bd 100644 --- a/lms/static/coffee/src/instructor_dashboard_tracking.coffee +++ b/lms/static/coffee/src/instructor_dashboard_tracking.coffee @@ -1,4 +1,5 @@ if $('.instructor-dashboard-wrapper').length == 1 - analytics.track "Loaded a Legacy Instructor Dashboard Page", + analytics.track "edx.bi.course.legacy_instructor_dashboard.loaded", + category: "courseware" location: window.location.pathname dashboard_page: $('.navbar .selectedmode').text() diff --git a/lms/templates/login.html b/lms/templates/login.html index 7035c56d97..293bd5d934 100644 --- a/lms/templates/login.html +++ b/lms/templates/login.html @@ -59,16 +59,16 @@ next = decodeURIComponent(next); } if (next && !isExternal(next)) { - location.href=next; + location.href=appendParameter(next, "signin", "return"); } else if(json.redirect_url){ - location.href=json.redirect_url; + location.href=appendParameter(json.redirect_url, "signin", "return"); } else { - location.href="${reverse('dashboard')}"; + location.href=appendParameter("${reverse('dashboard')}", "signin", "return"); } } else if(json.hasOwnProperty('redirect')) { var u=decodeURI(window.location.search); if (!isExternal(json.redirect)) { // a paranoid check. Our server is the one providing json.redirect - location.href=json.redirect+u; + location.href=appendParameter(json.redirect+u, "signin", "return"); } // else we just remain on this page, which is fine since this particular path implies a login failure // that has been generated via packet tampering (json.redirect has been messed with). } else { @@ -103,7 +103,7 @@ function thirdPartySignin(event, url) { event.preventDefault(); - window.location.href = url; + window.location.href = appendParameter(url, "signin", "return"); } (function post_form_if_pipeline_running(pipeline_running) { diff --git a/lms/templates/main.html b/lms/templates/main.html index 8fca033e36..1c81419f7f 100644 --- a/lms/templates/main.html +++ b/lms/templates/main.html @@ -95,8 +95,6 @@ <%include file="${google_analytics_file}" /> - <%include file="widgets/segment-io.html" /> - % if style_overrides_file: @@ -123,6 +121,8 @@ <%static:js group='module-js'/> <%block name="js_extra"/> + + <%include file="widgets/segment-io.html" /> diff --git a/lms/templates/register.html b/lms/templates/register.html index 9c5c3480a5..63a8a8cfa2 100644 --- a/lms/templates/register.html +++ b/lms/templates/register.html @@ -55,7 +55,7 @@ $('#register-form').on('ajax:success', function(event, json, xhr) { var url = json.redirect_url || "${reverse('dashboard')}"; - location.href = url; + location.href = appendParameter(url, "signin", "initial"); }); $('#register-form').on('ajax:error', function(event, jqXHR, textStatus) { diff --git a/lms/templates/widgets/segment-io.html b/lms/templates/widgets/segment-io.html index 9abdbde8c1..df8f9e0a3f 100644 --- a/lms/templates/widgets/segment-io.html +++ b/lms/templates/widgets/segment-io.html @@ -1,44 +1,56 @@ % if settings.FEATURES.get('SEGMENT_IO_LMS'): <%! from django.core.urlresolvers import reverse %> -<%! import waffle %> - -<% active_flags = " + ".join(waffle.get_flags(request)) %> % else: diff --git a/lms/urls.py b/lms/urls.py index f304e2c13c..815e14cf2b 100644 --- a/lms/urls.py +++ b/lms/urls.py @@ -4,7 +4,6 @@ from ratelimitbackend import admin from django.conf.urls.static import static import django.contrib.auth.views - from microsite_configuration import microsite # Uncomment the next two lines to enable the admin: diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index 109ad3fd17..3db4fd4afe 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -128,6 +128,9 @@ splinter==0.5.4 testtools==0.9.34 flaky==0.2.0 +# Used for Segment.io analytics +analytics-python==0.4.4 + git+https://github.com/mfogel/django-settings-context-processor.git # django-cas version 2.0.3 with patch to be compatible with django 1.4