diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py
index 8810c8609b..5d5dff81d2 100644
--- a/common/djangoapps/student/views.py
+++ b/common/djangoapps/student/views.py
@@ -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.
diff --git a/common/lib/xmodule/xmodule/course_module.py b/common/lib/xmodule/xmodule/course_module.py
index fc27a692ea..46e8e145df 100644
--- a/common/lib/xmodule/xmodule/course_module.py
+++ b/common/lib/xmodule/xmodule/course_module.py
@@ -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
diff --git a/lms/djangoapps/certificates/models.py b/lms/djangoapps/certificates/models.py
index 98b76d8fdc..1434510920 100644
--- a/lms/djangoapps/certificates/models.py
+++ b/lms/djangoapps/certificates/models.py
@@ -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}
diff --git a/lms/templates/dashboard.html b/lms/templates/dashboard.html
index ad2d66f8be..c6c71017b3 100644
--- a/lms/templates/dashboard.html
+++ b/lms/templates/dashboard.html
@@ -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 @@
% if len(courses) > 0:
- % for course in courses:
+ % for course, cert_status in zip(courses, cert_statuses):