Commit 8bc74af0 by Victor Shnayder

Integrate csv export of answer distributions with Ike's sweet dashboard

parent eb8d435b
...@@ -370,26 +370,3 @@ def progress(request, course_id, student_id=None): ...@@ -370,26 +370,3 @@ def progress(request, course_id, student_id=None):
return render_to_response('courseware/progress.html', context) return render_to_response('courseware/progress.html', context)
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
def answers_export(request, course_id):
"""
Export the distribution of student answers to all problems as a csv file.
- only displayed to course staff
"""
course = get_course_with_access(request.user, course_id, 'staff')
dist = grades.answer_distributions(request, course)
response = HttpResponse(mimetype='text/csv')
response['Content-Disposition'] = 'attachment; filename=%s' % "answer_distribution.csv"
writer = csv.writer(response)
for (url_name, display_name, answer_id), answers in dist.items():
# HEADER?
for a in answers:
writer.writerow([url_name, display_name, answer_id, a, answers[a]])
return response
...@@ -48,7 +48,7 @@ def instructor_dashboard(request, course_id): ...@@ -48,7 +48,7 @@ def instructor_dashboard(request, course_id):
"""Display the instructor dashboard for a course.""" """Display the instructor dashboard for a course."""
course = get_course_with_access(request.user, course_id, 'staff') course = get_course_with_access(request.user, course_id, 'staff')
instructor_access = has_access(request.user, course, 'instructor') # an instructor can manage staff lists instructor_access = has_access(request.user, course, 'instructor') # an instructor can manage staff lists
msg = '' msg = ''
# msg += ('POST=%s' % dict(request.POST)).replace('<','&lt;') # msg += ('POST=%s' % dict(request.POST)).replace('<','&lt;')
...@@ -99,7 +99,7 @@ def instructor_dashboard(request, course_id): ...@@ -99,7 +99,7 @@ def instructor_dashboard(request, course_id):
msg += "git pull on %s:<p>" % data_dir msg += "git pull on %s:<p>" % data_dir
msg += "<pre>%s</pre></p>" % escape(os.popen(cmd).read()) msg += "<pre>%s</pre></p>" % escape(os.popen(cmd).read())
track.views.server_track(request, 'git pull %s' % data_dir, {}, page='idashboard') track.views.server_track(request, 'git pull %s' % data_dir, {}, page='idashboard')
if 'Reload course' in action: if 'Reload course' in action:
log.debug('reloading %s (%s)' % (course_id, course)) log.debug('reloading %s (%s)' % (course_id, course))
try: try:
...@@ -144,6 +144,10 @@ def instructor_dashboard(request, course_id): ...@@ -144,6 +144,10 @@ def instructor_dashboard(request, course_id):
return return_csv('grades_%s_raw.csv' % course_id, return return_csv('grades_%s_raw.csv' % course_id,
get_student_grade_summary_data(request, course, course_id, get_raw_scores=True)) get_student_grade_summary_data(request, course, course_id, get_raw_scores=True))
elif 'Download CSV of answer distributions' in action:
track.views.server_track(request, 'dump-answer-dist-csv', {}, page='idashboard')
return return_csv('answer_dist_%s.csv' % course_id, get_answers_distribution(request, course_id))
elif 'List course staff' in action: elif 'List course staff' in action:
group = get_staff_group(course) group = get_staff_group(course)
msg += 'Staff group = %s' % group.name msg += 'Staff group = %s' % group.name
...@@ -290,7 +294,7 @@ def grade_summary(request, course_id): ...@@ -290,7 +294,7 @@ def grade_summary(request, course_id):
@ensure_csrf_cookie @ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True) @cache_control(no_cache=True, no_store=True, must_revalidate=True)
def enroll_students(request, course_id): def enroll_students(request, course_id):
''' Allows a staff member to enroll students in a course. """Allows a staff member to enroll students in a course.
This is a short-term hack for Berkeley courses launching fall This is a short-term hack for Berkeley courses launching fall
2012. In the long term, we would like functionality like this, but 2012. In the long term, we would like functionality like this, but
...@@ -300,7 +304,7 @@ def enroll_students(request, course_id): ...@@ -300,7 +304,7 @@ def enroll_students(request, course_id):
It is poorly written and poorly tested, but it's designed to be It is poorly written and poorly tested, but it's designed to be
stripped out. stripped out.
''' """
course = get_course_with_access(request.user, course_id, 'staff') course = get_course_with_access(request.user, course_id, 'staff')
existing_students = [ce.user.email for ce in CourseEnrollment.objects.filter(course_id=course_id)] existing_students = [ce.user.email for ce in CourseEnrollment.objects.filter(course_id=course_id)]
...@@ -328,6 +332,28 @@ def enroll_students(request, course_id): ...@@ -328,6 +332,28 @@ def enroll_students(request, course_id):
'rejected_students': rejected_students, 'rejected_students': rejected_students,
'debug': new_students}) 'debug': new_students})
def get_answers_distribution(request, course_id):
"""
Get the distribution of answers for all graded problems in the course.
Return a dict with two keys:
'header': a header row
'data': a list of rows
"""
course = get_course_with_access(request.user, course_id, 'staff')
dist = grades.answer_distributions(request, course)
d = {}
d['header'] = ['url_name', 'display name', 'answer id', 'answer', 'count']
d['data'] = [[url_name, display_name, answer_id, a, answers[a]]
for (url_name, display_name, answer_id), answers in dist.items()
for a in answers]
return d
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
......
...@@ -58,6 +58,9 @@ table.stat_table td { ...@@ -58,6 +58,9 @@ table.stat_table td {
<input type="submit" name="action" value="Dump all RAW grades for all students in this course"> <input type="submit" name="action" value="Dump all RAW grades for all students in this course">
<input type="submit" name="action" value="Download CSV of all RAW grades"> <input type="submit" name="action" value="Download CSV of all RAW grades">
<p>
<input type="submit" name="action" value="Download CSV of answer distributions">
%if instructor_access: %if instructor_access:
<hr width="40%" style="align:left"> <hr width="40%" style="align:left">
<p> <p>
......
...@@ -161,9 +161,6 @@ if settings.COURSEWARE_ENABLED: ...@@ -161,9 +161,6 @@ if settings.COURSEWARE_ENABLED:
'instructor.views.grade_summary', name='grade_summary'), 'instructor.views.grade_summary', name='grade_summary'),
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/enroll_students$', url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/enroll_students$',
'instructor.views.enroll_students', name='enroll_students'), 'instructor.views.enroll_students', name='enroll_students'),
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/answers_export$',
'courseware.views.answers_export', name='answers_export'),
) )
# discussion forums live within courseware, so courseware must be enabled first # discussion forums live within courseware, so courseware must be enabled first
...@@ -200,8 +197,8 @@ if settings.WIKI_ENABLED: ...@@ -200,8 +197,8 @@ if settings.WIKI_ENABLED:
) )
if settings.QUICKEDIT: if settings.QUICKEDIT:
urlpatterns += (url(r'^quickedit/(?P<id>[^/]*)$', 'dogfood.views.quickedit'),) urlpatterns += (url(r'^quickedit/(?P<id>[^/]*)$', 'dogfood.views.quickedit'),)
urlpatterns += (url(r'^dogfood/(?P<id>[^/]*)$', 'dogfood.views.df_capa_problem'),) urlpatterns += (url(r'^dogfood/(?P<id>[^/]*)$', 'dogfood.views.df_capa_problem'),)
if settings.ASKBOT_ENABLED: if settings.ASKBOT_ENABLED:
urlpatterns += (url(r'^%s' % settings.ASKBOT_URL, include('askbot.urls')), \ urlpatterns += (url(r'^%s' % settings.ASKBOT_URL, include('askbot.urls')), \
......
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