Merge pull request #1802 from MITx/feature/markchang/studio-analytics
Instrument studio for analytics
This commit is contained in:
@@ -46,6 +46,9 @@ SESSION_COOKIE_DOMAIN = ENV_TOKENS.get('SESSION_COOKIE_DOMAIN')
|
||||
for feature, value in ENV_TOKENS.get('MITX_FEATURES', {}).items():
|
||||
MITX_FEATURES[feature] = value
|
||||
|
||||
# load segment.io key, provide a dummy if it does not exist
|
||||
SEGMENT_IO_KEY = ENV_TOKENS.get('SEGMENT_IO_KEY', '***REMOVED***')
|
||||
|
||||
LOGGING = get_logger_config(LOG_DIR,
|
||||
logging_env=ENV_TOKENS['LOGGING_ENV'],
|
||||
syslog_addr=(ENV_TOKENS['SYSLOG_SERVER'], 514),
|
||||
|
||||
@@ -36,6 +36,7 @@ MITX_FEATURES = {
|
||||
'STUB_VIDEO_FOR_TESTING': False, # do not display video when running automated acceptance tests
|
||||
'STAFF_EMAIL': '', # email address for staff (eg to request course creation)
|
||||
'STUDIO_NPS_SURVEY': True,
|
||||
'SEGMENT_IO': True,
|
||||
}
|
||||
ENABLE_JASMINE = False
|
||||
|
||||
|
||||
@@ -150,3 +150,6 @@ DEBUG_TOOLBAR_MONGO_STACKTRACES = True
|
||||
|
||||
# disable NPS survey in dev mode
|
||||
MITX_FEATURES['STUDIO_NPS_SURVEY'] = False
|
||||
|
||||
# segment-io key for dev
|
||||
SEGMENT_IO_KEY = 'mty8edrrsg'
|
||||
|
||||
@@ -118,3 +118,6 @@ PASSWORD_HASHERS = (
|
||||
'django.contrib.auth.hashers.SHA1PasswordHasher',
|
||||
'django.contrib.auth.hashers.MD5PasswordHasher',
|
||||
)
|
||||
|
||||
# dummy segment-io key
|
||||
SEGMENT_IO_KEY = '***REMOVED***'
|
||||
|
||||
@@ -15,7 +15,7 @@ class CMS.Views.ModuleEdit extends Backbone.View
|
||||
$component_editor: => @$el.find('.component-editor')
|
||||
|
||||
loadDisplay: ->
|
||||
XModule.loadModule(@$el.find('.xmodule_display'))
|
||||
XModule.loadModule(@$el.find('.xmodule_display'))
|
||||
|
||||
loadEdit: ->
|
||||
if not @module
|
||||
@@ -55,6 +55,11 @@ class CMS.Views.ModuleEdit extends Backbone.View
|
||||
clickSaveButton: (event) =>
|
||||
event.preventDefault()
|
||||
data = @module.save()
|
||||
|
||||
analytics.track "Saved Module",
|
||||
course: course_location_analytics
|
||||
id: _this.model.id
|
||||
|
||||
data.metadata = _.extend(data.metadata || {}, @metadata())
|
||||
@hideModal()
|
||||
@model.save(data).done( =>
|
||||
|
||||
@@ -28,6 +28,10 @@ class CMS.Views.TabsEdit extends Backbone.View
|
||||
@$('.component').each((idx, element) =>
|
||||
tabs.push($(element).data('id'))
|
||||
)
|
||||
|
||||
analytics.track "Reordered Static Pages",
|
||||
course: course_location_analytics
|
||||
|
||||
$.ajax({
|
||||
type:'POST',
|
||||
url: '/reorder_static_tabs',
|
||||
@@ -56,10 +60,18 @@ class CMS.Views.TabsEdit extends Backbone.View
|
||||
'i4x://edx/templates/static_tab/Empty'
|
||||
)
|
||||
|
||||
analytics.track "Added Static Page",
|
||||
course: course_location_analytics
|
||||
|
||||
deleteTab: (event) =>
|
||||
if not confirm 'Are you sure you want to delete this component? This action cannot be undone.'
|
||||
return
|
||||
$component = $(event.currentTarget).parents('.component')
|
||||
|
||||
analytics.track "Deleted Static Page",
|
||||
course: course_location_analytics
|
||||
id: $component.data('id')
|
||||
|
||||
$.post('/delete_item', {
|
||||
id: $component.data('id')
|
||||
}, =>
|
||||
|
||||
@@ -35,6 +35,10 @@ class CMS.Views.UnitEdit extends Backbone.View
|
||||
@$('.components').sortable(
|
||||
handle: '.drag-handle'
|
||||
update: (event, ui) =>
|
||||
analytics.track "Reordered Components",
|
||||
course: course_location_analytics
|
||||
id: unit_location_analytics
|
||||
|
||||
payload = children : @components()
|
||||
options = success : => @model.unset('children')
|
||||
@model.save(payload, options)
|
||||
@@ -89,6 +93,11 @@ class CMS.Views.UnitEdit extends Backbone.View
|
||||
$(event.currentTarget).data('location')
|
||||
)
|
||||
|
||||
analytics.track "Added a Component",
|
||||
course: course_location_analytics
|
||||
unit_id: unit_location_analytics
|
||||
type: $(event.currentTarget).data('location')
|
||||
|
||||
@closeNewComponent(event)
|
||||
|
||||
components: => @$('.component').map((idx, el) -> $(el).data('id')).get()
|
||||
@@ -111,6 +120,11 @@ class CMS.Views.UnitEdit extends Backbone.View
|
||||
$.post('/delete_item', {
|
||||
id: $component.data('id')
|
||||
}, =>
|
||||
analytics.track "Deleted a Component",
|
||||
course: course_location_analytics
|
||||
unit_id: unit_location_analytics
|
||||
id: $component.data('id')
|
||||
|
||||
$component.remove()
|
||||
# b/c we don't vigilantly keep children up to date
|
||||
# get rid of it before it hurts someone
|
||||
@@ -129,6 +143,10 @@ class CMS.Views.UnitEdit extends Backbone.View
|
||||
id: @$el.data('id')
|
||||
delete_children: true
|
||||
}, =>
|
||||
analytics.track "Deleted Draft",
|
||||
course: course_location_analytics
|
||||
unit_id: unit_location_analytics
|
||||
|
||||
window.location.reload()
|
||||
)
|
||||
|
||||
@@ -138,6 +156,10 @@ class CMS.Views.UnitEdit extends Backbone.View
|
||||
$.post('/create_draft', {
|
||||
id: @$el.data('id')
|
||||
}, =>
|
||||
analytics.track "Created Draft",
|
||||
course: course_location_analytics
|
||||
unit_id: unit_location_analytics
|
||||
|
||||
@model.set('state', 'draft')
|
||||
)
|
||||
|
||||
@@ -148,20 +170,31 @@ class CMS.Views.UnitEdit extends Backbone.View
|
||||
$.post('/publish_draft', {
|
||||
id: @$el.data('id')
|
||||
}, =>
|
||||
analytics.track "Published Draft",
|
||||
course: course_location_analytics
|
||||
unit_id: unit_location_analytics
|
||||
|
||||
@model.set('state', 'public')
|
||||
)
|
||||
|
||||
setVisibility: (event) ->
|
||||
if @$('.visibility-select').val() == 'private'
|
||||
target_url = '/unpublish_unit'
|
||||
visibility = "private"
|
||||
else
|
||||
target_url = '/publish_draft'
|
||||
visibility = "public"
|
||||
|
||||
@wait(true)
|
||||
|
||||
$.post(target_url, {
|
||||
id: @$el.data('id')
|
||||
}, =>
|
||||
analytics.track "Set Unit Visibility",
|
||||
course: course_location_analytics
|
||||
unit_id: unit_location_analytics
|
||||
visibility: visibility
|
||||
|
||||
@model.set('state', @$('.visibility-select').val())
|
||||
)
|
||||
|
||||
@@ -193,6 +226,11 @@ class CMS.Views.UnitEdit.NameEdit extends Backbone.View
|
||||
@model.save(metadata: metadata)
|
||||
# Update name shown in the right-hand side location summary.
|
||||
$('.unit-location .editing .unit-name').html(metadata.display_name)
|
||||
analytics.track "Edited Unit Name",
|
||||
course: course_location_analytics
|
||||
unit_id: unit_location_analytics
|
||||
display_name: metadata.display_name
|
||||
|
||||
|
||||
class CMS.Views.UnitEdit.LocationState extends Backbone.View
|
||||
initialize: =>
|
||||
|
||||
@@ -331,6 +331,12 @@ function createNewUnit(e) {
|
||||
var parent = $(this).data('parent');
|
||||
var template = $(this).data('template');
|
||||
|
||||
analytics.track('Created a Unit', {
|
||||
'course': course_location_analytics,
|
||||
'parent_location': parent
|
||||
});
|
||||
|
||||
|
||||
$.post('/clone_item',
|
||||
{'parent_location': parent,
|
||||
'template': template,
|
||||
@@ -363,6 +369,12 @@ function _deleteItem($el) {
|
||||
|
||||
var id = $el.data('id');
|
||||
|
||||
analytics.track('Deleted an Item', {
|
||||
'course': course_location_analytics,
|
||||
'id': id
|
||||
});
|
||||
|
||||
|
||||
$.post('/delete_item',
|
||||
{'id': id, 'delete_children': true, 'delete_all_versions': true},
|
||||
function (data) {
|
||||
@@ -426,6 +438,11 @@ function displayFinishedUpload(xhr) {
|
||||
var html = Mustache.to_html(template, resp);
|
||||
$('table > tbody').prepend(html);
|
||||
|
||||
analytics.track('Uploaded a File', {
|
||||
'course': course_location_analytics,
|
||||
'asset_url': resp.url
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function markAsLoaded() {
|
||||
@@ -555,6 +572,11 @@ function saveNewSection(e) {
|
||||
var template = $saveButton.data('template');
|
||||
var display_name = $(this).find('.new-section-name').val();
|
||||
|
||||
analytics.track('Created a Section', {
|
||||
'course': course_location_analytics,
|
||||
'display_name': display_name
|
||||
});
|
||||
|
||||
$.post('/clone_item', {
|
||||
'parent_location': parent,
|
||||
'template': template,
|
||||
@@ -600,6 +622,12 @@ function saveNewCourse(e) {
|
||||
return;
|
||||
}
|
||||
|
||||
analytics.track('Created a Course', {
|
||||
'org': org,
|
||||
'number': number,
|
||||
'display_name': display_name
|
||||
});
|
||||
|
||||
$.post('/create_new_course', {
|
||||
'template': template,
|
||||
'org': org,
|
||||
@@ -646,9 +674,14 @@ function saveNewSubsection(e) {
|
||||
|
||||
var parent = $(this).find('.new-subsection-name-save').data('parent');
|
||||
var template = $(this).find('.new-subsection-name-save').data('template');
|
||||
|
||||
var display_name = $(this).find('.new-subsection-name-input').val();
|
||||
|
||||
analytics.track('Created a Subsection', {
|
||||
'course': course_location_analytics,
|
||||
'display_name': display_name
|
||||
});
|
||||
|
||||
|
||||
$.post('/clone_item', {
|
||||
'parent_location': parent,
|
||||
'template': template,
|
||||
@@ -702,6 +735,13 @@ function saveEditSectionName(e) {
|
||||
return;
|
||||
}
|
||||
|
||||
analytics.track('Edited Section Name', {
|
||||
'course': course_location_analytics,
|
||||
'display_name': display_name,
|
||||
'id': id
|
||||
});
|
||||
|
||||
|
||||
var $_this = $(this);
|
||||
// call into server to commit the new order
|
||||
$.ajax({
|
||||
@@ -741,6 +781,12 @@ function saveSetSectionScheduleDate(e) {
|
||||
|
||||
var id = $modal.attr('data-id');
|
||||
|
||||
analytics.track('Edited Section Release Date', {
|
||||
'course': course_location_analytics,
|
||||
'id': id,
|
||||
'start': start
|
||||
});
|
||||
|
||||
// call into server to commit the new order
|
||||
$.ajax({
|
||||
url: "/save_item",
|
||||
|
||||
@@ -77,11 +77,18 @@ CMS.Views.Checklists = Backbone.View.extend({
|
||||
var task_index = $checkbox.data('task');
|
||||
var model = this.collection.at(checklist_index);
|
||||
model.attributes.items[task_index].is_checked = $task.hasClass(completed);
|
||||
|
||||
model.save({},
|
||||
{
|
||||
success : function() {
|
||||
var updatedTemplate = self.renderTemplate(model, checklist_index);
|
||||
self.$el.find('#course-checklist'+checklist_index).first().replaceWith(updatedTemplate);
|
||||
|
||||
analytics.track('Toggled a Checklist Task', {
|
||||
'course': course_location_analytics,
|
||||
'task': model.attributes.items[task_index].short_description,
|
||||
'state': model.attributes.items[task_index].is_checked
|
||||
});
|
||||
},
|
||||
error : CMS.ServerError
|
||||
});
|
||||
|
||||
@@ -107,6 +107,11 @@ CMS.Views.ClassInfoUpdateView = Backbone.View.extend({
|
||||
// push change to display, hide the editor, submit the change
|
||||
targetModel.save({}, {error : CMS.ServerError});
|
||||
this.closeEditor(this);
|
||||
|
||||
analytics.track('Saved Course Update', {
|
||||
'course': course_location_analytics,
|
||||
'date': this.dateEntry(event).val()
|
||||
});
|
||||
},
|
||||
|
||||
onCancel: function(event) {
|
||||
@@ -147,6 +152,11 @@ CMS.Views.ClassInfoUpdateView = Backbone.View.extend({
|
||||
return;
|
||||
}
|
||||
|
||||
analytics.track('Deleted Course Update', {
|
||||
'course': course_location_analytics,
|
||||
'date': this.dateEntry(event).val()
|
||||
});
|
||||
|
||||
var targetModel = this.eventModel(event);
|
||||
this.modelDom(event).remove();
|
||||
var cacheThis = this;
|
||||
@@ -284,6 +294,11 @@ CMS.Views.ClassInfoHandoutsView = Backbone.View.extend({
|
||||
this.model.save({}, {error: CMS.ServerError});
|
||||
this.$form.hide();
|
||||
this.closeEditor(this);
|
||||
|
||||
analytics.track('Saved Course Handouts', {
|
||||
'course': course_location_analytics
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
onCancel: function(event) {
|
||||
|
||||
@@ -137,6 +137,10 @@ CMS.Views.Settings.Advanced = CMS.Views.ValidatingView.extend({
|
||||
success : function() {
|
||||
self.render();
|
||||
self.showMessage(self.successful_changes);
|
||||
analytics.track('Saved Advanced Settings', {
|
||||
'course': course_location_analytics
|
||||
});
|
||||
|
||||
},
|
||||
error : CMS.ServerError
|
||||
});
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
<link rel="stylesheet" type="text/css" href="${static.url('css/vendor/symbolset.ss-symbolicons-block.css')}" />
|
||||
<link rel="stylesheet" type="text/css" href="${static.url('css/vendor/symbolset.ss-standard.css')}" />
|
||||
|
||||
<%include file="widgets/segment-io.html" />
|
||||
|
||||
<%block name="header_extras"></%block>
|
||||
</head>
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
});
|
||||
});
|
||||
|
||||
var unit_location_analytics = '${unit_location}';
|
||||
</script>
|
||||
|
||||
</%block>
|
||||
|
||||
32
cms/templates/widgets/segment-io.html
Normal file
32
cms/templates/widgets/segment-io.html
Normal file
@@ -0,0 +1,32 @@
|
||||
% if settings.MITX_FEATURES.get('SEGMENT_IO'):
|
||||
<!-- begin Segment.io -->
|
||||
<script type="text/javascript">
|
||||
// if inside course, inject the course location into the JS namespace
|
||||
%if context_course:
|
||||
var course_location_analytics = "${context_course.location}";
|
||||
%endif
|
||||
|
||||
var analytics=analytics||[];analytics.load=function(e){var t=document.createElement("script");t.type="text/javascript",t.async=!0,t.src=("https:"===document.location.protocol?"https://":"http://")+"d2dq2ahtl5zl1z.cloudfront.net/analytics.js/v1/"+e+"/analytics.min.js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(t,n);var r=function(e){return function(){analytics.push([e].concat(Array.prototype.slice.call(arguments,0)))}},i=["identify","track","trackLink","trackForm","trackClick","trackSubmit","pageview","ab","alias","ready"];for(var s=0;s<i.length;s++)analytics[i[s]]=r(i[s])};
|
||||
analytics.load("${ settings.SEGMENT_IO_KEY }");
|
||||
|
||||
% if user.is_authenticated():
|
||||
analytics.identify("${ user.id }", {
|
||||
email : "${ user.email }",
|
||||
username : "${ user.username }"
|
||||
});
|
||||
|
||||
% endif
|
||||
</script>
|
||||
<!-- end Segment.io -->
|
||||
% else:
|
||||
<!-- dummy segment.io -->
|
||||
<script type="text/javascript">
|
||||
%if context_course:
|
||||
var course_location_analytics = "${context_course.location}";
|
||||
%endif
|
||||
var analytics = {
|
||||
track: function() { return; }
|
||||
};
|
||||
</script>
|
||||
<!-- end dummy segment.io -->
|
||||
% endif
|
||||
Reference in New Issue
Block a user