diff --git a/lms/djangoapps/instructor/features/common.py b/lms/djangoapps/instructor/features/common.py index 433992a72e..c12273030a 100644 --- a/lms/djangoapps/instructor/features/common.py +++ b/lms/djangoapps/instructor/features/common.py @@ -7,12 +7,24 @@ Define common steps for instructor dashboard acceptance tests. from __future__ import absolute_import +from django.conf import settings from lettuce import world, step +from mock import patch from nose.tools import assert_in # pylint: disable=E0611 from courseware.tests.factories import StaffFactory, InstructorFactory +@step(u'Given I am "([^"]*)" for a very large course') +def make_staff_or_instructor_for_large_course(step, role): + make_large_course(step, role) + + +@patch.dict('courseware.access.settings.FEATURES', {"MAX_ENROLLMENT_INSTR_BUTTONS": 0}) +def make_large_course(step, role): + i_am_staff_or_instructor(step, role) + + @step(u'Given I am "([^"]*)" for a course') def i_am_staff_or_instructor(step, role): # pylint: disable=unused-argument ## In summary: makes a test course, makes a new Staff or Instructor user @@ -99,5 +111,24 @@ def click_a_button(step, button): # pylint: disable=unused-argument world.css_click('input[name="list-profiles"]') + elif button == "Download profile information as a CSV": + # Go to the data download section of the instructor dash + go_to_section("data_download") + # Don't do anything else, next step will handle clicking & downloading + else: raise ValueError("Unrecognized button option " + button) + + +@step(u'I visit the "([^"]*)" tab') +def click_a_button(step, tab_name): # pylint: disable=unused-argument + # course_info, membership, student_admin, data_download, analytics, send_email + tab_name_dict = { + 'Course Info': 'course_info', + 'Membership': 'membership', + 'Student Admin': 'student_admin', + 'Data Download': 'data_download', + 'Analytics': 'analytics', + 'Email': 'send_email', + } + go_to_section(tab_name_dict[tab_name]) diff --git a/lms/djangoapps/instructor/features/data_download.feature b/lms/djangoapps/instructor/features/data_download.feature index 52388e8b7d..6efe9c6397 100644 --- a/lms/djangoapps/instructor/features/data_download.feature +++ b/lms/djangoapps/instructor/features/data_download.feature @@ -7,6 +7,7 @@ Feature: LMS.Instructor Dash Data Download ### todos when more time can be spent on instructor dashboard #Scenario: Download profile information as a CSV #Scenario: Download student anonymized IDs as a CSV + ## Need to figure out how to assert csvs will download without actually downloading them Scenario: List enrolled students' profile information Given I am "" for a course @@ -17,6 +18,15 @@ Feature: LMS.Instructor Dash Data Download | instructor | | staff | + Scenario: List enrolled students' profile information for a large course + Given I am "" for a very large course + When I visit the "Data Download" tab + Then I do not see a button to 'List enrolled students' profile information' + Examples: + | Role | + | instructor | + | staff | + Scenario: View the grading configuration Given I am "" for a course When I click "Grading Configuration" diff --git a/lms/djangoapps/instructor/features/data_download.py b/lms/djangoapps/instructor/features/data_download.py index dd6aac6aa7..6d08551781 100644 --- a/lms/djangoapps/instructor/features/data_download.py +++ b/lms/djangoapps/instructor/features/data_download.py @@ -9,6 +9,7 @@ acceptance tests. from lettuce import world, step from nose.tools import assert_in, assert_regexp_matches # pylint: disable=E0611 from terrain.steps import reload_the_page +from splinter.request_handler.request_handler import RequestHandler @step(u'I see a table of student profiles') @@ -39,6 +40,11 @@ def find_student_profile_table(step): # pylint: disable=unused-argument assert_in(datum, world.css_text('#data-student-profiles-table')) +@step(u"I do not see a button to 'List enrolled students' profile information'") +def no_student_profile_table(step): # pylint: disable=unused-argument + world.is_css_not_present('input[name="list-profiles"]') + + @step(u"I see the grading configuration for the course") def find_grading_config(step): # pylint: disable=unused-argument # Find the grading configuration display diff --git a/lms/djangoapps/instructor/views/api.py b/lms/djangoapps/instructor/views/api.py index 68c9e8e68c..b02396429a 100644 --- a/lms/djangoapps/instructor/views/api.py +++ b/lms/djangoapps/instructor/views/api.py @@ -23,10 +23,12 @@ from courseware.access import has_access from courseware.courses import get_course_with_access, get_course_by_id from django.contrib.auth.models import User from django_comment_client.utils import has_forum_access -from django_comment_common.models import (Role, - FORUM_ROLE_ADMINISTRATOR, - FORUM_ROLE_MODERATOR, - FORUM_ROLE_COMMUNITY_TA) +from django_comment_common.models import ( + Role, + FORUM_ROLE_ADMINISTRATOR, + FORUM_ROLE_MODERATOR, + FORUM_ROLE_COMMUNITY_TA, +) from courseware.models import StudentModule from student.models import unique_id_for_user diff --git a/lms/static/coffee/src/instructor_dashboard/data_download.coffee b/lms/static/coffee/src/instructor_dashboard/data_download.coffee index c491abec18..b8f89c5fe8 100644 --- a/lms/static/coffee/src/instructor_dashboard/data_download.coffee +++ b/lms/static/coffee/src/instructor_dashboard/data_download.coffee @@ -18,6 +18,7 @@ class DataDownload @$section.data 'wrapper', @ # gather elements @$list_studs_btn = @$section.find("input[name='list-profiles']'") + @$list_studs_csv_btn = @$section.find("input[name='list-profiles-csv']'") @$list_anon_btn = @$section.find("input[name='list-anon-ids']'") @$grade_config_btn = @$section.find("input[name='dump-gradeconf']'") @$calculate_grades_csv_btn = @$section.find("input[name='calculate-grades-csv']'") @@ -43,43 +44,44 @@ class DataDownload # this handler binds to both the download # and the csv button + @$list_studs_csv_btn.click (e) => + url = @$list_studs_btn.data 'endpoint' + # handle csv special case + # redirect the document to the csv file. + url += '/csv' + location.href = url + @$list_studs_btn.click (e) => url = @$list_studs_btn.data 'endpoint' - # handle csv special case - if $(e.target).data 'csv' - # redirect the document to the csv file. - url += '/csv' - location.href = url - else - # Dynamically generate slickgrid table for displaying student profile information - @clear_display() - @$download_display_table.text gettext('Loading...') + # Dynamically generate slickgrid table for displaying student profile information + @clear_display() + @$download_display_table.text gettext('Loading...') - # fetch user list - $.ajax - dataType: 'json' - url: url - error: std_ajax_err => - @clear_display() - @$download_request_response_error.text gettext("Error getting student list.") - success: (data) => - @clear_display() + # fetch user list + $.ajax + dataType: 'json' + url: url + error: std_ajax_err => + @clear_display() + @$download_request_response_error.text gettext("Error getting student list.") + success: (data) => + @clear_display() - # display on a SlickGrid - options = - enableCellNavigation: true - enableColumnReorder: false - forceFitColumns: true - rowHeight: 35 + # display on a SlickGrid + options = + enableCellNavigation: true + enableColumnReorder: false + forceFitColumns: true + rowHeight: 35 - columns = ({id: feature, field: feature, name: feature} for feature in data.queried_features) - grid_data = data.students + columns = ({id: feature, field: feature, name: feature} for feature in data.queried_features) + grid_data = data.students - $table_placeholder = $ '
', class: 'slickgrid' - @$download_display_table.append $table_placeholder - grid = new Slick.Grid($table_placeholder, grid_data, columns, options) - # grid.autosizeColumns() + $table_placeholder = $ '
', class: 'slickgrid' + @$download_display_table.append $table_placeholder + grid = new Slick.Grid($table_placeholder, grid_data, columns, options) + # grid.autosizeColumns() @$grade_config_btn.click (e) => url = @$grade_config_btn.data 'endpoint' diff --git a/lms/templates/instructor/instructor_dashboard_2/data_download.html b/lms/templates/instructor/instructor_dashboard_2/data_download.html index db59caa770..9e1c9fa73c 100644 --- a/lms/templates/instructor/instructor_dashboard_2/data_download.html +++ b/lms/templates/instructor/instructor_dashboard_2/data_download.html @@ -6,14 +6,19 @@

${_("Data Download")}

-

${_("The following button displays a list of all students enrolled in this course, along with profile information such as email address and username. The data can also be downloaded as a CSV file.")}

+

${_("The following button generates a CSV file of all students enrolled in this course, along with profile information such as email address and username.")}

-

-

+

+ + % if not disable_buttons: +

${_("For smaller courses, profile information for enrolled students can be listed directly on this page:")}

+

+ %endif
+
-

${_("Displays the grading configuration for the course. The grading configuration is the breakdown of graded subsections of the course (such as exams and problem sets), and can be changed on the 'Grading' page (under 'Settings') in Studio.")}

+

${_("The following button displays the grading configuration for the course. The grading configuration is the breakdown of graded subsections of the course (such as exams and problem sets), and can be changed on the 'Grading' page (under 'Settings') in Studio.")}