Commit 12a599b0 by David Ormsbee

Basic UI for generating certificates from a grade report.

parent 25146946
...@@ -1567,11 +1567,11 @@ def list_report_downloads(_request, course_id): ...@@ -1567,11 +1567,11 @@ def list_report_downloads(_request, course_id):
List grade CSV files that are available for download for this course. List grade CSV files that are available for download for this course.
""" """
course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id) course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)
report_store = ReportStore.from_config() report_store = ReportStore.from_config()
response_payload = { response_payload = {
'downloads': [ 'downloads': [
dict(name=name, url=url, link='<a href="{}">{}</a>'.format(url, name)) dict(name=name, url=url, link='<a href="{}" data-filename="{}">{}</a>'.format(url, name, name))
for name, url in report_store.links_for(course_id) for name, url in report_store.links_for(course_id)
] ]
} }
...@@ -1596,6 +1596,34 @@ def calculate_grades_csv(request, course_id): ...@@ -1596,6 +1596,34 @@ def calculate_grades_csv(request, course_id):
"status": already_running_status "status": already_running_status
}) })
def _generate_certificates_from_grades_csv_task(course_id, filename):
"""Assume this will be run async later."""
report_store = ReportStore.from_config()
grades_csv = report_store.get_as_string(CourseKey.from_string(course_id), filename)
print grades_csv
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
@require_post_params(filename="Name of file to generate certificates from")
def generate_certificates_from_grades_csv(request, course_id):
"""
List grade CSV files that are available for download for this course.
"""
# Make this celery later?
filename = request.POST['filename']
result = _generate_certificates_from_grades_csv_task(course_id, filename)
return JsonResponse({})
# response_payload = {
# 'downloads': [
# dict(name=name, url=url, link='<a href="{}" data-filename="{}">{}</a>'.format(url, name, name))
# for name, url in report_store.links_for(course_id)
# ]
# }
# return JsonResponse(response_payload)
@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)
......
...@@ -67,6 +67,8 @@ urlpatterns = patterns('', # nopep8 ...@@ -67,6 +67,8 @@ urlpatterns = patterns('', # nopep8
'instructor.views.api.list_report_downloads', name="list_report_downloads"), 'instructor.views.api.list_report_downloads', name="list_report_downloads"),
url(r'calculate_grades_csv$', url(r'calculate_grades_csv$',
'instructor.views.api.calculate_grades_csv', name="calculate_grades_csv"), 'instructor.views.api.calculate_grades_csv', name="calculate_grades_csv"),
url(r'generate_certificates_from_grades_csv$',
'instructor.views.api.generate_certificates_from_grades_csv', name="generate_certificates_from_grades_csv"),
# Registration Codes.. # Registration Codes..
url(r'get_registration_codes$', url(r'get_registration_codes$',
......
...@@ -320,6 +320,7 @@ def _section_data_download(course, access): ...@@ -320,6 +320,7 @@ def _section_data_download(course, access):
'list_instructor_tasks_url': reverse('list_instructor_tasks', kwargs={'course_id': course_key.to_deprecated_string()}), 'list_instructor_tasks_url': reverse('list_instructor_tasks', kwargs={'course_id': course_key.to_deprecated_string()}),
'list_report_downloads_url': reverse('list_report_downloads', kwargs={'course_id': course_key.to_deprecated_string()}), 'list_report_downloads_url': reverse('list_report_downloads', kwargs={'course_id': course_key.to_deprecated_string()}),
'calculate_grades_csv_url': reverse('calculate_grades_csv', kwargs={'course_id': course_key.to_deprecated_string()}), 'calculate_grades_csv_url': reverse('calculate_grades_csv', kwargs={'course_id': course_key.to_deprecated_string()}),
'generate_certificates_from_grades_csv': reverse('generate_certificates_from_grades_csv', kwargs={'course_id': course_key.to_deprecated_string()})
} }
return section_data return section_data
......
...@@ -274,6 +274,10 @@ class S3ReportStore(ReportStore): ...@@ -274,6 +274,10 @@ class S3ReportStore(ReportStore):
return key return key
def get_as_string(self, course_id, filename):
key = self.key_for(course_id, filename)
return key.get_contents_as_string()
def store(self, course_id, filename, buff): def store(self, course_id, filename, buff):
""" """
Store the contents of `buff` in a directory determined by hashing Store the contents of `buff` in a directory determined by hashing
...@@ -373,6 +377,11 @@ class LocalFSReportStore(ReportStore): ...@@ -373,6 +377,11 @@ class LocalFSReportStore(ReportStore):
"""Return the full path to a given file for a given course.""" """Return the full path to a given file for a given course."""
return os.path.join(self.root_path, urllib.quote(course_id.to_deprecated_string(), safe=''), filename) return os.path.join(self.root_path, urllib.quote(course_id.to_deprecated_string(), safe=''), filename)
def get_as_string(self, course_id, filename):
full_path = self.path_to(course_id, filename)
with open(full_path, "rb") as report_file:
return report_file.read()
def store(self, course_id, filename, buff): def store(self, course_id, filename, buff):
""" """
Given the `course_id` and `filename`, store the contents of `buff` in Given the `course_id` and `filename`, store the contents of `buff` in
......
...@@ -158,6 +158,24 @@ class ReportDownloads ...@@ -158,6 +158,24 @@ class ReportDownloads
POLL_INTERVAL, => @reload_report_downloads() POLL_INTERVAL, => @reload_report_downloads()
) )
@$generate_certificates_from_grades_csv_selector = @$section.find("select#generate-certificates-from-grades-csv-selector")
@$generate_certificates_from_grades_csv_btn = @$section.find("input[name='generate-certificates-from-grades-csv']'")
@$generate_certificates_from_grades_csv_btn.attr("disabled", true)
@$generate_certificates_from_grades_csv_btn.click (e) =>
url = @$generate_certificates_from_grades_csv_btn.data 'endpoint'
$.ajax
dataType: 'json'
type: 'POST'
data:
filename: @$generate_certificates_from_grades_csv_selector.val()
url: url
error: (std_ajax_err) =>
@$reports_request_response_error.text gettext("Error generating certificates from grades report.")
$(".msg-error").css({"display":"block"})
success: (data) =>
@$reports_request_response.text data['status']
$(".msg-confirm").css({"display":"block"})
reload_report_downloads: -> reload_report_downloads: ->
endpoint = @$report_downloads_table.data 'endpoint' endpoint = @$report_downloads_table.data 'endpoint'
$.ajax $.ajax
...@@ -166,6 +184,7 @@ class ReportDownloads ...@@ -166,6 +184,7 @@ class ReportDownloads
success: (data) => success: (data) =>
if data.downloads.length if data.downloads.length
@create_report_downloads_table data.downloads @create_report_downloads_table data.downloads
@populate_generate_certificates_from_grades_csv_selector data.downloads
else else
console.log "No reports ready for download" console.log "No reports ready for download"
error: (std_ajax_err) => console.error "Error finding report downloads" error: (std_ajax_err) => console.error "Error finding report downloads"
...@@ -196,6 +215,25 @@ class ReportDownloads ...@@ -196,6 +215,25 @@ class ReportDownloads
grid = new Slick.Grid($table_placeholder, report_downloads_data, columns, options) grid = new Slick.Grid($table_placeholder, report_downloads_data, columns, options)
grid.autosizeColumns() grid.autosizeColumns()
populate_generate_certificates_from_grades_csv_selector: (report_downloads_data) ->
# If there are no reports available, disable the generate certs button
if report_downloads_data.length == 0
@$generate_certificates_from_grades_csv_btn.attr("disabled", true)
return
else
@$generate_certificates_from_grades_csv_btn.attr("disabled", false)
#if @$generate_certificates_from_grades_csv_selector.length > 0
# return
@$generate_certificates_from_grades_csv_selector.empty()
for report_download in report_downloads_data
@$generate_certificates_from_grades_csv_selector.append $ '<option/>',
text: report_download["name"]
value: report_download["name"]
if report_downloads_data.length is 0
@$generate_certificates_from_grades_csv_selector.hide()
# export for use # export for use
# create parent namespaces if they do not already exist. # create parent namespaces if they do not already exist.
......
...@@ -63,6 +63,22 @@ ...@@ -63,6 +63,22 @@
<div class="report-downloads-table" id="report-downloads-table" data-endpoint="${ section_data['list_report_downloads_url'] }" ></div> <div class="report-downloads-table" id="report-downloads-table" data-endpoint="${ section_data['list_report_downloads_url'] }" ></div>
</div> </div>
%if settings.FEATURES.get('ALLOW_COURSE_STAFF_GRADE_DOWNLOADS') or section_data['access']['admin']:
<p><b>${_("Issue Certificates from Grade Report")}</b></p>
<p>${_("Click to generate certificates from grade report.")}</p>
<p>
<label for="generate-certificates-from-grades-csv-selector">${_("Select an existing Grade Report:")}</label>
<select id="generate-certificates-from-grades-csv-selector" class="generate-certificates-from-grades-csv-selector">
<option> ${_("Getting reports...")} </option>
</select>
<br/>
<input type="button" name="generate-certificates-from-grades-csv" value="${_("Generate Certificates from Grade Report")}" data-endpoint="${ section_data['generate_certificates_from_grades_csv'] }"/>
</p>
%endif
%endif %endif
%if settings.FEATURES.get('ENABLE_INSTRUCTOR_BACKGROUND_TASKS'): %if settings.FEATURES.get('ENABLE_INSTRUCTOR_BACKGROUND_TASKS'):
......
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