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
74b08249
Commit
74b08249
authored
Oct 12, 2015
by
asadiqbal
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
SOL-1288
parent
300bd431
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
341 additions
and
5 deletions
+341
-5
lms/djangoapps/instructor/tests/test_api.py
+114
-0
lms/djangoapps/instructor/tests/test_certificates.py
+2
-2
lms/djangoapps/instructor/views/api.py
+39
-0
lms/djangoapps/instructor/views/api_urls.py
+2
-0
lms/djangoapps/instructor/views/instructor_dashboard.py
+3
-0
lms/djangoapps/instructor_analytics/basic.py
+31
-0
lms/static/coffee/src/instructor_dashboard/data_download.coffee
+55
-1
lms/static/js/fixtures/instructor_dashboard/data_download.html
+10
-0
lms/static/js/spec/instructor_dashboard/data_download_spec.js
+67
-0
lms/static/js/spec/main.js
+4
-1
lms/static/js_test.yml
+3
-0
lms/templates/instructor/instructor_dashboard_2/data_download.html
+11
-1
No files found.
lms/djangoapps/instructor/tests/test_api.py
View file @
74b08249
...
...
@@ -65,6 +65,8 @@ from instructor.views.api import require_finance_admin
from
instructor.tests.utils
import
FakeContentTask
,
FakeEmail
,
FakeEmailInfo
from
instructor.views.api
import
_split_input_list
,
common_exceptions_400
,
generate_unique_password
from
instructor_task.api_helper
import
AlreadyRunningError
from
certificates.tests.factories
import
GeneratedCertificateFactory
from
certificates.models
import
CertificateStatuses
from
openedx.core.djangoapps.course_groups.cohorts
import
set_course_cohort_settings
...
...
@@ -3856,6 +3858,118 @@ class TestDueDateExtensions(SharedModuleStoreTestCase, LoginEnrollmentTestCase):
@attr
(
'shard_1'
)
class
TestCourseIssuedCertificatesData
(
SharedModuleStoreTestCase
):
"""
Test data dumps for issued certificates.
"""
@classmethod
def
setUpClass
(
cls
):
super
(
TestCourseIssuedCertificatesData
,
cls
)
.
setUpClass
()
cls
.
course
=
CourseFactory
.
create
()
def
setUp
(
self
):
super
(
TestCourseIssuedCertificatesData
,
self
)
.
setUp
()
self
.
instructor
=
InstructorFactory
(
course_key
=
self
.
course
.
id
)
self
.
client
.
login
(
username
=
self
.
instructor
.
username
,
password
=
'test'
)
def
generate_certificate
(
self
,
course_id
,
mode
,
status
):
"""
Generate test certificate
"""
test_user
=
UserFactory
()
GeneratedCertificateFactory
.
create
(
user
=
test_user
,
course_id
=
course_id
,
mode
=
mode
,
status
=
status
)
def
test_certificates_features_against_status
(
self
):
"""
Test certificates with status 'downloadable' should be in the response.
"""
url
=
reverse
(
'get_issued_certificates'
,
kwargs
=
{
'course_id'
:
unicode
(
self
.
course
.
id
)})
# firstly generating downloadable certificates with 'honor' mode
certificate_count
=
3
for
__
in
xrange
(
certificate_count
):
self
.
generate_certificate
(
course_id
=
self
.
course
.
id
,
mode
=
'honor'
,
status
=
CertificateStatuses
.
generating
)
response
=
self
.
client
.
get
(
url
)
res_json
=
json
.
loads
(
response
.
content
)
self
.
assertIn
(
'certificates'
,
res_json
)
self
.
assertEqual
(
len
(
res_json
[
'certificates'
]),
0
)
# Certificates with status 'downloadable' should be in response.
self
.
generate_certificate
(
course_id
=
self
.
course
.
id
,
mode
=
'honor'
,
status
=
CertificateStatuses
.
downloadable
)
response
=
self
.
client
.
get
(
url
)
res_json
=
json
.
loads
(
response
.
content
)
self
.
assertIn
(
'certificates'
,
res_json
)
self
.
assertEqual
(
len
(
res_json
[
'certificates'
]),
1
)
def
test_certificates_features_group_by_mode
(
self
):
"""
Test for certificate csv features against mode. Certificates should be group by 'mode' in reponse.
"""
url
=
reverse
(
'get_issued_certificates'
,
kwargs
=
{
'course_id'
:
unicode
(
self
.
course
.
id
)})
# firstly generating downloadable certificates with 'honor' mode
certificate_count
=
3
for
__
in
xrange
(
certificate_count
):
self
.
generate_certificate
(
course_id
=
self
.
course
.
id
,
mode
=
'honor'
,
status
=
CertificateStatuses
.
downloadable
)
response
=
self
.
client
.
get
(
url
)
res_json
=
json
.
loads
(
response
.
content
)
self
.
assertIn
(
'certificates'
,
res_json
)
self
.
assertEqual
(
len
(
res_json
[
'certificates'
]),
1
)
# retrieve the first certificate from the list, there should be 3 certificates for 'honor' mode.
certificate
=
res_json
[
'certificates'
][
0
]
self
.
assertEqual
(
certificate
.
get
(
'total_issued_certificate'
),
3
)
self
.
assertEqual
(
certificate
.
get
(
'mode'
),
'honor'
)
self
.
assertEqual
(
certificate
.
get
(
'course_id'
),
str
(
self
.
course
.
id
))
# Now generating downloadable certificates with 'verified' mode
for
__
in
xrange
(
certificate_count
):
self
.
generate_certificate
(
course_id
=
self
.
course
.
id
,
mode
=
'verified'
,
status
=
CertificateStatuses
.
downloadable
)
response
=
self
.
client
.
get
(
url
)
res_json
=
json
.
loads
(
response
.
content
)
self
.
assertIn
(
'certificates'
,
res_json
)
# total certificate count should be 2 for 'verified' mode.
self
.
assertEqual
(
len
(
res_json
[
'certificates'
]),
2
)
# retrieve the second certificate from the list
certificate
=
res_json
[
'certificates'
][
1
]
self
.
assertEqual
(
certificate
.
get
(
'total_issued_certificate'
),
3
)
self
.
assertEqual
(
certificate
.
get
(
'mode'
),
'verified'
)
def
test_certificates_features_csv
(
self
):
"""
Test for certificate csv features.
"""
url
=
reverse
(
'get_issued_certificates'
,
kwargs
=
{
'course_id'
:
unicode
(
self
.
course
.
id
)})
url
+=
'?csv=true'
# firstly generating downloadable certificates with 'honor' mode
certificate_count
=
3
for
__
in
xrange
(
certificate_count
):
self
.
generate_certificate
(
course_id
=
self
.
course
.
id
,
mode
=
'honor'
,
status
=
CertificateStatuses
.
downloadable
)
current_date
=
datetime
.
date
.
today
()
.
strftime
(
"
%
B
%
d,
%
Y"
)
response
=
self
.
client
.
get
(
url
)
self
.
assertEqual
(
response
[
'Content-Type'
],
'text/csv'
)
self
.
assertEqual
(
response
[
'Content-Disposition'
],
'attachment; filename={0}'
.
format
(
'issued_certificates.csv'
))
self
.
assertEqual
(
response
.
content
.
strip
(),
'"CourseID","Certificate Type","Total Certificates Issued","Date Report Run"
\r\n
"'
+
str
(
self
.
course
.
id
)
+
'","honor","3","'
+
current_date
+
'"'
)
@attr
(
'shard_1'
)
@override_settings
(
REGISTRATION_CODE_LENGTH
=
8
)
class
TestCourseRegistrationCodes
(
SharedModuleStoreTestCase
):
"""
...
...
lms/djangoapps/instructor/tests/test_certificates.py
View file @
74b08249
...
...
@@ -136,9 +136,9 @@ class CertificatesInstructorDashTest(SharedModuleStoreTestCase):
"""Check that the certificates section is visible on the instructor dash. """
response
=
self
.
client
.
get
(
self
.
url
)
if
is_visible
:
self
.
assertContains
(
response
,
"Certificates"
)
self
.
assertContains
(
response
,
"
Student-Generated
Certificates"
)
else
:
self
.
assertNotContains
(
response
,
"Certificates"
)
self
.
assertNotContains
(
response
,
"
Student-Generated
Certificates"
)
@contextlib.contextmanager
def
_certificate_status
(
self
,
description
,
status
):
...
...
lms/djangoapps/instructor/views/api.py
View file @
74b08249
...
...
@@ -1092,6 +1092,45 @@ def re_validate_invoice(obj_invoice):
@ensure_csrf_cookie
@cache_control
(
no_cache
=
True
,
no_store
=
True
,
must_revalidate
=
True
)
@require_level
(
'staff'
)
def
get_issued_certificates
(
request
,
course_id
):
# pylint: disable=invalid-name
"""
Responds with JSON if CSV is not required. contains a list of issued certificates.
Arguments:
course_id
Returns:
{"certificates": [{course_id: xyz, mode: 'honor'}, ...]}
"""
course_key
=
CourseKey
.
from_string
(
course_id
)
csv_required
=
request
.
GET
.
get
(
'csv'
,
'false'
)
query_features
=
[
'course_id'
,
'mode'
,
'total_issued_certificate'
,
'report_run_date'
]
query_features_names
=
[
(
'course_id'
,
_
(
'CourseID'
)),
(
'mode'
,
_
(
'Certificate Type'
)),
(
'total_issued_certificate'
,
_
(
'Total Certificates Issued'
)),
(
'report_run_date'
,
_
(
'Date Report Run'
))
]
certificates_data
=
instructor_analytics
.
basic
.
issued_certificates
(
course_key
,
query_features
)
if
csv_required
.
lower
()
==
'true'
:
__
,
data_rows
=
instructor_analytics
.
csvs
.
format_dictlist
(
certificates_data
,
query_features
)
return
instructor_analytics
.
csvs
.
create_csv_response
(
'issued_certificates.csv'
,
[
col_header
for
__
,
col_header
in
query_features_names
],
data_rows
)
else
:
response_payload
=
{
'certificates'
:
certificates_data
,
'queried_features'
:
query_features
,
'feature_names'
:
dict
(
query_features_names
)
}
return
JsonResponse
(
response_payload
)
@ensure_csrf_cookie
@cache_control
(
no_cache
=
True
,
no_store
=
True
,
must_revalidate
=
True
)
@require_level
(
'staff'
)
def
get_students_features
(
request
,
course_id
,
csv
=
False
):
# pylint: disable=redefined-outer-name
"""
Respond with json which contains a summary of all enrolled students profile information.
...
...
lms/djangoapps/instructor/views/api_urls.py
View file @
74b08249
...
...
@@ -23,6 +23,8 @@ urlpatterns = patterns(
'instructor.views.api.get_grading_config'
,
name
=
"get_grading_config"
),
url
(
r'^get_students_features(?P<csv>/csv)?$'
,
'instructor.views.api.get_students_features'
,
name
=
"get_students_features"
),
url
(
r'^get_issued_certificates/$'
,
'instructor.views.api.get_issued_certificates'
,
name
=
"get_issued_certificates"
),
url
(
r'^get_students_who_may_enroll$'
,
'instructor.views.api.get_students_who_may_enroll'
,
name
=
"get_students_who_may_enroll"
),
url
(
r'^get_user_invoice_preference$'
,
...
...
lms/djangoapps/instructor/views/instructor_dashboard.py
View file @
74b08249
...
...
@@ -504,6 +504,9 @@ def _section_data_download(course, access):
'get_problem_responses_url'
:
reverse
(
'get_problem_responses'
,
kwargs
=
{
'course_id'
:
unicode
(
course_key
)}),
'get_grading_config_url'
:
reverse
(
'get_grading_config'
,
kwargs
=
{
'course_id'
:
unicode
(
course_key
)}),
'get_students_features_url'
:
reverse
(
'get_students_features'
,
kwargs
=
{
'course_id'
:
unicode
(
course_key
)}),
'get_issued_certificates_url'
:
reverse
(
'get_issued_certificates'
,
kwargs
=
{
'course_id'
:
unicode
(
course_key
)}
),
'get_students_who_may_enroll_url'
:
reverse
(
'get_students_who_may_enroll'
,
kwargs
=
{
'course_id'
:
unicode
(
course_key
)}
),
...
...
lms/djangoapps/instructor_analytics/basic.py
View file @
74b08249
...
...
@@ -4,6 +4,7 @@ Student and course analytics.
Serve miscellaneous course and student data
"""
import
json
import
datetime
from
shoppingcart.models
import
(
PaidCourseRegistration
,
CouponRedemption
,
CourseRegCodeItem
,
RegistrationCodeRedemption
,
CourseRegistrationCodeInvoiceItem
...
...
@@ -19,6 +20,9 @@ from microsite_configuration import microsite
from
student.models
import
CourseEnrollmentAllowed
from
edx_proctoring.api
import
get_all_exam_attempts
from
courseware.models
import
StudentModule
from
certificates.models
import
GeneratedCertificate
from
django.db.models
import
Count
from
certificates.models
import
CertificateStatuses
STUDENT_FEATURES
=
(
'id'
,
'username'
,
'first_name'
,
'last_name'
,
'is_staff'
,
'email'
)
...
...
@@ -38,6 +42,7 @@ SALE_ORDER_FEATURES = ('id', 'company_name', 'company_contact_name', 'company_co
AVAILABLE_FEATURES
=
STUDENT_FEATURES
+
PROFILE_FEATURES
COURSE_REGISTRATION_FEATURES
=
(
'code'
,
'course_id'
,
'created_by'
,
'created_at'
,
'is_valid'
)
COUPON_FEATURES
=
(
'code'
,
'course_id'
,
'percentage_discount'
,
'description'
,
'expiration_date'
,
'is_active'
)
CERTIFICATE_FEATURES
=
(
'course_id'
,
'mode'
,
'status'
,
'grade'
,
'created_date'
,
'is_active'
,
'error_reason'
)
UNAVAILABLE
=
"[unavailable]"
...
...
@@ -162,6 +167,32 @@ def sale_record_features(course_id, features):
return
[
sale_records_info
(
sale
,
features
)
for
sale
in
sales
]
def
issued_certificates
(
course_key
,
features
):
"""
Return list of issued certificates as dictionaries against the given course key.
issued_certificates(course_key, features)
would return [
{course_id: 'abc', 'total_issued_certificate': '5', 'mode': 'honor'}
{course_id: 'abc', 'total_issued_certificate': '10', 'mode': 'verified'}
{course_id: 'abc', 'total_issued_certificate': '15', 'mode': 'Professional Education'}
]
"""
report_run_date
=
datetime
.
date
.
today
()
.
strftime
(
"
%
B
%
d,
%
Y"
)
certificate_features
=
[
x
for
x
in
CERTIFICATE_FEATURES
if
x
in
features
]
generated_certificates
=
list
(
GeneratedCertificate
.
objects
.
filter
(
course_id
=
course_key
,
status
=
CertificateStatuses
.
downloadable
)
.
values
(
*
certificate_features
)
.
annotate
(
total_issued_certificate
=
Count
(
'mode'
)))
# Report run date
for
data
in
generated_certificates
:
data
[
'report_run_date'
]
=
report_run_date
return
generated_certificates
def
enrolled_students_features
(
course_key
,
features
):
"""
Return list of student features as dictionaries.
...
...
lms/static/coffee/src/instructor_dashboard/data_download.coffee
View file @
74b08249
...
...
@@ -11,12 +11,66 @@ std_ajax_err = -> window.InstructorDashboard.util.std_ajax_err.apply this, argum
PendingInstructorTasks
=
->
window
.
InstructorDashboard
.
util
.
PendingInstructorTasks
ReportDownloads
=
->
window
.
InstructorDashboard
.
util
.
ReportDownloads
# Data Download Certificate issued
class
@
DataDownload_Certificate
constructor
:
(
@
$container
)
->
# gather elements
@
$list_issued_certificate_table_btn
=
@
$container
.
find
(
"input[name='issued-certificates-list']'"
)
@
$list_issued_certificate_csv_btn
=
@
$container
.
find
(
"input[name='issued-certificates-csv']'"
)
@
$certificate_display_table
=
@
$container
.
find
'.certificate-data-display-table'
@
$certificates_request_response_error
=
@
$container
.
find
'.issued-certificates-error.request-response-error'
@
$list_issued_certificate_table_btn
.
click
(
e
)
=>
url
=
@
$list_issued_certificate_table_btn
.
data
'endpoint'
# Dynamically generate slickgrid table for displaying issued certificate information.
@
clear_ui
()
@
$certificate_display_table
.
text
gettext
(
'Loading data...'
)
# fetch user list
$
.
ajax
type
:
'POST'
url
:
url
error
:
(
std_ajax_err
)
=>
@
clear_ui
()
@
$certificates_request_response_error
.
text
gettext
(
"Error getting issued certificates list."
)
$
(
".issued_certificates .issued-certificates-error.msg-error"
).
css
({
"display"
:
"block"
})
success
:
(
data
)
=>
@
clear_ui
()
# display on a SlickGrid
options
=
enableCellNavigation
:
true
enableColumnReorder
:
false
forceFitColumns
:
true
rowHeight
:
35
columns
=
({
id
:
feature
,
field
:
feature
,
name
:
data
.
feature_names
[
feature
]}
for
feature
in
data
.
queried_features
)
grid_data
=
data
.
certificates
$table_placeholder
=
$
'<div/>'
,
class
:
'slickgrid'
@
$certificate_display_table
.
append
$table_placeholder
new
Slick
.
Grid
(
$table_placeholder
,
grid_data
,
columns
,
options
)
@
$list_issued_certificate_csv_btn
.
click
(
e
)
=>
@
clear_ui
()
url
=
@
$list_issued_certificate_csv_btn
.
data
'endpoint'
location
.
href
=
url
+
'?csv=true'
clear_ui
:
->
# Clear any generated tables, warning messages, etc of certificates.
@
$certificate_display_table
.
empty
()
@
$certificates_request_response_error
.
empty
()
$
(
".issued-certificates-error.msg-error"
).
css
({
"display"
:
"none"
})
# Data Download Section
class
DataDownload
constructor
:
(
@
$section
)
->
# attach self to html so that instructor_dashboard.coffee can find
# this object to call event handlers like 'onClickTitle'
@
$section
.
data
'wrapper'
,
@
# isolate # initialize DataDownload_Certificate subsection
new
DataDownload_Certificate
@
$section
.
find
'.issued_certificates'
# gather elements
@
$list_studs_btn
=
@
$section
.
find
(
"input[name='list-profiles']'"
)
@
$list_studs_csv_btn
=
@
$section
.
find
(
"input[name='list-profiles-csv']'"
)
...
...
@@ -34,7 +88,7 @@ class DataDownload
@
$download_display_text
=
@
$download
.
find
'.data-display-text'
@
$download_request_response_error
=
@
$download
.
find
'.request-response-error'
@
$reports
=
@
$section
.
find
'.reports-download-container'
@
$download_display_table
=
@
$reports
.
find
'.data-display-table'
@
$download_display_table
=
@
$reports
.
find
'.
profile-
data-display-table'
@
$reports_request_response
=
@
$reports
.
find
'.request-response'
@
$reports_request_response_error
=
@
$reports
.
find
'.request-response-error'
...
...
lms/static/js/fixtures/instructor_dashboard/data_download.html
0 → 100644
View file @
74b08249
<div
class=
"issued_certificates"
>
<p>
${_("Click to list certificates that are issued for this course:")}
</p>
<span>
<input
type=
"button"
name=
"issued-certificates-list"
value=
"View Certificates Issued"
>
<input
type=
"button"
name=
"issued-certificates-csv"
value=
"Download CSV of Certificates Issued"
>
</span>
<div
class=
"data-display-table certificate-data-display-table"
id=
"data-issued-certificates-table"
></div>
<div
class=
"issued-certificates-error request-response-error msg msg-error copy"
></div>
</div>
\ No newline at end of file
lms/static/js/spec/instructor_dashboard/data_download_spec.js
0 → 100644
View file @
74b08249
/*global define */
define
([
'jquery'
,
'coffee/src/instructor_dashboard/data_download'
,
'common/js/spec_helpers/ajax_helpers'
,
'slick.grid'
],
function
(
$
,
DataDownload
,
AjaxHelpers
)
{
'use strict'
;
describe
(
"edx.instructor_dashboard.data_download.DataDownload_Certificate"
,
function
()
{
var
url
,
data_download_certificate
;
beforeEach
(
function
()
{
loadFixtures
(
'js/fixtures/instructor_dashboard/data_download.html'
);
data_download_certificate
=
new
window
.
DataDownload_Certificate
(
$
(
'.issued_certificates'
));
url
=
'/courses/PU/FSc/2014_T4/instructor/api/get_issued_certificates'
;
data_download_certificate
.
$list_issued_certificate_table_btn
.
data
(
'endpoint'
,
url
);
});
it
(
'show data on success callback'
,
function
()
{
// Spy on AJAX requests
var
requests
=
AjaxHelpers
.
requests
(
this
);
var
data
=
{
'certificates'
:
[{
'course_id'
:
'xyz_test'
,
'mode'
:
'honor'
}],
'queried_features'
:
[
'course_id'
,
'mode'
],
'feature_names'
:
{
'course_id'
:
'Course ID'
,
'mode'
:
' Mode'
}
};
data_download_certificate
.
$list_issued_certificate_table_btn
.
click
();
AjaxHelpers
.
expectJsonRequest
(
requests
,
'POST'
,
url
);
// Simulate a success response from the server
AjaxHelpers
.
respondWithJson
(
requests
,
data
);
expect
(
data_download_certificate
.
$certificate_display_table
.
html
()
.
indexOf
(
'Course ID'
)
!==
-
1
).
toBe
(
true
);
expect
(
data_download_certificate
.
$certificate_display_table
.
html
()
.
indexOf
(
'Mode'
)
!==
-
1
).
toBe
(
true
);
expect
(
data_download_certificate
.
$certificate_display_table
.
html
()
.
indexOf
(
'xyz_test'
)
!==
-
1
).
toBe
(
true
);
expect
(
data_download_certificate
.
$certificate_display_table
.
html
()
.
indexOf
(
'honor'
)
!==
-
1
).
toBe
(
true
);
});
it
(
'show error on failure callback'
,
function
()
{
// Spy on AJAX requests
var
requests
=
AjaxHelpers
.
requests
(
this
);
data_download_certificate
.
$list_issued_certificate_table_btn
.
click
();
// Simulate a error response from the server
AjaxHelpers
.
respondWithError
(
requests
);
expect
(
data_download_certificate
.
$certificates_request_response_error
.
text
())
.
toEqual
(
'Error getting issued certificates list.'
);
});
it
(
'error should be clear from UI on success callback'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
data_download_certificate
.
$list_issued_certificate_table_btn
.
click
();
// Simulate a error response from the server
AjaxHelpers
.
respondWithError
(
requests
);
expect
(
data_download_certificate
.
$certificates_request_response_error
.
text
())
.
toEqual
(
'Error getting issued certificates list.'
);
// Simulate a success response from the server
data_download_certificate
.
$list_issued_certificate_table_btn
.
click
();
AjaxHelpers
.
expectJsonRequest
(
requests
,
'POST'
,
url
);
expect
(
data_download_certificate
.
$certificates_request_response_error
.
text
())
.
not
.
toEqual
(
'Error getting issued certificates list'
);
});
});
});
lms/static/js/spec/main.js
View file @
74b08249
...
...
@@ -6,6 +6,7 @@
'codemirror'
:
'xmodule_js/common_static/js/vendor/CodeMirror/codemirror'
,
'jquery'
:
'xmodule_js/common_static/js/vendor/jquery.min'
,
'jquery.ui'
:
'xmodule_js/common_static/js/vendor/jquery-ui.min'
,
'jquery.eventDrag'
:
'xmodule_js/common_static/js/vendor/jquery.event.drag-2.2'
,
'jquery.flot'
:
'xmodule_js/common_static/js/vendor/flot/jquery.flot.min'
,
'jquery.form'
:
'xmodule_js/common_static/js/vendor/jquery.form'
,
'jquery.markitup'
:
'xmodule_js/common_static/js/vendor/markitup/jquery.markitup'
,
...
...
@@ -89,7 +90,9 @@
'annotator_1.2.9'
:
'xmodule_js/common_static/js/vendor/edxnotes/annotator-full.min'
,
// Common edx utils
'common/js/utils/edx.utils.validate'
:
'xmodule_js/common_static/common/js/utils/edx.utils.validate'
'common/js/utils/edx.utils.validate'
:
'xmodule_js/common_static/common/js/utils/edx.utils.validate'
,
'slick.grid'
:
'xmodule_js/common_static/js/vendor/slick.grid'
,
'slick.core'
:
'xmodule_js/common_static/js/vendor/slick.core'
},
shim
:
{
'gettext'
:
{
...
...
lms/static/js_test.yml
View file @
74b08249
...
...
@@ -65,6 +65,9 @@ lib_paths:
-
xmodule_js/common_static/js/vendor/moment.min.js
-
xmodule_js/common_static/js/vendor/moment-with-locales.min.js
-
xmodule_js/common_static/common/js/utils/edx.utils.validate.js
-
xmodule_js/common_static/js/vendor/slick.core.js
-
xmodule_js/common_static/js/vendor/slick.grid.js
-
xmodule_js/common_static/js/vendor/jquery.event.drag-2.2.js
# Paths to source JavaScript files
src_paths
:
...
...
lms/templates/instructor/instructor_dashboard_2/data_download.html
View file @
74b08249
...
...
@@ -52,11 +52,21 @@
<input
type=
"button"
name=
"list-problem-responses-csv"
value=
"${_("
Download
a
CSV
of
problem
responses
")}"
data-endpoint=
"${ section_data['get_problem_responses_url'] }"
data-csv=
"true"
>
</p>
<div
class=
"issued_certificates"
>
<p>
${_("Click to list certificates that are issued for this course:")}
</p>
<span>
<input
type=
"button"
name=
"issued-certificates-list"
value=
"${_("
View
Certificates
Issued
")}"
data-csv=
"false"
data-endpoint=
"${ section_data['get_issued_certificates_url'] }"
>
<input
type=
"button"
name=
"issued-certificates-csv"
value=
"${_("
Download
CSV
of
Certificates
Issued
")}"
data-csv=
"true"
data-endpoint=
"${ section_data['get_issued_certificates_url'] }"
>
</span>
<div
class=
"data-display-table certificate-data-display-table"
id=
"data-issued-certificates-table"
></div>
<div
class=
"issued-certificates-error request-response-error msg msg-error copy"
></div>
</div>
% if not disable_buttons:
<p>
${_("For smaller courses, click to list profile information for enrolled students 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
profile-data-display-table
"
id=
"data-student-profiles-table"
></div>
%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>
...
...
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