From 09442ef4ac17c63ae097246c7fe15f450098dbc5 Mon Sep 17 00:00:00 2001 From: Sarina Canelake Date: Tue, 29 Apr 2014 09:33:47 -0400 Subject: [PATCH] Port spoc gradebook to new instructor dash LMS-1296 --- .../courseware/features/courseware_common.py | 5 ++ .../courseware/features/lti.feature | 3 +- .../instructor/views/instructor_dashboard.py | 51 ++++++++++++++++++- .../instructor_dashboard_2/student_admin.html | 15 ++++++ lms/urls.py | 2 + 5 files changed, 74 insertions(+), 2 deletions(-) diff --git a/lms/djangoapps/courseware/features/courseware_common.py b/lms/djangoapps/courseware/features/courseware_common.py index 1c836f8674..f3ba602951 100644 --- a/lms/djangoapps/courseware/features/courseware_common.py +++ b/lms/djangoapps/courseware/features/courseware_common.py @@ -14,6 +14,11 @@ def i_click_on_the_tab(step, tab_text): world.click_link(tab_text) +@step('I click on the "([^"]*)" link$') +def i_click_on_the_link(step, link_text): + world.click_link(link_text) + + @step('I visit the courseware URL$') def i_visit_the_course_info_url(step): world.visit('/courses/MITx/6.002x/2012_Fall/courseware') diff --git a/lms/djangoapps/courseware/features/lti.feature b/lms/djangoapps/courseware/features/lti.feature index eb888daede..ef8e85fedc 100644 --- a/lms/djangoapps/courseware/features/lti.feature +++ b/lms/djangoapps/courseware/features/lti.feature @@ -51,7 +51,8 @@ Feature: LMS.LTI component Then I see text "Problem Scores: 5/10" And I see graph with total progress "5%" Then I click on the "Instructor" tab - And I click on the "Gradebook" tab + And I click on the "Student Admin" tab + And I click on the "View Gradebook" link And I see in the gradebook table that "HW" is "50" And I see in the gradebook table that "Total" is "5" diff --git a/lms/djangoapps/instructor/views/instructor_dashboard.py b/lms/djangoapps/instructor/views/instructor_dashboard.py index 774bc2cf19..eb04338f68 100644 --- a/lms/djangoapps/instructor/views/instructor_dashboard.py +++ b/lms/djangoapps/instructor/views/instructor_dashboard.py @@ -6,6 +6,7 @@ from django.utils.translation import ugettext as _ from django_future.csrf import ensure_csrf_cookie from django.views.decorators.cache import cache_control from edxmako.shortcuts import render_to_response +from django.contrib.auth.models import User from django.core.urlresolvers import reverse from django.utils.html import escape from django.http import Http404 @@ -18,9 +19,10 @@ from xmodule.modulestore.django import modulestore from xblock.field_data import DictFieldData from xblock.fields import ScopeIds from courseware.access import has_access -from courseware.courses import get_course_by_id, get_cms_course_link +from courseware.courses import get_course_by_id, get_cms_course_link, get_course_with_access from django_comment_client.utils import has_forum_access from django_comment_common.models import FORUM_ROLE_ADMINISTRATOR +from instructor.offline_gradecalc import student_grades from student.models import CourseEnrollment from bulk_email.models import CourseAuthorization from class_dashboard.dashboard_data import get_section_display_name, get_array_section_has_problem @@ -156,15 +158,23 @@ def _section_membership(course_id, access): def _section_student_admin(course_id, access): """ Provide data for the corresponding dashboard section """ + is_small_course = False + enrollment_count = CourseEnrollment.num_enrolled_in(course_id) + max_enrollment_for_buttons = settings.FEATURES.get("MAX_ENROLLMENT_INSTR_BUTTONS") + if max_enrollment_for_buttons is not None: + is_small_course = enrollment_count <= max_enrollment_for_buttons + section_data = { 'section_key': 'student_admin', 'section_display_name': _('Student Admin'), 'access': access, + 'is_small_course': is_small_course, 'get_student_progress_url_url': reverse('get_student_progress_url', kwargs={'course_id': course_id}), 'enrollment_url': reverse('students_update_enrollment', kwargs={'course_id': course_id}), 'reset_student_attempts_url': reverse('reset_student_attempts', kwargs={'course_id': course_id}), 'rescore_problem_url': reverse('rescore_problem', kwargs={'course_id': course_id}), 'list_instructor_tasks_url': reverse('list_instructor_tasks', kwargs={'course_id': course_id}), + 'spoc_gradebook_url': reverse('spoc_gradebook', kwargs={'course_id': course_id}), } return section_data @@ -246,3 +256,42 @@ def _section_metrics(course_id, access): 'get_students_problem_grades_url': reverse('get_students_problem_grades'), } return section_data + +#---- Gradebook (shown to small courses only) ---- +@cache_control(no_cache=True, no_store=True, must_revalidate=True) +def spoc_gradebook(request, course_id): + """ + Show the gradebook for this course: + - Only shown for courses with enrollment < settings.FEATURES.get("MAX_ENROLLMENT_INSTR_BUTTONS") + - Only displayed to course staff + """ + course = get_course_with_access(request.user, course_id, 'staff', depth=None) + + enrolled_students = User.objects.filter( + courseenrollment__course_id=course_id, + courseenrollment__is_active=1 + ).order_by('username').select_related("profile") + + # TODO (vshnayder): implement pagination to show to large courses + max_num_students = settings.FEATURES.get("MAX_ENROLLMENT_INSTR_BUTTONS") + enrolled_students = enrolled_students[:max_num_students] # HACK! + + student_info = [ + { + 'username': student.username, + 'id': student.id, + 'email': student.email, + 'grade_summary': student_grades(student, request, course), + 'realname': student.profile.name, + } + for student in enrolled_students + ] + + return render_to_response('courseware/gradebook.html', { + 'students': student_info, + 'course': course, + 'course_id': course_id, + # Checked above + 'staff_access': True, + 'ordered_grades': sorted(course.grade_cutoffs.items(), key=lambda i: i[1], reverse=True), + }) diff --git a/lms/templates/instructor/instructor_dashboard_2/student_admin.html b/lms/templates/instructor/instructor_dashboard_2/student_admin.html index 1ff3e2727c..93856d6695 100644 --- a/lms/templates/instructor/instructor_dashboard_2/student_admin.html +++ b/lms/templates/instructor/instructor_dashboard_2/student_admin.html @@ -1,6 +1,21 @@ <%! from django.utils.translation import ugettext as _ %> <%page args="section_data"/> +
+ %if section_data['is_small_course']: + ## Show the gradebook for small courses +

${_("Student Gradebook")}

+

+ ${_("Click here to view the gradebook for enrolled students. This feature is only visible to courses with a small number of total enrolled students.")} +

+
+

+ ${_("View Gradebook")} +

+
+ %endif +
+

${_("Student-specific grade inspection")}

diff --git a/lms/urls.py b/lms/urls.py index 164be5d522..a2f4d45dc2 100644 --- a/lms/urls.py +++ b/lms/urls.py @@ -273,6 +273,8 @@ if settings.COURSEWARE_ENABLED: 'instructor.views.instructor_dashboard.instructor_dashboard_2', name="instructor_dashboard"), url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/instructor_dashboard/api/', include('instructor.views.api_urls')), + url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/gradebook$', + 'instructor.views.instructor_dashboard.spoc_gradebook', name='spoc_gradebook'), # see ENABLE_INSTRUCTOR_LEGACY_DASHBOARD section for legacy dash urls