Commit 7d2f9b88 by Sarina Canelake

Merge pull request #2857 from edx/adam/new-data-download

Update data download dash for parity (LMS-1203)
parents 52c38a91 6ca099d5
...@@ -7,12 +7,24 @@ Define common steps for instructor dashboard acceptance tests. ...@@ -7,12 +7,24 @@ Define common steps for instructor dashboard acceptance tests.
from __future__ import absolute_import from __future__ import absolute_import
from django.conf import settings
from lettuce import world, step from lettuce import world, step
from mock import patch
from nose.tools import assert_in # pylint: disable=E0611 from nose.tools import assert_in # pylint: disable=E0611
from courseware.tests.factories import StaffFactory, InstructorFactory 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') @step(u'Given I am "([^"]*)" for a course')
def i_am_staff_or_instructor(step, role): # pylint: disable=unused-argument 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 ## 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 ...@@ -99,5 +111,24 @@ def click_a_button(step, button): # pylint: disable=unused-argument
world.css_click('input[name="list-profiles"]') 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: else:
raise ValueError("Unrecognized button option " + button) 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])
...@@ -7,6 +7,7 @@ Feature: LMS.Instructor Dash Data Download ...@@ -7,6 +7,7 @@ Feature: LMS.Instructor Dash Data Download
### todos when more time can be spent on instructor dashboard ### todos when more time can be spent on instructor dashboard
#Scenario: Download profile information as a CSV #Scenario: Download profile information as a CSV
#Scenario: Download student anonymized IDs 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 Scenario: List enrolled students' profile information
Given I am "<Role>" for a course Given I am "<Role>" for a course
...@@ -17,6 +18,15 @@ Feature: LMS.Instructor Dash Data Download ...@@ -17,6 +18,15 @@ Feature: LMS.Instructor Dash Data Download
| instructor | | instructor |
| staff | | staff |
Scenario: List enrolled students' profile information for a large course
Given I am "<Role>" 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 Scenario: View the grading configuration
Given I am "<Role>" for a course Given I am "<Role>" for a course
When I click "Grading Configuration" When I click "Grading Configuration"
......
...@@ -9,6 +9,7 @@ acceptance tests. ...@@ -9,6 +9,7 @@ acceptance tests.
from lettuce import world, step from lettuce import world, step
from nose.tools import assert_in, assert_regexp_matches # pylint: disable=E0611 from nose.tools import assert_in, assert_regexp_matches # pylint: disable=E0611
from terrain.steps import reload_the_page from terrain.steps import reload_the_page
from splinter.request_handler.request_handler import RequestHandler
@step(u'I see a table of student profiles') @step(u'I see a table of student profiles')
...@@ -39,6 +40,11 @@ def find_student_profile_table(step): # pylint: disable=unused-argument ...@@ -39,6 +40,11 @@ def find_student_profile_table(step): # pylint: disable=unused-argument
assert_in(datum, world.css_text('#data-student-profiles-table')) 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") @step(u"I see the grading configuration for the course")
def find_grading_config(step): # pylint: disable=unused-argument def find_grading_config(step): # pylint: disable=unused-argument
# Find the grading configuration display # Find the grading configuration display
......
...@@ -23,10 +23,12 @@ from courseware.access import has_access ...@@ -23,10 +23,12 @@ from courseware.access import has_access
from courseware.courses import get_course_with_access, get_course_by_id from courseware.courses import get_course_with_access, get_course_by_id
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django_comment_client.utils import has_forum_access from django_comment_client.utils import has_forum_access
from django_comment_common.models import (Role, from django_comment_common.models import (
FORUM_ROLE_ADMINISTRATOR, Role,
FORUM_ROLE_MODERATOR, FORUM_ROLE_ADMINISTRATOR,
FORUM_ROLE_COMMUNITY_TA) FORUM_ROLE_MODERATOR,
FORUM_ROLE_COMMUNITY_TA,
)
from courseware.models import StudentModule from courseware.models import StudentModule
from student.models import unique_id_for_user from student.models import unique_id_for_user
......
...@@ -18,6 +18,7 @@ class DataDownload ...@@ -18,6 +18,7 @@ class DataDownload
@$section.data 'wrapper', @ @$section.data 'wrapper', @
# gather elements # gather elements
@$list_studs_btn = @$section.find("input[name='list-profiles']'") @$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']'") @$list_anon_btn = @$section.find("input[name='list-anon-ids']'")
@$grade_config_btn = @$section.find("input[name='dump-gradeconf']'") @$grade_config_btn = @$section.find("input[name='dump-gradeconf']'")
@$calculate_grades_csv_btn = @$section.find("input[name='calculate-grades-csv']'") @$calculate_grades_csv_btn = @$section.find("input[name='calculate-grades-csv']'")
...@@ -43,43 +44,44 @@ class DataDownload ...@@ -43,43 +44,44 @@ class DataDownload
# this handler binds to both the download # this handler binds to both the download
# and the csv button # 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) => @$list_studs_btn.click (e) =>
url = @$list_studs_btn.data 'endpoint' url = @$list_studs_btn.data 'endpoint'
# handle csv special case # Dynamically generate slickgrid table for displaying student profile information
if $(e.target).data 'csv' @clear_display()
# redirect the document to the csv file. @$download_display_table.text gettext('Loading...')
url += '/csv'
location.href = url # fetch user list
else $.ajax
# Dynamically generate slickgrid table for displaying student profile information dataType: 'json'
@clear_display() url: url
@$download_display_table.text gettext('Loading...') error: std_ajax_err =>
@clear_display()
# fetch user list @$download_request_response_error.text gettext("Error getting student list.")
$.ajax success: (data) =>
dataType: 'json' @clear_display()
url: url
error: std_ajax_err => # display on a SlickGrid
@clear_display() options =
@$download_request_response_error.text gettext("Error getting student list.") enableCellNavigation: true
success: (data) => enableColumnReorder: false
@clear_display() forceFitColumns: true
rowHeight: 35
# display on a SlickGrid
options = columns = ({id: feature, field: feature, name: feature} for feature in data.queried_features)
enableCellNavigation: true grid_data = data.students
enableColumnReorder: false
forceFitColumns: true $table_placeholder = $ '<div/>', class: 'slickgrid'
rowHeight: 35 @$download_display_table.append $table_placeholder
grid = new Slick.Grid($table_placeholder, grid_data, columns, options)
columns = ({id: feature, field: feature, name: feature} for feature in data.queried_features) # grid.autosizeColumns()
grid_data = data.students
$table_placeholder = $ '<div/>', 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) => @$grade_config_btn.click (e) =>
url = @$grade_config_btn.data 'endpoint' url = @$grade_config_btn.data 'endpoint'
......
...@@ -6,14 +6,19 @@ ...@@ -6,14 +6,19 @@
<h2>${_("Data Download")}</h2> <h2>${_("Data Download")}</h2>
<div class="request-response-error msg msg-error copy" id="data-request-response-error"></div> <div class="request-response-error msg msg-error copy" id="data-request-response-error"></div>
<p>${_("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.")}</p> <p>${_("The following button generates a CSV file of all students enrolled in this course, along with profile information such as email address and username.")}</p>
<p><input type="button" name="list-profiles" value="${_("List enrolled students' profile information")}" data-endpoint="${ section_data['get_students_features_url'] }"> <p><input type="button" name="list-profiles-csv" value="${_("Download profile information as a CSV")}" data-endpoint="${ section_data['get_students_features_url'] }" data-csv="true"></p>
<input type="button" name="list-profiles" value="${_("Download profile information as a CSV")}" data-csv="true"></p>
% if not disable_buttons:
<p>${_("For smaller courses, profile information for enrolled students can be listed directly on this page:")}</p>
<p><input type="button" name="list-profiles" value="${_("List enrolled students' profile information")}" data-endpoint="${ section_data['get_students_features_url'] }"></p>
%endif
<div class="data-display-table" id="data-student-profiles-table"></div> <div class="data-display-table" id="data-student-profiles-table"></div>
<br> <br>
<p>${_("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.")}</p> <p>${_("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.")}</p>
<p><input type="button" name="dump-gradeconf" value="${_("Grading Configuration")}" data-endpoint="${ section_data['get_grading_config_url'] }"></p> <p><input type="button" name="dump-gradeconf" value="${_("Grading Configuration")}" data-endpoint="${ section_data['get_grading_config_url'] }"></p>
<div class="data-display-text" id="data-grade-config-text"></div> <div class="data-display-text" id="data-grade-config-text"></div>
......
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