Commit f1ccf1c0 by Renzo Lucioni

Integrate split testing and LMS tabs experiments

parent fd06640d
......@@ -11,6 +11,7 @@ from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE
FAKE_REQUEST = None
class ProgressTestCase(TestCase):
......@@ -29,20 +30,20 @@ class ProgressTestCase(TestCase):
def test_progress(self):
self.assertEqual(tabs._progress(self.tab, self.mockuser0, self.course,
self.active_page0), [])
self.active_page0, FAKE_REQUEST), [])
self.assertEqual(tabs._progress(self.tab, self.mockuser1, self.course,
self.active_page1)[0].name, 'same')
self.active_page1, FAKE_REQUEST)[0].name, 'same')
self.assertEqual(tabs._progress(self.tab, self.mockuser1, self.course,
self.active_page1)[0].link,
self.active_page1, FAKE_REQUEST)[0].link,
reverse('progress', args=[self.course.id]))
self.assertEqual(tabs._progress(self.tab, self.mockuser1, self.course,
self.active_page0)[0].is_active, False)
self.active_page0, FAKE_REQUEST)[0].is_active, False)
self.assertEqual(tabs._progress(self.tab, self.mockuser1, self.course,
self.active_page1)[0].is_active, True)
self.active_page1, FAKE_REQUEST)[0].is_active, True)
class WikiTestCase(TestCase):
......@@ -60,26 +61,26 @@ class WikiTestCase(TestCase):
def test_wiki_enabled(self):
self.assertEqual(tabs._wiki(self.tab, self.user,
self.course, self.active_page1)[0].name,
self.course, self.active_page1, FAKE_REQUEST)[0].name,
'same')
self.assertEqual(tabs._wiki(self.tab, self.user,
self.course, self.active_page1)[0].link,
self.course, self.active_page1, FAKE_REQUEST)[0].link,
reverse('course_wiki', args=[self.course.id]))
self.assertEqual(tabs._wiki(self.tab, self.user,
self.course, self.active_page1)[0].is_active,
self.course, self.active_page1, FAKE_REQUEST)[0].is_active,
True)
self.assertEqual(tabs._wiki(self.tab, self.user,
self.course, self.active_page0)[0].is_active,
self.course, self.active_page0, FAKE_REQUEST)[0].is_active,
False)
@override_settings(WIKI_ENABLED=False)
def test_wiki_enabled_false(self):
self.assertEqual(tabs._wiki(self.tab, self.user,
self.course, self.active_page1), [])
self.course, self.active_page1, FAKE_REQUEST), [])
class ExternalLinkTestCase(TestCase):
......@@ -95,19 +96,19 @@ class ExternalLinkTestCase(TestCase):
def test_external_link(self):
self.assertEqual(tabs._external_link(self.tabby, self.user,
self.course, self.active_page0)[0].name,
self.course, self.active_page0, FAKE_REQUEST)[0].name,
'same')
self.assertEqual(tabs._external_link(self.tabby, self.user,
self.course, self.active_page0)[0].link,
self.course, self.active_page0, FAKE_REQUEST)[0].link,
'blink')
self.assertEqual(tabs._external_link(self.tabby, self.user,
self.course, self.active_page0)[0].is_active,
self.course, self.active_page0, FAKE_REQUEST)[0].is_active,
False)
self.assertEqual(tabs._external_link(self.tabby, self.user,
self.course, self.active_page00)[0].is_active,
self.course, self.active_page00, FAKE_REQUEST)[0].is_active,
False)
......@@ -125,20 +126,20 @@ class StaticTabTestCase(TestCase):
def test_static_tab(self):
self.assertEqual(tabs._static_tab(self.tabby, self.user,
self.course, self.active_page1)[0].name,
self.course, self.active_page1, FAKE_REQUEST)[0].name,
'same')
self.assertEqual(tabs._static_tab(self.tabby, self.user,
self.course, self.active_page1)[0].link,
self.course, self.active_page1, FAKE_REQUEST)[0].link,
reverse('static_tab', args=[self.course.id,
self.tabby['url_slug']]))
self.assertEqual(tabs._static_tab(self.tabby, self.user,
self.course, self.active_page1)[0].is_active,
self.course, self.active_page1, FAKE_REQUEST)[0].is_active,
True)
self.assertEqual(tabs._static_tab(self.tabby, self.user,
self.course, self.active_page0)[0].is_active,
self.course, self.active_page0, FAKE_REQUEST)[0].is_active,
False)
......@@ -166,45 +167,45 @@ class TextbooksTestCase(TestCase):
def test_textbooks1(self):
self.assertEqual(tabs._textbooks(self.tab, self.mockuser1,
self.course, self.active_page0)[0].name,
self.course, self.active_page0, FAKE_REQUEST)[0].name,
'Algebra')
self.assertEqual(tabs._textbooks(self.tab, self.mockuser1,
self.course, self.active_page0)[0].link,
self.course, self.active_page0, FAKE_REQUEST)[0].link,
reverse('book', args=[self.course.id, 0]))
self.assertEqual(tabs._textbooks(self.tab, self.mockuser1,
self.course, self.active_page0)[0].is_active,
self.course, self.active_page0, FAKE_REQUEST)[0].is_active,
True)
self.assertEqual(tabs._textbooks(self.tab, self.mockuser1,
self.course, self.active_pageX)[0].is_active,
self.course, self.active_pageX, FAKE_REQUEST)[0].is_active,
False)
self.assertEqual(tabs._textbooks(self.tab, self.mockuser1,
self.course, self.active_page1)[1].name,
self.course, self.active_page1, FAKE_REQUEST)[1].name,
'Topology')
self.assertEqual(tabs._textbooks(self.tab, self.mockuser1,
self.course, self.active_page1)[1].link,
self.course, self.active_page1, FAKE_REQUEST)[1].link,
reverse('book', args=[self.course.id, 1]))
self.assertEqual(tabs._textbooks(self.tab, self.mockuser1,
self.course, self.active_page1)[1].is_active,
self.course, self.active_page1, FAKE_REQUEST)[1].is_active,
True)
self.assertEqual(tabs._textbooks(self.tab, self.mockuser1,
self.course, self.active_pageX)[1].is_active,
self.course, self.active_pageX, FAKE_REQUEST)[1].is_active,
False)
@override_settings(MITX_FEATURES={'ENABLE_TEXTBOOK': False})
def test_textbooks0(self):
self.assertEqual(tabs._textbooks(self.tab, self.mockuser1,
self.course, self.active_pageX), [])
self.course, self.active_pageX, FAKE_REQUEST), [])
self.assertEqual(tabs._textbooks(self.tab, self.mockuser0,
self.course, self.active_pageX), [])
self.course, self.active_pageX, FAKE_REQUEST), [])
class KeyCheckerTestCase(TestCase):
......
......@@ -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 src="${ reverse('wafflejs') }"></script> -->
<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