Commit c124a330 by Renzo Lucioni

Merge pull request #829 from edx/renzo/ab-testing

Split Testing
parents 82af8d4b ac0e65ab
......@@ -5,6 +5,8 @@ These are notable changes in edx-platform. This is a rolling list of changes,
in roughly chronological order, most recent first. Add your entries at or near
the top. Include a label indicating the component affected.
LMS: Add split testing functionality for internal use.
LMS: Improved accessibility of parts of forum navigation sidebar.
LMS: enhanced accessibility labeling and aria support for the discussion forum new post dropdown as well as response and comment area labeling.
......
......@@ -728,6 +728,7 @@ def submission_history(request, course_id, student_username, location):
Right now this only works for problems because that's all
StudentModuleHistory records.
"""
course = get_course_with_access(request.user, course_id, 'load')
staff_access = has_access(request.user, course, 'staff')
......
......@@ -80,7 +80,7 @@ MITX_FEATURES = {
'ENABLE_PSYCHOMETRICS': False, # real-time psychometrics (eg item response theory analysis in instructor dashboard)
'ENABLE_DJANGO_ADMIN_SITE': False, # set true to enable django's admin site, even on prod (e.g. for course ops)
'ENABLE_DJANGO_ADMIN_SITE': True, # set true to enable django's admin site, even on prod (e.g. for course ops)
'ENABLE_SQL_TRACKING_LOGS': False,
'ENABLE_LMS_MIGRATION': False,
'ENABLE_MANUAL_GIT_RELOAD': False,
......@@ -523,6 +523,14 @@ MOCK_STAFF_GRADING = False
################################# Jasmine ###################################
JASMINE_TEST_DIRECTORY = PROJECT_ROOT + '/static/coffee'
################################# Waffle ###################################
# Name prepended to cookies set by Waffle
WAFFLE_COOKIE = "waffle_flag_%s"
# Two weeks (in sec)
WAFFLE_MAX_AGE = 1209600
################################# Middleware ###################################
# List of finder classes that know how to find static files in
# various locations.
......@@ -570,6 +578,9 @@ MIDDLEWARE_CLASSES = (
# catches any uncaught RateLimitExceptions and returns a 403 instead of a 500
'ratelimitbackend.middleware.RateLimitMiddleware',
# For A/B testing
'waffle.middleware.WaffleMiddleware',
)
############################### Pipeline #######################################
......@@ -832,6 +843,9 @@ INSTALLED_APPS = (
# Foldit integration
'foldit',
# For A/B testing
'waffle',
# For testing
'django.contrib.admin', # only used in DEBUG mode
'django_nose',
......
......@@ -255,7 +255,7 @@ ANALYTICS_API_KEY = ""
##### segment-io ######
# If there's an environment variable set, grab it and turn on 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:
MITX_FEATURES['SEGMENT_IO_LMS'] = True
......
......@@ -23,6 +23,17 @@ nav.course-material {
list-style: none;
margin-right: 6px;
&.prominent {
margin-right: 16px;
background: rgba(255, 255, 255, .5);
border-radius: 3px;
}
&.prominent + li {
padding-left: 15px;
border-left: 1px solid #333;
}
a {
border-radius: 3px;
color: #555;
......
......@@ -13,19 +13,24 @@ def url_class(is_active):
%>
<%! from courseware.tabs import get_course_tabs %>
<%! from django.utils.translation import ugettext as _ %>
<% import waffle %>
<nav class="${active_page} course-material">
<div class="inner-wrapper">
<ol class="course-tabs">
% for tab in get_course_tabs(user, course, active_page):
% for tab in get_course_tabs(user, course, active_page, request):
% if waffle.flag_is_active(request, 'visual_treatment') or waffle.flag_is_active(request, 'merge_course_tabs'):
<li class="${"prominent" if tab.name in ("Courseware", "Course Content") else ""}">
% else:
<li>
% endif
<a href="${tab.link | h}" class="${url_class(tab.is_active)}">
${tab.name | h}
% if tab.is_active == True:
<span class="sr">, current location</span>
<span class="sr">, current location</span>
%endif
% if tab.has_img == True:
<img src="${tab.img}"/>
<img src="${tab.img}"/>
%endif
</a>
</li>
......
<%! from django.utils.translation import ugettext as _ %>
<%!
from django.utils.translation import ugettext as _
import waffle
%>
<h2>${chapter_module.display_name_with_default}</h2>
<p>${_("You were most recently in {section_link}. If you\'re done with that, choose another section on the left.").format(
......@@ -7,3 +11,31 @@
section_name=prev_section.display_name_with_default,
)
)}</p>
% if waffle.flag_is_active(request, 'merge_course_tabs'):
<%! from courseware.courses import get_course_info_section %>
<section class="container">
<div class="info-wrapper">
% if user.is_authenticated():
<section class="updates">
<h1>${_("Course Updates &amp; News")}</h1>
${get_course_info_section(request, course, 'updates')}
</section>
<section aria-label="${_('Handout Navigation')}" class="handouts">
<h1>${course.info_sidebar_name}</h1>
${get_course_info_section(request, course, 'handouts')}
</section>
% else:
<section class="updates">
<h1>${_("Course Updates &amp; News")}</h1>
${get_course_info_section(request, course, 'guest_updates')}
</section>
<section aria-label="${_('Handout Navigation')}" class="handouts">
<h1>${_("Course Handouts")}</h1>
${get_course_info_section(request, course, 'guest_handouts')}
</section>
% endif
</div>
</section>
% endif
......@@ -5,8 +5,11 @@
from courseware.courses import course_image_url, get_course_about_section
from courseware.access import has_access
from certificates.models import CertificateStatuses
from xmodule.modulestore import MONGO_MODULESTORE_TYPE
from xmodule.modulestore.django import modulestore
import waffle
%>
<%inherit file="main.html" />
......@@ -163,7 +166,10 @@
<li class="course-item">
<article class="course ${enrollment.mode}">
<%
course_target = reverse('info', args=[course.id])
if waffle.flag_is_active(request, 'merge_course_tabs'):
course_target = reverse('courseware', args=[course.id])
else:
course_target = reverse('info', args=[course.id])
%>
% if course.id in show_courseware_links_for:
......
% if settings.MITX_FEATURES.get('SEGMENT_IO_LMS'):
<!-- begin Segment.io -->
<%! from django.core.urlresolvers import reverse %>
<%! import waffle %>
<% active_flags = " + ".join(waffle.get_flags(request)) %>
<script type="text/javascript">
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_LMS_KEY }");
% if user.is_authenticated():
analytics.identify("${ user.id }", {
email : "${ user.email }",
username : "${ user.username }"
});
analytics.identify("${ user.id }", {
email : "${ user.email }",
username : "${ user.username }",
"Active Flags" : "${ active_flags }",
});
% endif
</script>
......
......@@ -59,6 +59,7 @@ urlpatterns = ('', # nopep8
url(r'^user_api/', include('user_api.urls')),
url(r'^', include('waffle.urls')),
)
# if settings.MITX_FEATURES.get("MULTIPLE_ENROLLMENT_ROLES"):
......
......@@ -18,3 +18,4 @@
-e git+https://github.com/edx/codejail.git@0a1b468#egg=codejail
-e git+https://github.com/edx/diff-cover.git@v0.2.3#egg=diff_cover
-e git+https://github.com/edx/js-test-tool.git@v0.0.7#egg=js_test_tool
-e git+https://github.com/edx/django-waffle.git@823a102e48#egg=django-waffle
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment