Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
f1ccf1c0
Commit
f1ccf1c0
authored
Sep 09, 2013
by
Renzo Lucioni
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Integrate split testing and LMS tabs experiments
parent
fd06640d
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
184 additions
and
73 deletions
+184
-73
lms/djangoapps/courseware/tabs.py
+65
-34
lms/djangoapps/courseware/tests/test_tabs.py
+29
-28
lms/djangoapps/courseware/views.py
+1
-0
lms/envs/common.py
+15
-1
lms/envs/dev.py
+1
-1
lms/static/sass/course/layout/_courseware_header.scss
+11
-0
lms/templates/courseware/course_navigation.html
+8
-3
lms/templates/courseware/welcome-back.html
+33
-1
lms/templates/dashboard.html
+7
-1
lms/templates/widgets/segment-io.html
+12
-4
lms/urls.py
+1
-0
requirements/edx/github.txt
+1
-0
No files found.
lms/djangoapps/courseware/tabs.py
View file @
f1ccf1c0
This diff is collapsed.
Click to expand it.
lms/djangoapps/courseware/tests/test_tabs.py
View file @
f1ccf1c0
...
...
@@ -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
):
...
...
lms/djangoapps/courseware/views.py
View file @
f1ccf1c0
...
...
@@ -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'
)
...
...
lms/envs/common.py
View file @
f1ccf1c0
...
...
@@ -80,7 +80,7 @@ MITX_FEATURES = {
'ENABLE_PSYCHOMETRICS'
:
False
,
# real-time psychometrics (eg item response theory analysis in instructor dashboard)
'ENABLE_DJANGO_ADMIN_SITE'
:
Fals
e
,
# set true to enable django's admin site, even on prod (e.g. for course ops)
'ENABLE_DJANGO_ADMIN_SITE'
:
Tru
e
,
# 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'
,
...
...
lms/envs/dev.py
View file @
f1ccf1c0
...
...
@@ -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
...
...
lms/static/sass/course/layout/_courseware_header.scss
View file @
f1ccf1c0
...
...
@@ -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
;
...
...
lms/templates/courseware/course_navigation.html
View file @
f1ccf1c0
...
...
@@ -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>
...
...
lms/templates/courseware/welcome-back.html
View file @
f1ccf1c0
<
%!
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
&
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
&
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
lms/templates/dashboard.html
View file @
f1ccf1c0
...
...
@@ -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:
...
...
lms/templates/widgets/segment-io.html
View file @
f1ccf1c0
% 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>
...
...
lms/urls.py
View file @
f1ccf1c0
...
...
@@ -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"):
...
...
requirements/edx/github.txt
View file @
f1ccf1c0
...
...
@@ -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
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment