Wire up cert status
This commit is contained in:
committed by
Carlos Andrés Rocha
parent
01dcf291b6
commit
cf33d85ef9
@@ -29,6 +29,9 @@ from django_future.csrf import ensure_csrf_cookie, csrf_exempt
|
||||
from student.models import (Registration, UserProfile,
|
||||
PendingNameChange, PendingEmailChange,
|
||||
CourseEnrollment)
|
||||
|
||||
from certificates.models import CertificateStatuses, certificate_status_for_student
|
||||
|
||||
from xmodule.course_module import CourseDescriptor
|
||||
from xmodule.modulestore.exceptions import ItemNotFoundError
|
||||
from xmodule.modulestore.django import modulestore
|
||||
@@ -143,11 +146,15 @@ def dashboard(request):
|
||||
show_courseware_links_for = frozenset(course.id for course in courses
|
||||
if has_access(request.user, course, 'load'))
|
||||
|
||||
cert_statuses = [certificate_status_for_student(request.user, course.id) for course in courses]
|
||||
|
||||
context = {'courses': courses,
|
||||
'message': message,
|
||||
'staff_access': staff_access,
|
||||
'errored_courses': errored_courses,
|
||||
'show_courseware_links_for' : show_courseware_links_for}
|
||||
'show_courseware_links_for' : show_courseware_links_for,
|
||||
'cert_statuses': cert_statuses,
|
||||
}
|
||||
|
||||
return render_to_response('dashboard.html', context)
|
||||
|
||||
@@ -206,13 +213,13 @@ def change_enrollment(request):
|
||||
return {'success': False,
|
||||
'error': 'enrollment in {} not allowed at this time'
|
||||
.format(course.display_name)}
|
||||
|
||||
org, course_num, run=course_id.split("/")
|
||||
|
||||
org, course_num, run=course_id.split("/")
|
||||
statsd.increment("common.student.enrollment",
|
||||
tags=["org:{0}".format(org),
|
||||
"course:{0}".format(course_num),
|
||||
"run:{0}".format(run)])
|
||||
|
||||
|
||||
enrollment, created = CourseEnrollment.objects.get_or_create(user=user, course_id=course.id)
|
||||
return {'success': True}
|
||||
|
||||
@@ -220,13 +227,13 @@ def change_enrollment(request):
|
||||
try:
|
||||
enrollment = CourseEnrollment.objects.get(user=user, course_id=course_id)
|
||||
enrollment.delete()
|
||||
|
||||
org, course_num, run=course_id.split("/")
|
||||
|
||||
org, course_num, run=course_id.split("/")
|
||||
statsd.increment("common.student.unenrollment",
|
||||
tags=["org:{0}".format(org),
|
||||
"course:{0}".format(course_num),
|
||||
"run:{0}".format(run)])
|
||||
|
||||
|
||||
return {'success': True}
|
||||
except CourseEnrollment.DoesNotExist:
|
||||
return {'success': False, 'error': 'You are not enrolled for this course.'}
|
||||
@@ -275,13 +282,13 @@ def login_user(request, error=""):
|
||||
log.info("Login success - {0} ({1})".format(username, email))
|
||||
|
||||
try_change_enrollment(request)
|
||||
|
||||
|
||||
statsd.increment("common.student.successful_login")
|
||||
|
||||
|
||||
return HttpResponse(json.dumps({'success': True}))
|
||||
|
||||
|
||||
log.warning("Login failed - Account not active for user {0}, resending activation".format(username))
|
||||
|
||||
|
||||
reactivation_email_for_user(user)
|
||||
not_activated_msg = "This account has not been activated. We have " + \
|
||||
"sent another activation message. Please check your " + \
|
||||
@@ -483,9 +490,9 @@ def create_account(request, post_override=None):
|
||||
log.debug('bypassing activation email')
|
||||
login_user.is_active = True
|
||||
login_user.save()
|
||||
|
||||
|
||||
statsd.increment("common.student.account_created")
|
||||
|
||||
|
||||
js = {'success': True}
|
||||
return HttpResponse(json.dumps(js), mimetype="application/json")
|
||||
|
||||
@@ -541,9 +548,9 @@ def password_reset(request):
|
||||
''' Attempts to send a password reset e-mail. '''
|
||||
if request.method != "POST":
|
||||
raise Http404
|
||||
|
||||
|
||||
# By default, Django doesn't allow Users with is_active = False to reset their passwords,
|
||||
# but this bites people who signed up a long time ago, never activated, and forgot their
|
||||
# but this bites people who signed up a long time ago, never activated, and forgot their
|
||||
# password. So for their sake, we'll auto-activate a user for whome password_reset is called.
|
||||
try:
|
||||
user = User.objects.get(email=request.POST['email'])
|
||||
@@ -551,7 +558,7 @@ def password_reset(request):
|
||||
user.save()
|
||||
except:
|
||||
log.exception("Tried to auto-activate user to enable password reset, but failed.")
|
||||
|
||||
|
||||
form = PasswordResetForm(request.POST)
|
||||
if form.is_valid():
|
||||
form.save(use_https = request.is_secure(),
|
||||
@@ -589,7 +596,7 @@ def reactivation_email_for_user(user):
|
||||
res = user.email_user(subject, message, settings.DEFAULT_FROM_EMAIL)
|
||||
|
||||
return HttpResponse(json.dumps({'success': True}))
|
||||
|
||||
|
||||
|
||||
@ensure_csrf_cookie
|
||||
def change_email_request(request):
|
||||
@@ -764,8 +771,8 @@ def accept_name_change_by_id(id):
|
||||
|
||||
@ensure_csrf_cookie
|
||||
def accept_name_change(request):
|
||||
''' JSON: Name change process. Course staff clicks 'accept' on a given name change
|
||||
|
||||
''' JSON: Name change process. Course staff clicks 'accept' on a given name change
|
||||
|
||||
We used this during the prototype but now we simply record name changes instead
|
||||
of manually approving them. Still keeping this around in case we want to go
|
||||
back to this approval method.
|
||||
|
||||
@@ -298,6 +298,16 @@ class CourseDescriptor(SequenceDescriptor):
|
||||
# Explicit comparison to True because we always want to return a bool.
|
||||
return self.metadata.get('hide_progress_tab') == True
|
||||
|
||||
@property
|
||||
def end_of_course_survey_url(self):
|
||||
"""
|
||||
Pull from policy. Once we have our own survey module set up, can change this to point to an automatically
|
||||
created survey for each class.
|
||||
|
||||
Returns None if no url specified.
|
||||
"""
|
||||
return self.metadata.get('end_of_course_survey_url')
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
return self.display_name
|
||||
|
||||
@@ -2,7 +2,7 @@ from django.contrib.auth.models import User
|
||||
from django.db import models
|
||||
from datetime import datetime
|
||||
|
||||
'''
|
||||
"""
|
||||
Certificates are created for a student and an offering of a course.
|
||||
|
||||
When a certificate is generated, a unique ID is generated so that
|
||||
@@ -35,8 +35,7 @@ State diagram:
|
||||
v v v
|
||||
[downloadable] [downloadable] [deleted]
|
||||
|
||||
'''
|
||||
|
||||
"""
|
||||
|
||||
class CertificateStatuses(object):
|
||||
unavailable = 'unavailable'
|
||||
@@ -88,6 +87,7 @@ def certificate_status_for_student(student, course_id):
|
||||
If the status is "downloadable", the dictionary also contains
|
||||
"download_url".
|
||||
|
||||
If the student has been graded, the dictionary also contains their grade for the course.
|
||||
'''
|
||||
|
||||
try:
|
||||
@@ -97,6 +97,7 @@ def certificate_status_for_student(student, course_id):
|
||||
return {
|
||||
'status': CertificateStatuses.downloadable,
|
||||
'download_url': generated_certificate.download_url,
|
||||
'grade': generated_certificate.grade,
|
||||
}
|
||||
else:
|
||||
return {'status': generated_certificate.status}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
from django.core.urlresolvers import reverse
|
||||
from courseware.courses import course_image_url, get_course_about_section
|
||||
from courseware.access import has_access
|
||||
from certificates.models import CertificateStatuses
|
||||
%>
|
||||
<%inherit file="main.html" />
|
||||
|
||||
@@ -114,7 +115,7 @@
|
||||
</header>
|
||||
|
||||
% if len(courses) > 0:
|
||||
% for course in courses:
|
||||
% for course, cert_status in zip(courses, cert_statuses):
|
||||
|
||||
<article class="my-course">
|
||||
<%
|
||||
@@ -145,35 +146,65 @@
|
||||
</a>
|
||||
</article>
|
||||
|
||||
<div class="message message-status course-status-processing is-shown">
|
||||
<p class="message-copy">Final course details are being wrapped up at this time. Your final standing will be available shortly.</p>
|
||||
</div>
|
||||
|
||||
<div class="message message-status course-status-certrendering is-shown">
|
||||
<p class="message-copy">You have received a grade of <span class="grade-value">B</span> in this course.</p>
|
||||
% if course.has_ended:
|
||||
<%
|
||||
passing_grade = False
|
||||
cert_button = False
|
||||
survey_button = False
|
||||
if cert_status['status'] in [CertificateStatuses.generating, CertificateStatuses.regenerating]:
|
||||
status_css_class = 'course-status-certrendering'
|
||||
cert_button = True
|
||||
survey_button = True
|
||||
passing_grade = True
|
||||
elif cert_status['status'] == CertificateStatuses.downloadable:
|
||||
status_css_class = 'course-status-certavailable'
|
||||
cert_button = True
|
||||
survey_button = True
|
||||
passing_grade = True
|
||||
elif cert_status['status'] == CertificateStatuses.notpassing:
|
||||
status_css_class = 'course-status-certnotavailable'
|
||||
survey_button = True
|
||||
else cert_status['status']:
|
||||
# This is primarily the 'unavailable' state, but also 'error', 'deleted', etc.
|
||||
status_css_class = 'course-status-processing'
|
||||
|
||||
<ul class="actions">
|
||||
<li class="action"><span class="btn disabled" href="">Your Certificate is Generating</span></li>
|
||||
<li class="action"><a class="cta" href="">Complete our course feedback survey</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
if survey_button and not course.end_of_course_survey_url:
|
||||
survey_button = False
|
||||
%>
|
||||
<div class="message message-status ${status_css_class} is-shown">
|
||||
|
||||
<div class="message message-status course-status-certavailable is-shown">
|
||||
<p class="message-copy">You have received a grade of <span class="grade-value">B</span> in this course.</p>
|
||||
% if cert_status == CertificateStatuses.unavailable:
|
||||
<p class="message-copy">Final course details are being wrapped up at this time.
|
||||
Your final standing will be available shortly.</p>
|
||||
% elif passing_grade:
|
||||
<p class="message-copy">You have received a grade of
|
||||
<span class="grade-value">${cert_status['grade']}</span>
|
||||
in this course.</p>
|
||||
% elif cert_status == CertificateStatuses.notpassing:
|
||||
<p class="message-copy">You did not complete the necessary requirements for
|
||||
completion of this course. Your grade was <span class="grade-value">${cert_status['grade']}</span>
|
||||
</p>
|
||||
% endif
|
||||
% if cert_button or survey_button:
|
||||
<ul class="actions">
|
||||
% if cert_button and cert_status['status'] == CertificateStatuses.generating:
|
||||
<li class="action"><span class="btn disabled" href="">Your Certificate is Generating</span></li>
|
||||
% elif cert_button and cert_status['status'] == CertificateStatuses.downloadable:
|
||||
<li class="action">
|
||||
<a class="btn" href="${cert_status['download_url']}"
|
||||
title="This link will open/download a PDF document">
|
||||
Download Your PDF Certificate</a></li>
|
||||
% endif
|
||||
% if survey_button:
|
||||
<li class="action"><a class="cta" href="${course.end_of_course_survey_url}">
|
||||
Complete our course feedback survey</a></li>
|
||||
% endif
|
||||
</ul>
|
||||
% endif
|
||||
</div>
|
||||
|
||||
<ul class="actions">
|
||||
<li class="action"><a class="btn" href="" title="This link will open/download a PDF document">Download Your PDF Certificate</a></li>
|
||||
<li class="action"><a class="cta" href="">Complete our course feedback survey</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="message message-status course-status-certnotavailable is-shown">
|
||||
<p class="message-copy">You did not complete the necessary requirements for completion of this course.</p>
|
||||
|
||||
<ul class="actions">
|
||||
<li class="action"><a class="cta" href="">Complete our course feedback survey</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
% endif
|
||||
|
||||
<a href="#unenroll-modal" class="unenroll" rel="leanModal" data-course-id="${course.id}" data-course-number="${course.number}">Unregister</a>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user