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
376fe0a5
Commit
376fe0a5
authored
Mar 17, 2015
by
Sarina Canelake
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Remove outdated Analytics scripts, code, and css
parent
4f2be41a
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
11 additions
and
442 deletions
+11
-442
lms/djangoapps/instructor/tests/test_api.py
+0
-0
lms/djangoapps/instructor/tests/views/test_instructor_dashboard.py
+11
-21
lms/djangoapps/instructor/views/api.py
+0
-106
lms/djangoapps/instructor/views/api_urls.py
+0
-4
lms/envs/common.py
+0
-3
lms/static/coffee/src/instructor_dashboard/instructor_analytics.coffee
+0
-241
lms/static/sass/course/instructor/_instructor_2.scss
+0
-67
No files found.
lms/djangoapps/instructor/tests/test_api.py
View file @
376fe0a5
This diff is collapsed.
Click to expand it.
lms/djangoapps/instructor/tests/views/test_instructor_dashboard.py
View file @
376fe0a5
...
...
@@ -54,11 +54,11 @@ class TestInstructorDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
return
'Enrollment data is now available in <a href="http://example.com/courses/{}" '
\
'target="_blank">Example</a>.'
.
format
(
unicode
(
self
.
course
.
id
))
def
get_dashboard_
demographic
_message
(
self
):
def
get_dashboard_
analytics
_message
(
self
):
"""
Returns expected dashboard demographic message with link to Insights.
"""
return
'
Demographic data is now available in
<a href="http://example.com/courses/{}" '
\
return
'
For analytics about your course, go to
<a href="http://example.com/courses/{}" '
\
'target="_blank">Example</a>.'
.
format
(
unicode
(
self
.
course
.
id
))
def
test_instructor_tab
(
self
):
...
...
@@ -157,38 +157,28 @@ class TestInstructorDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
expected_message
=
self
.
get_dashboard_enrollment_message
()
self
.
assertTrue
(
expected_message
in
response
.
content
)
@patch.dict
(
settings
.
FEATURES
,
{
'DISPLAY_ANALYTICS_DEMOGRAPHICS'
:
True
})
@override_settings
(
ANALYTICS_DASHBOARD_URL
=
''
)
@override_settings
(
ANALYTICS_DASHBOARD_NAME
=
''
)
def
test_
show_dashboard_demographic_data
(
self
):
def
test_
dashboard_analytics_tab_not_shown
(
self
):
"""
Test
enrollment demographic data is shown
.
Test
dashboard analytics tab isn't shown if insights isn't configured
.
"""
response
=
self
.
client
.
get
(
self
.
url
)
# demographic information displayed
self
.
assertTrue
(
'data-feature="year_of_birth"'
in
response
.
content
)
self
.
assertTrue
(
'data-feature="gender"'
in
response
.
content
)
self
.
assertTrue
(
'data-feature="level_of_education"'
in
response
.
content
)
analytics_section
=
'<li class="nav-item"><a href="" data-section="instructor_analytics">Analytics</a></li>'
self
.
assertFalse
(
analytics_section
in
response
.
content
)
# dashboard link hidden
self
.
assertFalse
(
self
.
get_dashboard_demographic_message
()
in
response
.
content
)
@patch.dict
(
settings
.
FEATURES
,
{
'DISPLAY_ANALYTICS_DEMOGRAPHICS'
:
False
})
@override_settings
(
ANALYTICS_DASHBOARD_URL
=
'http://example.com'
)
@override_settings
(
ANALYTICS_DASHBOARD_NAME
=
'Example'
)
def
test_
show_dashboard_demographic_message
(
self
):
def
test_
dashboard_analytics_points_at_insights
(
self
):
"""
Test
enrollment demographic dashboard message is shown and data is hidden.
Test
analytics dashboard message is shown
"""
response
=
self
.
client
.
get
(
self
.
url
)
# demographics are hidden
self
.
assertFalse
(
'data-feature="year_of_birth"'
in
response
.
content
)
self
.
assertFalse
(
'data-feature="gender"'
in
response
.
content
)
self
.
assertFalse
(
'data-feature="level_of_education"'
in
response
.
content
)
analytics_section
=
'<li class="nav-item"><a href="" data-section="instructor_analytics">Analytics</a></li>'
self
.
assertTrue
(
analytics_section
in
response
.
content
)
# link to dashboard shown
expected_message
=
self
.
get_dashboard_
demographic
_message
()
expected_message
=
self
.
get_dashboard_
analytics
_message
()
self
.
assertTrue
(
expected_message
in
response
.
content
)
def
add_course_to_user_cart
(
self
,
cart
,
course_key
):
...
...
lms/djangoapps/instructor/views/api.py
View file @
376fe0a5
...
...
@@ -1647,56 +1647,6 @@ def get_anon_ids(request, course_id): # pylint: disable=unused-argument
@ensure_csrf_cookie
@cache_control
(
no_cache
=
True
,
no_store
=
True
,
must_revalidate
=
True
)
@require_level
(
'staff'
)
def
get_distribution
(
request
,
course_id
):
"""
Respond with json of the distribution of students over selected features which have choices.
Ask for a feature through the `feature` query parameter.
If no `feature` is supplied, will return response with an
empty response['feature_results'] object.
A list of available will be available in the response['available_features']
"""
course_id
=
SlashSeparatedCourseKey
.
from_deprecated_string
(
course_id
)
feature
=
request
.
GET
.
get
(
'feature'
)
# alternate notations of None
if
feature
in
(
None
,
'null'
,
''
):
feature
=
None
else
:
feature
=
str
(
feature
)
available_features
=
instructor_analytics
.
distributions
.
AVAILABLE_PROFILE_FEATURES
# allow None so that requests for no feature can list available features
if
feature
not
in
available_features
+
(
None
,):
return
HttpResponseBadRequest
(
strip_tags
(
"feature '{}' not available."
.
format
(
feature
)
))
response_payload
=
{
'course_id'
:
course_id
.
to_deprecated_string
(),
'queried_feature'
:
feature
,
'available_features'
:
available_features
,
'feature_display_names'
:
instructor_analytics
.
distributions
.
DISPLAY_NAMES
,
}
p_dist
=
None
if
feature
is
not
None
:
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
,
'data'
:
p_dist
.
data
,
'type'
:
p_dist
.
type
,
}
if
p_dist
.
type
==
'EASY_CHOICE'
:
response_payload
[
'feature_results'
][
'choices_display_names'
]
=
p_dist
.
choices_display_names
return
JsonResponse
(
response_payload
)
@ensure_csrf_cookie
@cache_control
(
no_cache
=
True
,
no_store
=
True
,
must_revalidate
=
True
)
@common_exceptions_400
@require_level
(
'staff'
)
@require_query_params
(
...
...
@@ -2361,62 +2311,6 @@ def update_forum_role_membership(request, course_id):
return
JsonResponse
(
response_payload
)
@ensure_csrf_cookie
@cache_control
(
no_cache
=
True
,
no_store
=
True
,
must_revalidate
=
True
)
@require_level
(
'staff'
)
@require_query_params
(
aname
=
"name of analytic to query"
,
)
@common_exceptions_400
def
proxy_legacy_analytics
(
request
,
course_id
):
"""
Proxies to the analytics cron job server.
`aname` is a query parameter specifying which analytic to query.
"""
course_id
=
SlashSeparatedCourseKey
.
from_deprecated_string
(
course_id
)
analytics_name
=
request
.
GET
.
get
(
'aname'
)
# abort if misconfigured
if
not
(
hasattr
(
settings
,
'ANALYTICS_SERVER_URL'
)
and
hasattr
(
settings
,
'ANALYTICS_API_KEY'
)
and
settings
.
ANALYTICS_SERVER_URL
and
settings
.
ANALYTICS_API_KEY
):
return
HttpResponse
(
"Analytics service not configured."
,
status
=
501
)
url
=
"{}get?aname={}&course_id={}&apikey={}"
.
format
(
settings
.
ANALYTICS_SERVER_URL
,
analytics_name
,
urllib
.
quote
(
unicode
(
course_id
)),
settings
.
ANALYTICS_API_KEY
,
)
try
:
res
=
requests
.
get
(
url
)
except
Exception
:
# pylint: disable=broad-except
log
.
exception
(
u"Error requesting from analytics server at
%
s"
,
url
)
return
HttpResponse
(
"Error requesting from analytics server."
,
status
=
500
)
if
res
.
status_code
is
200
:
payload
=
json
.
loads
(
res
.
content
)
add_block_ids
(
payload
)
content
=
json
.
dumps
(
payload
)
# return the successful request content
return
HttpResponse
(
content
,
content_type
=
"application/json"
)
elif
res
.
status_code
is
404
:
# forward the 404 and content
return
HttpResponse
(
res
.
content
,
content_type
=
"application/json"
,
status
=
404
)
else
:
# 500 on all other unexpected status codes.
log
.
error
(
u"Error fetching
%
s, code:
%
s, msg:
%
s"
,
url
,
res
.
status_code
,
res
.
content
)
return
HttpResponse
(
"Error from analytics server ({})."
.
format
(
res
.
status_code
),
status
=
500
)
@require_POST
def
get_user_invoice_preference
(
request
,
course_id
):
# pylint: disable=unused-argument
"""
...
...
lms/djangoapps/instructor/views/api_urls.py
View file @
376fe0a5
...
...
@@ -33,8 +33,6 @@ urlpatterns = patterns(
'instructor.views.api.sale_validation'
,
name
=
"sale_validation"
),
url
(
r'^get_anon_ids$'
,
'instructor.views.api.get_anon_ids'
,
name
=
"get_anon_ids"
),
url
(
r'^get_distribution$'
,
'instructor.views.api.get_distribution'
,
name
=
"get_distribution"
),
url
(
r'^get_student_progress_url$'
,
'instructor.views.api.get_student_progress_url'
,
name
=
"get_student_progress_url"
),
url
(
r'^reset_student_attempts$'
,
...
...
@@ -71,8 +69,6 @@ urlpatterns = patterns(
'instructor.views.api.list_forum_members'
,
name
=
"list_forum_members"
),
url
(
r'^update_forum_role_membership$'
,
'instructor.views.api.update_forum_role_membership'
,
name
=
"update_forum_role_membership"
),
url
(
r'^proxy_legacy_analytics$'
,
'instructor.views.api.proxy_legacy_analytics'
,
name
=
"proxy_legacy_analytics"
),
url
(
r'^send_email$'
,
'instructor.views.api.send_email'
,
name
=
"send_email"
),
url
(
r'^change_due_date$'
,
'instructor.views.api.change_due_date'
,
...
...
lms/envs/common.py
View file @
376fe0a5
...
...
@@ -334,9 +334,6 @@ FEATURES = {
# and register for course.
'ALLOW_AUTOMATED_SIGNUPS'
:
False
,
# Display demographic data on the analytics tab in the instructor dashboard.
'DISPLAY_ANALYTICS_DEMOGRAPHICS'
:
True
,
# Enable display of enrollment counts in instructor dash, analytics section
'DISPLAY_ANALYTICS_ENROLLMENTS'
:
True
,
...
...
lms/static/coffee/src/instructor_dashboard/instructor_analytics.coffee
deleted
100644 → 0
View file @
4f2be41a
###
Analytics Section
imports from other modules.
wrap in (-> ... apply) to defer evaluation
such that the value can be defined later than this assignment (file load order).
###
plantTimeout
=
->
window
.
InstructorDashboard
.
util
.
plantTimeout
.
apply
this
,
arguments
std_ajax_err
=
->
window
.
InstructorDashboard
.
util
.
std_ajax_err
.
apply
this
,
arguments
class
ProfileDistributionWidget
constructor
:
({
@
$container
,
@
feature
,
@
title
,
@
endpoint
})
->
# render template
template_params
=
title
:
@
title
feature
:
@
feature
endpoint
:
@
endpoint
template_html
=
$
(
"#profile-distribution-widget-template"
).
text
()
@
$container
.
html
Mustache
.
render
template_html
,
template_params
reset_display
:
->
@
$container
.
find
(
'.display-errors'
).
empty
()
@
$container
.
find
(
'.display-text'
).
empty
()
@
$container
.
find
(
'.display-graph'
).
empty
()
@
$container
.
find
(
'.display-table'
).
empty
()
show_error
:
(
msg
)
->
@
$container
.
find
(
'.display-errors'
).
text
msg
# display data
load
:
->
@
reset_display
()
@
get_profile_distributions
@
feature
,
error
:
std_ajax_err
=>
`//
Translators
:
"Distribution"
refers
to
a
grade
distribution
.
This
error
message
appears
when
there
is
an
error
getting
the
data
on
grade
distribution
.
`
@
show_error
gettext
(
"Error fetching distribution."
)
success
:
(
data
)
=>
feature_res
=
data
.
feature_results
if
feature_res
.
type
is
'EASY_CHOICE'
# display on SlickGrid
options
=
enableCellNavigation
:
true
enableColumnReorder
:
false
forceFitColumns
:
true
columns
=
[
id
:
@
feature
field
:
@
feature
name
:
data
.
feature_display_names
[
@
feature
]
,
id
:
'count'
field
:
'count'
name
:
'Count'
]
grid_data
=
_
.
map
feature_res
.
data
,
(
value
,
key
)
=>
datapoint
=
{}
datapoint
[
@
feature
]
=
feature_res
.
choices_display_names
[
key
]
datapoint
[
'count'
]
=
value
datapoint
table_placeholder
=
$
'<div/>'
,
class
:
'slickgrid'
@
$container
.
find
(
'.display-table'
).
append
table_placeholder
grid
=
new
Slick
.
Grid
(
table_placeholder
,
grid_data
,
columns
,
options
)
else
if
feature_res
.
feature
is
'year_of_birth'
graph_placeholder
=
$
'<div/>'
,
class
:
'graph-placeholder'
@
$container
.
find
(
'.display-graph'
).
append
graph_placeholder
graph_data
=
_
.
map
feature_res
.
data
,
(
value
,
key
)
->
[
parseInt
(
key
),
value
]
$
.
plot
graph_placeholder
,
[
data
:
graph_data
]
else
console
.
warn
(
"unable to show distribution
#{
feature_res
.
type
}
"
)
@
show_error
gettext
(
'Unavailable metric display.'
)
# fetch distribution data from server.
# `handler` can be either a callback for success
# or a mapping e.g. {success: ->, error: ->, complete: ->}
get_profile_distributions
:
(
feature
,
handler
)
->
settings
=
dataType
:
'json'
url
:
@
endpoint
data
:
feature
:
feature
if
typeof
handler
is
'function'
_
.
extend
settings
,
success
:
handler
else
_
.
extend
settings
,
handler
$
.
ajax
settings
class
GradeDistributionDisplay
constructor
:
({
@
$container
,
@
endpoint
})
->
template_params
=
{}
template_html
=
$
(
'#grade-distributions-widget-template'
).
text
()
@
$container
.
html
Mustache
.
render
template_html
,
template_params
@
$problem_selector
=
@
$container
.
find
'.problem-selector'
reset_display
:
->
@
$container
.
find
(
'.display-errors'
).
empty
()
@
$container
.
find
(
'.display-text'
).
empty
()
@
$container
.
find
(
'.display-graph'
).
empty
()
show_error
:
(
msg
)
->
@
$container
.
find
(
'.display-errors'
).
text
msg
load
:
->
@
get_grade_distributions
error
:
std_ajax_err
=>
@
show_error
gettext
(
"Error fetching grade distributions."
)
success
:
(
data
)
=>
time_updated
=
gettext
(
"Last Updated: <%= timestamp %>"
)
full_time_updated
=
_
.
template
(
time_updated
,
{
timestamp
:
data
.
time
})
@
$container
.
find
(
'.last-updated'
).
text
full_time_updated
# populate selector
@
$problem_selector
.
empty
()
for
{
module_id
,
block_id
,
grade_info
}
in
data
.
data
label
=
block_id
label
?=
module_id
@
$problem_selector
.
append
$
'<option/>'
,
text
:
label
data
:
module_id
:
module_id
grade_info
:
grade_info
@
$problem_selector
.
change
=>
$opt
=
@
$problem_selector
.
children
(
'option:selected'
)
return
unless
$opt
.
length
>
0
@
reset_display
()
@
render_distribution
module_id
:
$opt
.
data
'module_id'
grade_info
:
$opt
.
data
'grade_info'
# one-time first selection of first list item.
@
$problem_selector
.
change
()
render_distribution
:
({
module_id
,
grade_info
})
->
$display_graph
=
@
$container
.
find
(
'.display-graph'
)
graph_data
=
grade_info
.
map
({
grade
,
max_grade
,
num_students
})
->
[
grade
,
num_students
]
total_students
=
_
.
reduce
([
0
].
concat
grade_info
),
(
accum
,
{
grade
,
max_grade
,
num_students
})
->
accum
+
num_students
msg
=
gettext
(
"<%= num_students %> students scored."
)
full_msg
=
_
.
template
(
msg
,
{
num_students
:
total_students
})
# show total students
@
$container
.
find
(
'.display-text'
).
text
full_msg
# render to graph
graph_placeholder
=
$
'<div/>'
,
class
:
'graph-placeholder'
$display_graph
.
append
graph_placeholder
graph_data
=
graph_data
$
.
plot
graph_placeholder
,
[
data
:
graph_data
bars
:
show
:
true
color
:
'#1d9dd9'
]
# `handler` can be either a callback for success
# or a mapping e.g. {success: ->, error: ->, complete: ->}
#
# the data passed to the success handler takes this form:
# {
# "aname": "ProblemGradeDistribution",
# "time": "2013-07-31T20:25:56+00:00",
# "course_id": "MITx/6.002x/2013_Spring",
# "options": {
# "course_id": "MITx/6.002x/2013_Spring",
# "_id": "6fudge2b49somedbid1e1",
# "data": [
# {
# "module_id": "i4x://MITx/6.002x/problem/Capacitors_and_Energy_Storage",
# "grade_info": [
# {
# "grade": 0.0,
# "max_grade": 100.0,
# "num_students": 3
# }, ... for each grade number between 0 and max_grade
# ],
# }
get_grade_distributions
:
(
handler
)
->
settings
=
dataType
:
'json'
url
:
@
endpoint
data
:
aname
:
'ProblemGradeDistribution'
if
typeof
handler
is
'function'
_
.
extend
settings
,
success
:
handler
else
_
.
extend
settings
,
handler
$
.
ajax
settings
# Analytics Section
class
InstructorAnalytics
constructor
:
(
@
$section
)
->
@
$section
.
data
'wrapper'
,
@
@
$pd_containers
=
@
$section
.
find
'.profile-distribution-widget-container'
@
$gd_containers
=
@
$section
.
find
'.grade-distributions-widget-container'
@
pdws
=
_
.
map
(
@
$pd_containers
),
(
container
)
=>
new
ProfileDistributionWidget
$container
:
$
(
container
)
feature
:
$
(
container
).
data
'feature'
title
:
$
(
container
).
data
'title'
endpoint
:
$
(
container
).
data
'endpoint'
@
gdws
=
_
.
map
(
@
$gd_containers
),
(
container
)
=>
new
GradeDistributionDisplay
$container
:
$
(
container
)
endpoint
:
$
(
container
).
data
'endpoint'
refresh
:
->
for
pdw
in
@
pdws
pdw
.
load
()
for
gdw
in
@
gdws
gdw
.
load
()
onClickTitle
:
->
@
refresh
()
# export for use
# create parent namespaces if they do not already exist.
_
.
defaults
window
,
InstructorDashboard
:
{}
_
.
defaults
window
.
InstructorDashboard
,
sections
:
{}
_
.
defaults
window
.
InstructorDashboard
.
sections
,
InstructorAnalytics
:
InstructorAnalytics
lms/static/sass/course/instructor/_instructor_2.scss
View file @
376fe0a5
...
...
@@ -1355,40 +1355,6 @@
}
}
.profile-distribution-widget
{
margin-bottom
:
(
$baseline
*
2
);
.display-graph
.graph-placeholder
{
width
:
750px
;
height
:
250px
;
}
.display-table
{
.slickgrid
{
height
:
250px
;
}
}
}
.grade-distributions-widget
{
margin-bottom
:
$baseline
*
2
;
.last-updated
{
line-height
:
2
.2em
;
@include
font-size
(
12
);
}
.display-graph
.graph-placeholder
{
width
:
750px
;
height
:
200px
;
}
.display-text
{
line-height
:
2em
;
}
}
input
[
name
=
"subject"
]
{
width
:
600px
;
}
...
...
@@ -1875,39 +1841,6 @@ input[name="subject"] {
}
.profile-distribution-widget
{
margin-bottom
:
(
$baseline
*
2
);
.display-graph
.graph-placeholder
{
width
:
750px
;
height
:
250px
;
}
.display-table
{
.slickgrid
{
height
:
250px
;
}
}
}
.grade-distributions-widget
{
margin-bottom
:
(
$baseline
*
2
);
.last-updated
{
line-height
:
2
.2em
;
@include
font-size
(
12
);
}
.display-graph
.graph-placeholder
{
width
:
750px
;
height
:
200px
;
}
.display-text
{
line-height
:
2em
;
}
}
input
[
name
=
"subject"
]
{
width
:
600px
;
}
...
...
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