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
a647169a
Commit
a647169a
authored
Mar 10, 2016
by
Eric Fischer
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #11167 from edx/christina/ora-data-download
WIP: Asynchronous download button for ORA2 data
parents
f0925509
2b1a7eec
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
351 additions
and
65 deletions
+351
-65
common/test/acceptance/pages/lms/instructor_dashboard.py
+7
-0
common/test/acceptance/tests/lms/test_lms_instructor_dashboard.py
+14
-0
lms/djangoapps/instructor/features/common.py
+1
-1
lms/djangoapps/instructor/tests/test_api.py
+30
-6
lms/djangoapps/instructor/views/api.py
+42
-19
lms/djangoapps/instructor/views/api_urls.py
+2
-0
lms/djangoapps/instructor/views/instructor_dashboard.py
+1
-0
lms/djangoapps/instructor_task/api.py
+14
-1
lms/djangoapps/instructor_task/tasks.py
+12
-1
lms/djangoapps/instructor_task/tasks_helper.py
+68
-0
lms/djangoapps/instructor_task/tests/test_api.py
+21
-7
lms/djangoapps/instructor_task/tests/test_tasks.py
+35
-1
lms/djangoapps/instructor_task/tests/test_tasks_helper.py
+74
-1
lms/envs/common.py
+2
-1
lms/static/coffee/src/instructor_dashboard/data_download.coffee
+21
-21
lms/templates/instructor/instructor_dashboard_2/data_download.html
+5
-4
requirements/edx/github.txt
+2
-2
No files found.
common/test/acceptance/pages/lms/instructor_dashboard.py
View file @
a647169a
...
@@ -912,6 +912,13 @@ class DataDownloadPage(PageObject):
...
@@ -912,6 +912,13 @@ class DataDownloadPage(PageObject):
"""
"""
return
self
.
q
(
css
=
"#report-downloads-table .file-download-link>a"
)
return
self
.
q
(
css
=
"#report-downloads-table .file-download-link>a"
)
@property
def
generate_ora2_response_report_button
(
self
):
"""
Returns the ORA2 response download button for the current page.
"""
return
self
.
q
(
css
=
'input[name=export-ora2-data]'
)
def
wait_for_available_report
(
self
):
def
wait_for_available_report
(
self
):
"""
"""
Waits for a downloadable report to be available.
Waits for a downloadable report to be available.
...
...
common/test/acceptance/tests/lms/test_lms_instructor_dashboard.py
View file @
a647169a
...
@@ -636,6 +636,20 @@ class DataDownloadsTest(BaseInstructorDashboardTest):
...
@@ -636,6 +636,20 @@ class DataDownloadsTest(BaseInstructorDashboardTest):
self
.
verify_report_requested_event
(
report_name
)
self
.
verify_report_requested_event
(
report_name
)
self
.
verify_report_download
(
report_name
)
self
.
verify_report_download
(
report_name
)
def
test_ora2_response_report_download
(
self
):
"""
Scenario: Verify that an instructor can download an ORA2 grade report
Given that I am an instructor
And I visit the instructor dashboard's "Data Downloads" tab
And I click on the "Download ORA2 Responses" button
Then a report should be generated
"""
report_name
=
u"ORA_data"
self
.
data_download_section
.
generate_ora2_response_report_button
.
click
()
self
.
data_download_section
.
wait_for_available_report
()
self
.
verify_report_download
(
report_name
)
@attr
(
'shard_7'
)
@attr
(
'shard_7'
)
class
CertificatesTest
(
BaseInstructorDashboardTest
):
class
CertificatesTest
(
BaseInstructorDashboardTest
):
...
...
lms/djangoapps/instructor/features/common.py
View file @
a647169a
...
@@ -92,7 +92,7 @@ def click_a_button(step, button): # pylint: disable=unused-argument
...
@@ -92,7 +92,7 @@ def click_a_button(step, button): # pylint: disable=unused-argument
# Expect to see a message that grade report is being generated
# Expect to see a message that grade report is being generated
expected_msg
=
"The grade report is being created."
\
expected_msg
=
"The grade report is being created."
\
" To view the status of the report, see"
\
" To view the status of the report, see"
\
" Pending
Instructor
Tasks below."
" Pending Tasks below."
world
.
wait_for_visible
(
'#report-request-response'
)
world
.
wait_for_visible
(
'#report-request-response'
)
assert_in
(
assert_in
(
expected_msg
,
world
.
css_text
(
'#report-request-response'
),
expected_msg
,
world
.
css_text
(
'#report-request-response'
),
...
...
lms/djangoapps/instructor/tests/test_api.py
View file @
a647169a
...
@@ -244,6 +244,7 @@ class TestInstructorAPIDenyLevels(SharedModuleStoreTestCase, LoginEnrollmentTest
...
@@ -244,6 +244,7 @@ class TestInstructorAPIDenyLevels(SharedModuleStoreTestCase, LoginEnrollmentTest
(
'get_exec_summary_report'
,
{}),
(
'get_exec_summary_report'
,
{}),
(
'get_proctored_exam_results'
,
{}),
(
'get_proctored_exam_results'
,
{}),
(
'get_problem_responses'
,
{}),
(
'get_problem_responses'
,
{}),
(
'export_ora2_data'
,
{}),
]
]
# Endpoints that only Instructors can access
# Endpoints that only Instructors can access
self
.
instructor_level_endpoints
=
[
self
.
instructor_level_endpoints
=
[
...
@@ -322,6 +323,8 @@ class TestInstructorAPIDenyLevels(SharedModuleStoreTestCase, LoginEnrollmentTest
...
@@ -322,6 +323,8 @@ class TestInstructorAPIDenyLevels(SharedModuleStoreTestCase, LoginEnrollmentTest
# update_forum_role(self.course.id, staff_member, FORUM_ROLE_ADMINISTRATOR, 'allow')
# update_forum_role(self.course.id, staff_member, FORUM_ROLE_ADMINISTRATOR, 'allow')
for
endpoint
,
args
in
self
.
staff_level_endpoints
:
for
endpoint
,
args
in
self
.
staff_level_endpoints
:
expected_status
=
200
# TODO: make these work
# TODO: make these work
if
endpoint
in
[
'update_forum_role_membership'
,
'list_forum_members'
]:
if
endpoint
in
[
'update_forum_role_membership'
,
'list_forum_members'
]:
continue
continue
...
@@ -333,7 +336,7 @@ class TestInstructorAPIDenyLevels(SharedModuleStoreTestCase, LoginEnrollmentTest
...
@@ -333,7 +336,7 @@ class TestInstructorAPIDenyLevels(SharedModuleStoreTestCase, LoginEnrollmentTest
self
.
_access_endpoint
(
self
.
_access_endpoint
(
endpoint
,
endpoint
,
args
,
args
,
200
,
expected_status
,
"Staff member should be allowed to access endpoint "
+
endpoint
"Staff member should be allowed to access endpoint "
+
endpoint
)
)
...
@@ -356,6 +359,8 @@ class TestInstructorAPIDenyLevels(SharedModuleStoreTestCase, LoginEnrollmentTest
...
@@ -356,6 +359,8 @@ class TestInstructorAPIDenyLevels(SharedModuleStoreTestCase, LoginEnrollmentTest
self
.
client
.
login
(
username
=
inst
.
username
,
password
=
'test'
)
self
.
client
.
login
(
username
=
inst
.
username
,
password
=
'test'
)
for
endpoint
,
args
in
self
.
staff_level_endpoints
:
for
endpoint
,
args
in
self
.
staff_level_endpoints
:
expected_status
=
200
# TODO: make these work
# TODO: make these work
if
endpoint
in
[
'update_forum_role_membership'
]:
if
endpoint
in
[
'update_forum_role_membership'
]:
continue
continue
...
@@ -367,18 +372,20 @@ class TestInstructorAPIDenyLevels(SharedModuleStoreTestCase, LoginEnrollmentTest
...
@@ -367,18 +372,20 @@ class TestInstructorAPIDenyLevels(SharedModuleStoreTestCase, LoginEnrollmentTest
self
.
_access_endpoint
(
self
.
_access_endpoint
(
endpoint
,
endpoint
,
args
,
args
,
200
,
expected_status
,
"Instructor should be allowed to access endpoint "
+
endpoint
"Instructor should be allowed to access endpoint "
+
endpoint
)
)
for
endpoint
,
args
in
self
.
instructor_level_endpoints
:
for
endpoint
,
args
in
self
.
instructor_level_endpoints
:
expected_status
=
200
# TODO: make this work
# TODO: make this work
if
endpoint
in
[
'rescore_problem'
]:
if
endpoint
in
[
'rescore_problem'
]:
continue
continue
self
.
_access_endpoint
(
self
.
_access_endpoint
(
endpoint
,
endpoint
,
args
,
args
,
200
,
expected_status
,
"Instructor should be allowed to access endpoint "
+
endpoint
"Instructor should be allowed to access endpoint "
+
endpoint
)
)
...
@@ -2866,8 +2873,7 @@ class TestInstructorAPILevelsDataDump(SharedModuleStoreTestCase, LoginEnrollment
...
@@ -2866,8 +2873,7 @@ class TestInstructorAPILevelsDataDump(SharedModuleStoreTestCase, LoginEnrollment
response
=
self
.
client
.
get
(
url
,
{})
response
=
self
.
client
.
get
(
url
,
{})
success_status
=
"The {report_type} report is being created."
\
success_status
=
"The {report_type} report is being created."
\
" To view the status of the report, see Pending"
\
" To view the status of the report, see Pending"
\
" Instructor Tasks"
\
" Tasks below"
.
format
(
report_type
=
report_type
)
" below"
.
format
(
report_type
=
report_type
)
self
.
assertIn
(
success_status
,
response
.
content
)
self
.
assertIn
(
success_status
,
response
.
content
)
@ddt.data
(
*
EXECUTIVE_SUMMARY_DATA
)
@ddt.data
(
*
EXECUTIVE_SUMMARY_DATA
)
...
@@ -2888,12 +2894,30 @@ class TestInstructorAPILevelsDataDump(SharedModuleStoreTestCase, LoginEnrollment
...
@@ -2888,12 +2894,30 @@ class TestInstructorAPILevelsDataDump(SharedModuleStoreTestCase, LoginEnrollment
mock
.
side_effect
=
AlreadyRunningError
()
mock
.
side_effect
=
AlreadyRunningError
()
response
=
self
.
client
.
get
(
url
,
{})
response
=
self
.
client
.
get
(
url
,
{})
already_running_status
=
"The {report_type} report is currently being created."
\
already_running_status
=
"The {report_type} report is currently being created."
\
" To view the status of the report, see Pending
Instructor
Tasks below."
\
" To view the status of the report, see Pending Tasks below."
\
" You will be able to download the report"
\
" You will be able to download the report"
\
" when it is"
\
" when it is"
\
" complete."
.
format
(
report_type
=
report_type
)
" complete."
.
format
(
report_type
=
report_type
)
self
.
assertIn
(
already_running_status
,
response
.
content
)
self
.
assertIn
(
already_running_status
,
response
.
content
)
def
test_get_ora2_responses_success
(
self
):
url
=
reverse
(
'export_ora2_data'
,
kwargs
=
{
'course_id'
:
unicode
(
self
.
course
.
id
)})
with
patch
(
'instructor_task.api.submit_export_ora2_data'
)
as
mock_submit_ora2_task
:
mock_submit_ora2_task
.
return_value
=
True
response
=
self
.
client
.
get
(
url
,
{})
success_status
=
"The ORA data report is being generated."
self
.
assertIn
(
success_status
,
response
.
content
)
def
test_get_ora2_responses_already_running
(
self
):
url
=
reverse
(
'export_ora2_data'
,
kwargs
=
{
'course_id'
:
unicode
(
self
.
course
.
id
)})
with
patch
(
'instructor_task.api.submit_export_ora2_data'
)
as
mock_submit_ora2_task
:
mock_submit_ora2_task
.
side_effect
=
AlreadyRunningError
()
response
=
self
.
client
.
get
(
url
,
{})
already_running_status
=
"An ORA data report generation task is already in progress."
self
.
assertIn
(
already_running_status
,
response
.
content
)
def
test_get_student_progress_url
(
self
):
def
test_get_student_progress_url
(
self
):
""" Test that progress_url is in the successful response. """
""" Test that progress_url is in the successful response. """
url
=
reverse
(
'get_student_progress_url'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
.
to_deprecated_string
()})
url
=
reverse
(
'get_student_progress_url'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
.
to_deprecated_string
()})
...
...
lms/djangoapps/instructor/views/api.py
View file @
a647169a
...
@@ -1290,12 +1290,12 @@ def get_students_features(request, course_id, csv=False): # pylint: disable=red
...
@@ -1290,12 +1290,12 @@ def get_students_features(request, course_id, csv=False): # pylint: disable=red
try
:
try
:
instructor_task
.
api
.
submit_calculate_students_features_csv
(
request
,
course_key
,
query_features
)
instructor_task
.
api
.
submit_calculate_students_features_csv
(
request
,
course_key
,
query_features
)
success_status
=
_
(
"The enrolled learner profile report is being created."
success_status
=
_
(
"The enrolled learner profile report is being created."
" To view the status of the report, see Pending
Instructor
Tasks below."
)
" To view the status of the report, see Pending Tasks below."
)
return
JsonResponse
({
"status"
:
success_status
})
return
JsonResponse
({
"status"
:
success_status
})
except
AlreadyRunningError
:
except
AlreadyRunningError
:
already_running_status
=
_
(
already_running_status
=
_
(
"This enrollment report is currently being created."
"This enrollment report is currently being created."
" To view the status of the report, see Pending
Instructor
Tasks below."
" To view the status of the report, see Pending Tasks below."
" You will be able to download the report when it is complete."
)
" You will be able to download the report when it is complete."
)
return
JsonResponse
({
"status"
:
already_running_status
})
return
JsonResponse
({
"status"
:
already_running_status
})
...
@@ -1320,13 +1320,13 @@ def get_students_who_may_enroll(request, course_id):
...
@@ -1320,13 +1320,13 @@ def get_students_who_may_enroll(request, course_id):
success_status
=
_
(
success_status
=
_
(
"The enrollment report is being created. This report contains"
"The enrollment report is being created. This report contains"
" information about learners who can enroll in the course."
" information about learners who can enroll in the course."
" To view the status of the report, see Pending
Instructor
Tasks below."
" To view the status of the report, see Pending Tasks below."
)
)
return
JsonResponse
({
"status"
:
success_status
})
return
JsonResponse
({
"status"
:
success_status
})
except
AlreadyRunningError
:
except
AlreadyRunningError
:
already_running_status
=
_
(
already_running_status
=
_
(
"This enrollment report is currently being created."
"This enrollment report is currently being created."
" To view the status of the report, see Pending
Instructor
Tasks below."
" To view the status of the report, see Pending Tasks below."
" You will be able to download the report when it is complete."
" You will be able to download the report when it is complete."
)
)
return
JsonResponse
({
"status"
:
already_running_status
})
return
JsonResponse
({
"status"
:
already_running_status
})
...
@@ -1420,11 +1420,11 @@ def get_enrollment_report(request, course_id):
...
@@ -1420,11 +1420,11 @@ def get_enrollment_report(request, course_id):
try
:
try
:
instructor_task
.
api
.
submit_detailed_enrollment_features_csv
(
request
,
course_key
)
instructor_task
.
api
.
submit_detailed_enrollment_features_csv
(
request
,
course_key
)
success_status
=
_
(
"The detailed enrollment report is being created."
success_status
=
_
(
"The detailed enrollment report is being created."
" To view the status of the report, see Pending
Instructor
Tasks below."
)
" To view the status of the report, see Pending Tasks below."
)
return
JsonResponse
({
"status"
:
success_status
})
return
JsonResponse
({
"status"
:
success_status
})
except
AlreadyRunningError
:
except
AlreadyRunningError
:
already_running_status
=
_
(
"The detailed enrollment report is being created."
already_running_status
=
_
(
"The detailed enrollment report is being created."
" To view the status of the report, see Pending
Instructor
Tasks below."
" To view the status of the report, see Pending Tasks below."
" You will be able to download the report when it is complete."
)
" You will be able to download the report when it is complete."
)
return
JsonResponse
({
return
JsonResponse
({
"status"
:
already_running_status
"status"
:
already_running_status
...
@@ -1444,11 +1444,11 @@ def get_exec_summary_report(request, course_id):
...
@@ -1444,11 +1444,11 @@ def get_exec_summary_report(request, course_id):
try
:
try
:
instructor_task
.
api
.
submit_executive_summary_report
(
request
,
course_key
)
instructor_task
.
api
.
submit_executive_summary_report
(
request
,
course_key
)
status_response
=
_
(
"The executive summary report is being created."
status_response
=
_
(
"The executive summary report is being created."
" To view the status of the report, see Pending
Instructor
Tasks below."
)
" To view the status of the report, see Pending Tasks below."
)
except
AlreadyRunningError
:
except
AlreadyRunningError
:
status_response
=
_
(
status_response
=
_
(
"The executive summary report is currently being created."
"The executive summary report is currently being created."
" To view the status of the report, see Pending
Instructor
Tasks below."
" To view the status of the report, see Pending Tasks below."
" You will be able to download the report when it is complete."
" You will be able to download the report when it is complete."
)
)
return
JsonResponse
({
return
JsonResponse
({
...
@@ -1468,11 +1468,11 @@ def get_course_survey_results(request, course_id):
...
@@ -1468,11 +1468,11 @@ def get_course_survey_results(request, course_id):
try
:
try
:
instructor_task
.
api
.
submit_course_survey_report
(
request
,
course_key
)
instructor_task
.
api
.
submit_course_survey_report
(
request
,
course_key
)
status_response
=
_
(
"The survey report is being created."
status_response
=
_
(
"The survey report is being created."
" To view the status of the report, see Pending
Instructor
Tasks below."
)
" To view the status of the report, see Pending Tasks below."
)
except
AlreadyRunningError
:
except
AlreadyRunningError
:
status_response
=
_
(
status_response
=
_
(
"The survey report is currently being created."
"The survey report is currently being created."
" To view the status of the report, see Pending
Instructor
Tasks below."
" To view the status of the report, see Pending Tasks below."
" You will be able to download the report when it is complete."
" You will be able to download the report when it is complete."
)
)
return
JsonResponse
({
return
JsonResponse
({
...
@@ -1503,11 +1503,11 @@ def get_proctored_exam_results(request, course_id):
...
@@ -1503,11 +1503,11 @@ def get_proctored_exam_results(request, course_id):
try
:
try
:
instructor_task
.
api
.
submit_proctored_exam_results_report
(
request
,
course_key
,
query_features
)
instructor_task
.
api
.
submit_proctored_exam_results_report
(
request
,
course_key
,
query_features
)
status_response
=
_
(
"The proctored exam results report is being created."
status_response
=
_
(
"The proctored exam results report is being created."
" To view the status of the report, see Pending
Instructor
Tasks below."
)
" To view the status of the report, see Pending Tasks below."
)
except
AlreadyRunningError
:
except
AlreadyRunningError
:
status_response
=
_
(
status_response
=
_
(
"The proctored exam results report is currently being created."
"The proctored exam results report is currently being created."
" To view the status of the report, see Pending
Instructor
Tasks below."
" To view the status of the report, see Pending Tasks below."
" You will be able to download the report when it is complete."
" You will be able to download the report when it is complete."
)
)
return
JsonResponse
({
return
JsonResponse
({
...
@@ -2331,6 +2331,31 @@ def list_financial_report_downloads(_request, course_id):
...
@@ -2331,6 +2331,31 @@ def list_financial_report_downloads(_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
)
@require_level
(
'staff'
)
@require_level
(
'staff'
)
def
export_ora2_data
(
request
,
course_id
):
"""
Pushes a Celery task which will aggregate ora2 responses for a course into a .csv
"""
course_key
=
SlashSeparatedCourseKey
.
from_deprecated_string
(
course_id
)
try
:
instructor_task
.
api
.
submit_export_ora2_data
(
request
,
course_key
)
success_status
=
_
(
"The ORA data report is being generated."
)
return
JsonResponse
({
"status"
:
success_status
})
except
AlreadyRunningError
:
already_running_status
=
_
(
"An ORA data report generation task is already in "
"progress. Check the 'Pending Tasks' table "
"for the status of the task. When completed, the report "
"will be available for download in the table below."
)
return
JsonResponse
({
"status"
:
already_running_status
})
@transaction.non_atomic_requests
@ensure_csrf_cookie
@cache_control
(
no_cache
=
True
,
no_store
=
True
,
must_revalidate
=
True
)
@require_level
(
'staff'
)
def
calculate_grades_csv
(
request
,
course_id
):
def
calculate_grades_csv
(
request
,
course_id
):
"""
"""
AlreadyRunningError is raised if the course's grades are already being updated.
AlreadyRunningError is raised if the course's grades are already being updated.
...
@@ -2339,15 +2364,13 @@ def calculate_grades_csv(request, course_id):
...
@@ -2339,15 +2364,13 @@ def calculate_grades_csv(request, course_id):
try
:
try
:
instructor_task
.
api
.
submit_calculate_grades_csv
(
request
,
course_key
)
instructor_task
.
api
.
submit_calculate_grades_csv
(
request
,
course_key
)
success_status
=
_
(
"The grade report is being created."
success_status
=
_
(
"The grade report is being created."
" To view the status of the report, see Pending
Instructor
Tasks below."
)
" To view the status of the report, see Pending Tasks below."
)
return
JsonResponse
({
"status"
:
success_status
})
return
JsonResponse
({
"status"
:
success_status
})
except
AlreadyRunningError
:
except
AlreadyRunningError
:
already_running_status
=
_
(
"The grade report is currently being created."
already_running_status
=
_
(
"The grade report is currently being created."
" To view the status of the report, see Pending
Instructor
Tasks below."
" To view the status of the report, see Pending Tasks below."
" You will be able to download the report when it is complete."
)
" You will be able to download the report when it is complete."
)
return
JsonResponse
({
return
JsonResponse
({
"status"
:
already_running_status
})
"status"
:
already_running_status
})
@transaction.non_atomic_requests
@transaction.non_atomic_requests
...
@@ -2366,11 +2389,11 @@ def problem_grade_report(request, course_id):
...
@@ -2366,11 +2389,11 @@ def problem_grade_report(request, course_id):
try
:
try
:
instructor_task
.
api
.
submit_problem_grade_report
(
request
,
course_key
)
instructor_task
.
api
.
submit_problem_grade_report
(
request
,
course_key
)
success_status
=
_
(
"The problem grade report is being created."
success_status
=
_
(
"The problem grade report is being created."
" To view the status of the report, see Pending
Instructor
Tasks below."
)
" To view the status of the report, see Pending Tasks below."
)
return
JsonResponse
({
"status"
:
success_status
})
return
JsonResponse
({
"status"
:
success_status
})
except
AlreadyRunningError
:
except
AlreadyRunningError
:
already_running_status
=
_
(
"A problem grade report is already being generated."
already_running_status
=
_
(
"A problem grade report is already being generated."
" To view the status of the report, see Pending
Instructor
Tasks below."
" To view the status of the report, see Pending Tasks below."
" You will be able to download the report when it is complete."
)
" You will be able to download the report when it is complete."
)
return
JsonResponse
({
return
JsonResponse
({
"status"
:
already_running_status
"status"
:
already_running_status
...
...
lms/djangoapps/instructor/views/api_urls.py
View file @
a647169a
...
@@ -117,6 +117,8 @@ urlpatterns = patterns(
...
@@ -117,6 +117,8 @@ urlpatterns = patterns(
'instructor.views.api.get_exec_summary_report'
,
name
=
"get_exec_summary_report"
),
'instructor.views.api.get_exec_summary_report'
,
name
=
"get_exec_summary_report"
),
url
(
r'get_course_survey_results$'
,
url
(
r'get_course_survey_results$'
,
'instructor.views.api.get_course_survey_results'
,
name
=
"get_course_survey_results"
),
'instructor.views.api.get_course_survey_results'
,
name
=
"get_course_survey_results"
),
url
(
r'export_ora2_data'
,
'instructor.views.api.export_ora2_data'
,
name
=
"export_ora2_data"
),
# Coupon Codes..
# Coupon Codes..
url
(
r'get_coupon_codes'
,
url
(
r'get_coupon_codes'
,
...
...
lms/djangoapps/instructor/views/instructor_dashboard.py
View file @
a647169a
...
@@ -567,6 +567,7 @@ def _section_data_download(course, access):
...
@@ -567,6 +567,7 @@ def _section_data_download(course, access):
'problem_grade_report_url'
:
reverse
(
'problem_grade_report'
,
kwargs
=
{
'course_id'
:
unicode
(
course_key
)}),
'problem_grade_report_url'
:
reverse
(
'problem_grade_report'
,
kwargs
=
{
'course_id'
:
unicode
(
course_key
)}),
'course_has_survey'
:
True
if
course
.
course_survey_name
else
False
,
'course_has_survey'
:
True
if
course
.
course_survey_name
else
False
,
'course_survey_results_url'
:
reverse
(
'get_course_survey_results'
,
kwargs
=
{
'course_id'
:
unicode
(
course_key
)}),
'course_survey_results_url'
:
reverse
(
'get_course_survey_results'
,
kwargs
=
{
'course_id'
:
unicode
(
course_key
)}),
'export_ora2_data_url'
:
reverse
(
'export_ora2_data'
,
kwargs
=
{
'course_id'
:
unicode
(
course_key
)}),
}
}
return
section_data
return
section_data
...
...
lms/djangoapps/instructor_task/api.py
View file @
a647169a
...
@@ -28,7 +28,8 @@ from instructor_task.tasks import (
...
@@ -28,7 +28,8 @@ from instructor_task.tasks import (
exec_summary_report_csv
,
exec_summary_report_csv
,
course_survey_report_csv
,
course_survey_report_csv
,
generate_certificates
,
generate_certificates
,
proctored_exam_results_csv
proctored_exam_results_csv
,
export_ora2_data
,
)
)
from
certificates.models
import
CertificateGenerationHistory
from
certificates.models
import
CertificateGenerationHistory
...
@@ -424,6 +425,18 @@ def submit_cohort_students(request, course_key, file_name):
...
@@ -424,6 +425,18 @@ def submit_cohort_students(request, course_key, file_name):
return
submit_task
(
request
,
task_type
,
task_class
,
course_key
,
task_input
,
task_key
)
return
submit_task
(
request
,
task_type
,
task_class
,
course_key
,
task_input
,
task_key
)
def
submit_export_ora2_data
(
request
,
course_key
):
"""
AlreadyRunningError is raised if an ora2 report is already being generated.
"""
task_type
=
'export_ora2_data'
task_class
=
export_ora2_data
task_input
=
{}
task_key
=
''
return
submit_task
(
request
,
task_type
,
task_class
,
course_key
,
task_input
,
task_key
)
def
generate_certificates_for_students
(
request
,
course_key
,
students
=
None
):
# pylint: disable=invalid-name
def
generate_certificates_for_students
(
request
,
course_key
,
students
=
None
):
# pylint: disable=invalid-name
"""
"""
Submits a task to generate certificates for given students enrolled in the course or
Submits a task to generate certificates for given students enrolled in the course or
...
...
lms/djangoapps/instructor_task/tasks.py
View file @
a647169a
...
@@ -44,7 +44,8 @@ from instructor_task.tasks_helper import (
...
@@ -44,7 +44,8 @@ from instructor_task.tasks_helper import (
upload_exec_summary_report
,
upload_exec_summary_report
,
upload_course_survey_report
,
upload_course_survey_report
,
generate_students_certificates
,
generate_students_certificates
,
upload_proctored_exam_results_report
upload_proctored_exam_results_report
,
upload_ora2_data
,
)
)
...
@@ -290,3 +291,13 @@ def cohort_students(entry_id, xmodule_instance_args):
...
@@ -290,3 +291,13 @@ def cohort_students(entry_id, xmodule_instance_args):
action_name
=
ugettext_noop
(
'cohorted'
)
action_name
=
ugettext_noop
(
'cohorted'
)
task_fn
=
partial
(
cohort_students_and_upload
,
xmodule_instance_args
)
task_fn
=
partial
(
cohort_students_and_upload
,
xmodule_instance_args
)
return
run_main_task
(
entry_id
,
task_fn
,
action_name
)
return
run_main_task
(
entry_id
,
task_fn
,
action_name
)
@task
(
base
=
BaseInstructorTask
,
routing_key
=
settings
.
GRADES_DOWNLOAD_ROUTING_KEY
)
# pylint: disable=not-callable
def
export_ora2_data
(
entry_id
,
xmodule_instance_args
):
"""
Generate a CSV of ora2 responses and push it to S3.
"""
action_name
=
ugettext_noop
(
'generated'
)
task_fn
=
partial
(
upload_ora2_data
,
xmodule_instance_args
)
return
run_main_task
(
entry_id
,
task_fn
,
action_name
)
lms/djangoapps/instructor_task/tasks_helper.py
View file @
a647169a
...
@@ -57,6 +57,7 @@ from instructor_analytics.basic import (
...
@@ -57,6 +57,7 @@ from instructor_analytics.basic import (
list_problem_responses
list_problem_responses
)
)
from
instructor_analytics.csvs
import
format_dictlist
from
instructor_analytics.csvs
import
format_dictlist
from
openassessment.data
import
OraAggregateData
from
instructor_task.models
import
ReportStore
,
InstructorTask
,
PROGRESS
from
instructor_task.models
import
ReportStore
,
InstructorTask
,
PROGRESS
from
lms.djangoapps.lms_xblock.runtime
import
LmsPartitionService
from
lms.djangoapps.lms_xblock.runtime
import
LmsPartitionService
from
openedx.core.djangoapps.course_groups.cohorts
import
get_cohort
from
openedx.core.djangoapps.course_groups.cohorts
import
get_cohort
...
@@ -1599,3 +1600,70 @@ def invalidate_generated_certificates(course_id, enrolled_students, certificate_
...
@@ -1599,3 +1600,70 @@ def invalidate_generated_certificates(course_id, enrolled_students, certificate_
download_url
=
''
,
download_url
=
''
,
grade
=
''
,
grade
=
''
,
)
)
def
upload_ora2_data
(
_xmodule_instance_args
,
_entry_id
,
course_id
,
_task_input
,
action_name
):
"""
Collect ora2 responses and upload them to S3 as a CSV
"""
start_date
=
datetime
.
now
(
UTC
)
start_time
=
time
()
num_attempted
=
1
num_total
=
1
fmt
=
u'Task: {task_id}, InstructorTask ID: {entry_id}, Course: {course_id}, Input: {task_input}'
task_info_string
=
fmt
.
format
(
task_id
=
_xmodule_instance_args
.
get
(
'task_id'
)
if
_xmodule_instance_args
is
not
None
else
None
,
entry_id
=
_entry_id
,
course_id
=
course_id
,
task_input
=
_task_input
)
TASK_LOG
.
info
(
u'
%
s, Task type:
%
s, Starting task execution'
,
task_info_string
,
action_name
)
task_progress
=
TaskProgress
(
action_name
,
num_total
,
start_time
)
task_progress
.
attempted
=
num_attempted
curr_step
=
{
'step'
:
"Collecting responses"
}
TASK_LOG
.
info
(
u'
%
s, Task type:
%
s, Current step:
%
s for all submissions'
,
task_info_string
,
action_name
,
curr_step
,
)
task_progress
.
update_task_state
(
extra_meta
=
curr_step
)
try
:
header
,
datarows
=
OraAggregateData
.
collect_ora2_data
(
course_id
)
rows
=
[
header
]
+
[
row
for
row
in
datarows
]
# Update progress to failed regardless of error type
except
Exception
:
# pylint: disable=broad-except
TASK_LOG
.
exception
(
'Failed to get ORA data.'
)
task_progress
.
failed
=
1
curr_step
=
{
'step'
:
"Error while collecting data"
}
task_progress
.
update_task_state
(
extra_meta
=
curr_step
)
return
UPDATE_STATUS_FAILED
task_progress
.
succeeded
=
1
curr_step
=
{
'step'
:
"Uploading CSV"
}
TASK_LOG
.
info
(
u'
%
s, Task type:
%
s, Current step:
%
s'
,
task_info_string
,
action_name
,
curr_step
,
)
task_progress
.
update_task_state
(
extra_meta
=
curr_step
)
upload_csv_to_report_store
(
rows
,
'ORA_data'
,
course_id
,
start_date
)
curr_step
=
{
'step'
:
'Finalizing ORA data report'
}
task_progress
.
update_task_state
(
extra_meta
=
curr_step
)
TASK_LOG
.
info
(
u'
%
s, Task type:
%
s, Upload complete.'
,
task_info_string
,
action_name
)
return
UPDATE_STATUS_SUCCEEDED
lms/djangoapps/instructor_task/tests/test_api.py
View file @
a647169a
"""
"""
Test for LMS instructor background task queue management
Test for LMS instructor background task queue management
"""
"""
from
mock
import
patch
,
Mock
from
mock
import
patch
,
Mock
,
MagicMock
from
bulk_email.models
import
CourseEmail
,
SEND_TO_ALL
from
bulk_email.models
import
CourseEmail
,
SEND_TO_ALL
from
courseware.tests.factories
import
UserFactory
from
courseware.tests.factories
import
UserFactory
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
...
@@ -22,16 +22,20 @@ from instructor_task.api import (
...
@@ -22,16 +22,20 @@ from instructor_task.api import (
submit_executive_summary_report
,
submit_executive_summary_report
,
submit_course_survey_report
,
submit_course_survey_report
,
generate_certificates_for_students
,
generate_certificates_for_students
,
regenerate_certificates
regenerate_certificates
,
submit_export_ora2_data
,
)
)
from
instructor_task.api_helper
import
AlreadyRunningError
from
instructor_task.api_helper
import
AlreadyRunningError
from
instructor_task.models
import
InstructorTask
,
PROGRESS
from
instructor_task.models
import
InstructorTask
,
PROGRESS
from
instructor_task.tests.test_base
import
(
InstructorTaskTestCase
,
from
instructor_task.tasks
import
export_ora2_data
InstructorTaskCourseTestCase
,
from
instructor_task.tests.test_base
import
(
InstructorTaskModuleTestCase
,
InstructorTaskTestCase
,
TestReportMixin
,
InstructorTaskCourseTestCase
,
TEST_COURSE_KEY
)
InstructorTaskModuleTestCase
,
TestReportMixin
,
TEST_COURSE_KEY
,
)
from
certificates.models
import
CertificateStatuses
,
CertificateGenerationHistory
from
certificates.models
import
CertificateStatuses
,
CertificateGenerationHistory
...
@@ -256,6 +260,16 @@ class InstructorTaskCourseSubmitTest(TestReportMixin, InstructorTaskCourseTestCa
...
@@ -256,6 +260,16 @@ class InstructorTaskCourseSubmitTest(TestReportMixin, InstructorTaskCourseTestCa
)
)
self
.
_test_resubmission
(
api_call
)
self
.
_test_resubmission
(
api_call
)
def
test_submit_ora2_request_task
(
self
):
request
=
self
.
create_task_request
(
self
.
instructor
)
with
patch
(
'instructor_task.api.submit_task'
)
as
mock_submit_task
:
mock_submit_task
.
return_value
=
MagicMock
()
submit_export_ora2_data
(
request
,
self
.
course
.
id
)
mock_submit_task
.
assert_called_once_with
(
request
,
'export_ora2_data'
,
export_ora2_data
,
self
.
course
.
id
,
{},
''
)
def
test_submit_generate_certs_students
(
self
):
def
test_submit_generate_certs_students
(
self
):
"""
"""
Tests certificates generation task submission api
Tests certificates generation task submission api
...
...
lms/djangoapps/instructor_task/tests/test_tasks.py
View file @
a647169a
...
@@ -11,6 +11,8 @@ from uuid import uuid4
...
@@ -11,6 +11,8 @@ from uuid import uuid4
from
mock
import
Mock
,
MagicMock
,
patch
from
mock
import
Mock
,
MagicMock
,
patch
from
celery.states
import
SUCCESS
,
FAILURE
from
celery.states
import
SUCCESS
,
FAILURE
from
django.utils.translation
import
ugettext_noop
from
functools
import
partial
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
from
opaque_keys.edx.locations
import
i4xEncoder
from
opaque_keys.edx.locations
import
i4xEncoder
...
@@ -27,8 +29,12 @@ from instructor_task.tasks import (
...
@@ -27,8 +29,12 @@ from instructor_task.tasks import (
reset_problem_attempts
,
reset_problem_attempts
,
delete_problem_state
,
delete_problem_state
,
generate_certificates
,
generate_certificates
,
export_ora2_data
,
)
from
instructor_task.tasks_helper
import
(
UpdateProblemModuleStateError
,
upload_ora2_data
,
)
)
from
instructor_task.tasks_helper
import
UpdateProblemModuleStateError
PROBLEM_URL_NAME
=
"test_urlname"
PROBLEM_URL_NAME
=
"test_urlname"
...
@@ -471,3 +477,31 @@ class TestCertificateGenerationnstructorTask(TestInstructorTasks):
...
@@ -471,3 +477,31 @@ class TestCertificateGenerationnstructorTask(TestInstructorTasks):
expected_attempted
=
1
,
expected_attempted
=
1
,
expected_total
=
1
expected_total
=
1
)
)
class
TestOra2ResponsesInstructorTask
(
TestInstructorTasks
):
"""Tests instructor task that fetches ora2 response data."""
def
test_ora2_missing_current_task
(
self
):
self
.
_test_missing_current_task
(
export_ora2_data
)
def
test_ora2_with_failure
(
self
):
self
.
_test_run_with_failure
(
export_ora2_data
,
'We expected this to fail'
)
def
test_ora2_with_long_error_msg
(
self
):
self
.
_test_run_with_long_error_msg
(
export_ora2_data
)
def
test_ora2_with_short_error_msg
(
self
):
self
.
_test_run_with_short_error_msg
(
export_ora2_data
)
def
test_ora2_runs_task
(
self
):
task_entry
=
self
.
_create_input_entry
()
task_xmodule_args
=
self
.
_get_xmodule_instance_args
()
with
patch
(
'instructor_task.tasks.run_main_task'
)
as
mock_main_task
:
export_ora2_data
(
task_entry
.
id
,
task_xmodule_args
)
action_name
=
ugettext_noop
(
'generated'
)
task_fn
=
partial
(
upload_ora2_data
,
task_xmodule_args
)
mock_main_task
.
assert_called_once_with_args
(
task_entry
.
id
,
task_fn
,
action_name
)
lms/djangoapps/instructor_task/tests/test_tasks_helper.py
View file @
a647169a
...
@@ -3,10 +3,18 @@
...
@@ -3,10 +3,18 @@
"""
"""
Unit tests for LMS instructor-initiated background tasks helper functions.
Unit tests for LMS instructor-initiated background tasks helper functions.
Tests that CSV grade report generation works with unicode emails.
- Tests that CSV grade report generation works with unicode emails.
- Tests all of the existing reports.
"""
"""
import
os
import
shutil
from
datetime
import
datetime
import
urllib
import
ddt
import
ddt
from
freezegun
import
freeze_time
from
mock
import
Mock
,
patch
from
mock
import
Mock
,
patch
import
tempfile
import
tempfile
import
json
import
json
...
@@ -22,6 +30,15 @@ from course_modes.models import CourseMode
...
@@ -22,6 +30,15 @@ from course_modes.models import CourseMode
from
courseware.tests.factories
import
InstructorFactory
from
courseware.tests.factories
import
InstructorFactory
from
instructor_task.tests.test_base
import
InstructorTaskCourseTestCase
,
TestReportMixin
,
InstructorTaskModuleTestCase
from
instructor_task.tests.test_base
import
InstructorTaskCourseTestCase
,
TestReportMixin
,
InstructorTaskModuleTestCase
from
openedx.core.djangoapps.course_groups.models
import
CourseUserGroupPartitionGroup
,
CohortMembership
from
openedx.core.djangoapps.course_groups.models
import
CourseUserGroupPartitionGroup
,
CohortMembership
from
django.conf
import
settings
from
xmodule.modulestore.tests.django_utils
import
SharedModuleStoreTestCase
from
pytz
import
UTC
from
xmodule.modulestore.tests.factories
import
CourseFactory
from
student.tests.factories
import
UserFactory
from
student.models
import
CourseEnrollment
from
xmodule.partitions.partitions
import
Group
,
UserPartition
from
openedx.core.djangoapps.course_groups.tests.helpers
import
CohortFactory
from
openedx.core.djangoapps.course_groups.tests.helpers
import
CohortFactory
import
openedx.core.djangoapps.user_api.course_tag.api
as
course_tag_api
import
openedx.core.djangoapps.user_api.course_tag.api
as
course_tag_api
from
openedx.core.djangoapps.user_api.partition_schemes
import
RandomUserPartitionScheme
from
openedx.core.djangoapps.user_api.partition_schemes
import
RandomUserPartitionScheme
...
@@ -45,6 +62,9 @@ from instructor_task.tasks_helper import (
...
@@ -45,6 +62,9 @@ from instructor_task.tasks_helper import (
upload_exec_summary_report
,
upload_exec_summary_report
,
upload_course_survey_report
,
upload_course_survey_report
,
generate_students_certificates
,
generate_students_certificates
,
upload_ora2_data
,
UPDATE_STATUS_FAILED
,
UPDATE_STATUS_SUCCEEDED
,
)
)
from
instructor_analytics.basic
import
UNAVAILABLE
from
instructor_analytics.basic
import
UNAVAILABLE
from
openedx.core.djangoapps.util.testing
import
ContentGroupTestCase
,
TestConditionalContent
from
openedx.core.djangoapps.util.testing
import
ContentGroupTestCase
,
TestConditionalContent
...
@@ -2012,3 +2032,56 @@ class TestCertificateGeneration(InstructorTaskModuleTestCase):
...
@@ -2012,3 +2032,56 @@ class TestCertificateGeneration(InstructorTaskModuleTestCase):
},
},
result
result
)
)
class
TestInstructorOra2Report
(
SharedModuleStoreTestCase
):
"""
Tests that ORA2 response report generation works.
"""
@classmethod
def
setUpClass
(
cls
):
super
(
TestInstructorOra2Report
,
cls
)
.
setUpClass
()
cls
.
course
=
CourseFactory
.
create
()
def
setUp
(
self
):
super
(
TestInstructorOra2Report
,
self
)
.
setUp
()
self
.
current_task
=
Mock
()
self
.
current_task
.
update_state
=
Mock
()
def
tearDown
(
self
):
super
(
TestInstructorOra2Report
,
self
)
.
tearDown
()
if
os
.
path
.
exists
(
settings
.
GRADES_DOWNLOAD
[
'ROOT_PATH'
]):
shutil
.
rmtree
(
settings
.
GRADES_DOWNLOAD
[
'ROOT_PATH'
])
def
test_report_fails_if_error
(
self
):
with
patch
(
'instructor_task.tasks_helper.OraAggregateData.collect_ora2_data'
)
as
mock_collect_data
:
mock_collect_data
.
side_effect
=
KeyError
with
patch
(
'instructor_task.tasks_helper._get_current_task'
)
as
mock_current_task
:
mock_current_task
.
return_value
=
self
.
current_task
response
=
upload_ora2_data
(
None
,
None
,
self
.
course
.
id
,
None
,
'generated'
)
self
.
assertEqual
(
response
,
UPDATE_STATUS_FAILED
)
@freeze_time
(
'2001-01-01 00:00:00'
)
def
test_report_stores_results
(
self
):
test_header
=
[
'field1'
,
'field2'
]
test_rows
=
[[
'row1_field1'
,
'row1_field2'
],
[
'row2_field1'
,
'row2_field2'
]]
with
patch
(
'instructor_task.tasks_helper._get_current_task'
)
as
mock_current_task
:
mock_current_task
.
return_value
=
self
.
current_task
with
patch
(
'instructor_task.tasks_helper.OraAggregateData.collect_ora2_data'
)
as
mock_collect_data
:
mock_collect_data
.
return_value
=
(
test_header
,
test_rows
)
with
patch
(
'instructor_task.models.LocalFSReportStore.store_rows'
)
as
mock_store_rows
:
return_val
=
upload_ora2_data
(
None
,
None
,
self
.
course
.
id
,
None
,
'generated'
)
# pylint: disable=maybe-no-member
timestamp_str
=
datetime
.
now
(
UTC
)
.
strftime
(
'
%
Y-
%
m-
%
d-
%
H
%
M'
)
course_id_string
=
urllib
.
quote
(
self
.
course
.
id
.
to_deprecated_string
()
.
replace
(
'/'
,
'_'
))
filename
=
u'{}_ORA_data_{}.csv'
.
format
(
course_id_string
,
timestamp_str
)
self
.
assertEqual
(
return_val
,
UPDATE_STATUS_SUCCEEDED
)
mock_store_rows
.
assert_called_once_with
(
self
.
course
.
id
,
filename
,
[
test_header
]
+
test_rows
)
lms/envs/common.py
View file @
a647169a
...
@@ -2230,6 +2230,8 @@ BADGR_BASE_URL = "http://localhost:8005"
...
@@ -2230,6 +2230,8 @@ BADGR_BASE_URL = "http://localhost:8005"
BADGR_ISSUER_SLUG
=
"example-issuer"
BADGR_ISSUER_SLUG
=
"example-issuer"
###################### Grade Downloads ######################
###################### Grade Downloads ######################
# These keys are used for all of our asynchronous downloadable files, including
# the ones that contain information other than grades.
GRADES_DOWNLOAD_ROUTING_KEY
=
HIGH_MEM_QUEUE
GRADES_DOWNLOAD_ROUTING_KEY
=
HIGH_MEM_QUEUE
GRADES_DOWNLOAD
=
{
GRADES_DOWNLOAD
=
{
...
@@ -2244,7 +2246,6 @@ FINANCIAL_REPORTS = {
...
@@ -2244,7 +2246,6 @@ FINANCIAL_REPORTS = {
'ROOT_PATH'
:
'/tmp/edx-s3/financial_reports'
,
'ROOT_PATH'
:
'/tmp/edx-s3/financial_reports'
,
}
}
#### PASSWORD POLICY SETTINGS #####
#### PASSWORD POLICY SETTINGS #####
PASSWORD_MIN_LENGTH
=
8
PASSWORD_MIN_LENGTH
=
8
PASSWORD_MAX_LENGTH
=
None
PASSWORD_MAX_LENGTH
=
None
...
...
lms/static/coffee/src/instructor_dashboard/data_download.coffee
View file @
a647169a
...
@@ -83,6 +83,7 @@ class DataDownload
...
@@ -83,6 +83,7 @@ class DataDownload
@
$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']'"
)
@
$problem_grade_report_csv_btn
=
@
$section
.
find
(
"input[name='problem-grade-report']'"
)
@
$problem_grade_report_csv_btn
=
@
$section
.
find
(
"input[name='problem-grade-report']'"
)
@
$async_report_btn
=
@
$section
.
find
(
"input[class='async-report-btn']'"
)
# response areas
# response areas
@
$download
=
@
$section
.
find
'.data-download-container'
@
$download
=
@
$section
.
find
'.data-download-container'
...
@@ -236,27 +237,26 @@ class DataDownload
...
@@ -236,27 +237,26 @@ class DataDownload
@
clear_display
()
@
clear_display
()
@
$download_display_text
.
html
data
[
'grading_config_summary'
]
@
$download_display_text
.
html
data
[
'grading_config_summary'
]
@
$calculate_grades_csv_btn
.
click
(
e
)
=>
@
$async_report_btn
.
click
(
e
)
=>
@
onClickGradeDownload
@
$calculate_grades_csv_btn
,
gettext
(
"Error generating grades. Please try again."
)
# Clear any CSS styling from the request-response areas
#$(".msg-confirm").css({"display":"none"})
@
$problem_grade_report_csv_btn
.
click
(
e
)
=>
#$(".msg-error").css({"display":"none"})
@
onClickGradeDownload
@
$problem_grade_report_csv_btn
,
gettext
(
"Error generating problem grade report. Please try again."
)
@
clear_display
()
url
=
$
(
e
.
target
).
data
'endpoint'
onClickGradeDownload
:
(
button
,
errorMessage
)
->
$
.
ajax
# Clear any CSS styling from the request-response areas
dataType
:
'json'
#$(".msg-confirm").css({"display":"none"})
url
:
url
#$(".msg-error").css({"display":"none"})
error
:
std_ajax_err
=>
@
clear_display
()
if
e
.
target
.
name
==
'calculate-grades-csv'
url
=
button
.
data
'endpoint'
@
$grades_request_response_error
.
text
gettext
(
"Error generating grades. Please try again."
)
$
.
ajax
else
if
e
.
target
.
name
==
'problem-grade-report'
dataType
:
'json'
@
$grades_request_response_error
.
text
gettext
(
"Error generating problem grade report. Please try again."
)
url
:
url
else
if
e
.
target
.
name
==
'export-ora2-data'
error
:
(
std_ajax_err
)
=>
@
$grades_request_response_error
.
text
gettext
(
"Error generating ORA data report. Please try again."
)
@
$reports_request_response_error
.
text
errorMessage
$
(
".msg-error"
).
css
({
"display"
:
"block"
})
$
(
".msg-error"
).
css
({
"display"
:
"block"
})
success
:
(
data
)
=>
success
:
(
data
)
=>
@
$reports_request_response
.
text
data
[
'status'
]
@
$reports_request_response
.
text
data
[
'status'
]
$
(
".msg-confirm"
).
css
({
"display"
:
"block"
})
$
(
".msg-confirm"
).
css
({
"display"
:
"block"
})
# handler for when the section title is clicked.
# handler for when the section title is clicked.
onClickTitle
:
->
onClickTitle
:
->
...
...
lms/templates/instructor/instructor_dashboard_2/data_download.html
View file @
a647169a
...
@@ -75,10 +75,11 @@
...
@@ -75,10 +75,11 @@
%if settings.FEATURES.get('ALLOW_COURSE_STAFF_GRADE_DOWNLOADS') or section_data['access']['admin']:
%if settings.FEATURES.get('ALLOW_COURSE_STAFF_GRADE_DOWNLOADS') or section_data['access']['admin']:
<p>
${_("Click to generate a CSV grade report for all currently enrolled students.")}
</p>
<p>
${_("Click to generate a CSV grade report for all currently enrolled students.")}
</p>
<p>
<p><input
type=
"button"
name=
"calculate-grades-csv"
value=
"${_("
Generate
Grade
Report
")}"
data-endpoint=
"${ section_data['calculate_grades_csv_url'] }"
/></p>
<input
type=
"button"
name=
"calculate-grades-csv"
class=
"async-report-btn"
value=
"${_("
Generate
Grade
Report
")}"
data-endpoint=
"${ section_data['calculate_grades_csv_url'] }"
/>
<input
type=
"button"
name=
"problem-grade-report"
class=
"async-report-btn"
value=
"${_("
Generate
Problem
Grade
Report
")}"
data-endpoint=
"${ section_data['problem_grade_report_url'] }"
/>
<p><input
type=
"button"
name=
"problem-grade-report"
value=
"${_("
Generate
Problem
Grade
Report
")}"
data-endpoint=
"${ section_data['problem_grade_report_url'] }"
/></p>
<input
type=
"button"
name=
"export-ora2-data"
class=
"async-report-btn"
value=
"${_("
Generate
ORA
Data
Report
")}"
data-endpoint=
"${ section_data['export_ora2_data_url'] }"
/>
</p>
%endif
%endif
<div
class=
"request-response msg msg-confirm copy"
id=
"report-request-response"
></div>
<div
class=
"request-response msg msg-confirm copy"
id=
"report-request-response"
></div>
...
...
requirements/edx/github.txt
View file @
a647169a
...
@@ -76,8 +76,8 @@ git+https://github.com/edx/XBlock.git@xblock-0.4.5#egg=XBlock==0.4.5
...
@@ -76,8 +76,8 @@ git+https://github.com/edx/XBlock.git@xblock-0.4.5#egg=XBlock==0.4.5
-e git+https://github.com/edx/event-tracking.git@0.2.1#egg=event-tracking==0.2.1
-e git+https://github.com/edx/event-tracking.git@0.2.1#egg=event-tracking==0.2.1
-e git+https://github.com/edx/django-splash.git@v0.2#egg=django-splash==0.2
-e git+https://github.com/edx/django-splash.git@v0.2#egg=django-splash==0.2
-e git+https://github.com/edx/acid-block.git@e46f9cda8a03e121a00c7e347084d142d22ebfb7#egg=acid-xblock
-e git+https://github.com/edx/acid-block.git@e46f9cda8a03e121a00c7e347084d142d22ebfb7#egg=acid-xblock
git+https://github.com/edx/edx-ora2.git@1.
0.1#egg=ora2==1.0.1
git+https://github.com/edx/edx-ora2.git@1.
1.0#egg=ora2==1.1.0
-e git+https://github.com/edx/edx-submissions.git@1.
0.0#egg=edx-submissions==1.0
.0
-e git+https://github.com/edx/edx-submissions.git@1.
1.0#egg=edx-submissions==1.1
.0
git+https://github.com/edx/ease.git@release-2015-07-14#egg=ease==0.1.3
git+https://github.com/edx/ease.git@release-2015-07-14#egg=ease==0.1.3
git+https://github.com/edx/i18n-tools.git@v0.2#egg=i18n-tools==v0.2
git+https://github.com/edx/i18n-tools.git@v0.2#egg=i18n-tools==v0.2
git+https://github.com/edx/edx-val.git@0.0.9#egg=edxval==0.0.9
git+https://github.com/edx/edx-val.git@0.0.9#egg=edxval==0.0.9
...
...
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