Commit 0b903264 by Nimisha Asthagiri

MA-1667: Update Mobile API to support Web Certificates

parent a7e21bf1
......@@ -183,7 +183,7 @@ def certificate_downloadable_status(student, course_key):
if current_status['status'] == CertificateStatuses.downloadable:
response_data['is_downloadable'] = True
response_data['download_url'] = current_status['download_url']
response_data['download_url'] = get_certificate_url(student.id, course_key)
return response_data
......
......@@ -31,8 +31,57 @@ FEATURES_WITH_CERTS_ENABLED = settings.FEATURES.copy()
FEATURES_WITH_CERTS_ENABLED['CERTIFICATES_HTML_VIEW'] = True
class WebCertificateTestMixin(object):
"""
Mixin with helpers for testing Web Certificates.
"""
@contextmanager
def _mock_passing_grade(self):
"""
Mock the grading function to always return a passing grade.
"""
symbol = 'courseware.grades.grade'
with patch(symbol) as mock_grade:
mock_grade.return_value = {'grade': 'Pass', 'percent': 0.75}
yield
@contextmanager
def _mock_queue(self, is_successful=True):
"""
Mock the "send to XQueue" method to return either success or an error.
"""
symbol = 'capa.xqueue_interface.XQueueInterface.send_to_queue'
with patch(symbol) as mock_send_to_queue:
if is_successful:
mock_send_to_queue.return_value = (0, "Successfully queued")
else:
mock_send_to_queue.side_effect = XQueueAddToQueueError(1, self.ERROR_REASON)
yield mock_send_to_queue
def _setup_course_certificate(self):
"""
Creates certificate configuration for course
"""
certificates = [
{
'id': 1,
'name': 'Test Certificate Name',
'description': 'Test Certificate Description',
'course_title': 'tes_course_title',
'signatories': [],
'version': 1,
'is_active': True
}
]
self.course.certificates = {'certificates': certificates}
self.course.cert_html_view_enabled = True
self.course.save()
self.store.update_item(self.course, self.user.id)
@attr('shard_1')
class CertificateDownloadableStatusTests(ModuleStoreTestCase):
class CertificateDownloadableStatusTests(WebCertificateTestMixin, ModuleStoreTestCase):
"""Tests for the `certificate_downloadable_status` helper function. """
def setUp(self):
......@@ -48,7 +97,7 @@ class CertificateDownloadableStatusTests(ModuleStoreTestCase):
self.request_factory = RequestFactory()
def test_user_cert_status_with_generating(self):
def test_cert_status_with_generating(self):
GeneratedCertificateFactory.create(
user=self.student,
course_id=self.course.id,
......@@ -65,7 +114,7 @@ class CertificateDownloadableStatusTests(ModuleStoreTestCase):
}
)
def test_user_cert_status_with_error(self):
def test_cert_status_with_error(self):
GeneratedCertificateFactory.create(
user=self.student,
course_id=self.course.id,
......@@ -82,7 +131,7 @@ class CertificateDownloadableStatusTests(ModuleStoreTestCase):
}
)
def test_user_with_out_cert(self):
def test_without_cert(self):
self.assertEqual(
certs_api.certificate_downloadable_status(self.student_no_cert, self.course.id),
{
......@@ -92,7 +141,7 @@ class CertificateDownloadableStatusTests(ModuleStoreTestCase):
}
)
def test_user_with_downloadable_cert(self):
def test_with_downloadable_pdf_cert(self):
GeneratedCertificateFactory.create(
user=self.student,
course_id=self.course.id,
......@@ -110,10 +159,29 @@ class CertificateDownloadableStatusTests(ModuleStoreTestCase):
}
)
@patch.dict(settings.FEATURES, {'CERTIFICATES_HTML_VIEW': True})
def test_with_downloadable_web_cert(self):
CourseEnrollment.enroll(self.student, self.course.id, mode='honor')
self._setup_course_certificate()
with self._mock_passing_grade():
certs_api.generate_user_certificates(self.student, self.course.id)
self.assertEqual(
certs_api.certificate_downloadable_status(self.student, self.course.id),
{
'is_downloadable': True,
'is_generating': False,
'download_url': '/certificates/user/{user_id}/course/{course_id}'.format(
user_id=self.student.id, # pylint: disable=no-member
course_id=self.course.id,
),
}
)
@attr('shard_1')
@override_settings(CERT_QUEUE='certificates')
class GenerateUserCertificatesTest(EventTestMixin, ModuleStoreTestCase):
class GenerateUserCertificatesTest(EventTestMixin, WebCertificateTestMixin, ModuleStoreTestCase):
"""Tests for generating certificates for students. """
ERROR_REASON = "Kaboom!"
......@@ -185,46 +253,6 @@ class GenerateUserCertificatesTest(EventTestMixin, ModuleStoreTestCase):
url = certs_api.get_certificate_url(self.student.id, self.course.id)
self.assertEqual(url, "")
@contextmanager
def _mock_passing_grade(self):
"""Mock the grading function to always return a passing grade. """
symbol = 'courseware.grades.grade'
with patch(symbol) as mock_grade:
mock_grade.return_value = {'grade': 'Pass', 'percent': 0.75}
yield
@contextmanager
def _mock_queue(self, is_successful=True):
"""Mock the "send to XQueue" method to return either success or an error. """
symbol = 'capa.xqueue_interface.XQueueInterface.send_to_queue'
with patch(symbol) as mock_send_to_queue:
if is_successful:
mock_send_to_queue.return_value = (0, "Successfully queued")
else:
mock_send_to_queue.side_effect = XQueueAddToQueueError(1, self.ERROR_REASON)
yield mock_send_to_queue
def _setup_course_certificate(self):
"""
Creates certificate configuration for course
"""
certificates = [
{
'id': 1,
'name': 'Test Certificate Name',
'description': 'Test Certificate Description',
'course_title': 'tes_course_title',
'signatories': [],
'version': 1,
'is_active': True
}
]
self.course.certificates = {'certificates': certificates}
self.course.cert_html_view_enabled = True
self.course.save()
self.store.update_item(self.course, self.user.id)
@attr('shard_1')
@ddt.ddt
......
......@@ -8,7 +8,7 @@ from django.template import defaultfilters
from courseware.access import has_access
from student.models import CourseEnrollment, User
from certificates.models import certificate_status_for_student, CertificateStatuses
from certificates.api import certificate_downloadable_status
from xmodule.course_module import DEFAULT_START_DATE
......@@ -89,10 +89,12 @@ class CourseEnrollmentSerializer(serializers.ModelSerializer):
def get_certificate(self, model):
"""Returns the information about the user's certificate in the course."""
certificate_info = certificate_status_for_student(model.user, model.course_id)
if certificate_info['status'] == CertificateStatuses.downloadable:
certificate_info = certificate_downloadable_status(model.user, model.course_id)
if certificate_info['is_downloadable']:
return {
"url": certificate_info['download_url'],
'url': self.context['request'].build_absolute_uri(
certificate_info['download_url']
),
}
else:
return {}
......
"""
Tests for users API
"""
# pylint: disable=no-member
import datetime
import ddt
from mock import patch
......@@ -10,6 +11,7 @@ from django.conf import settings
from django.utils import timezone
from django.template import defaultfilters
from certificates.api import generate_user_certificates
from certificates.models import CertificateStatuses
from certificates.tests.factories import GeneratedCertificateFactory
from courseware.access_response import (
......@@ -180,7 +182,7 @@ class TestUserEnrollmentApi(UrlResetMixin, MobileAPITestCase, MobileAuthUserTest
certificate_data = response.data[0]['certificate']
self.assertDictEqual(certificate_data, {})
def test_certificate(self):
def test_pdf_certificate(self):
self.login_and_enroll()
certificate_url = "http://test_certificate_url"
......@@ -196,6 +198,27 @@ class TestUserEnrollmentApi(UrlResetMixin, MobileAPITestCase, MobileAuthUserTest
certificate_data = response.data[0]['certificate']
self.assertEquals(certificate_data['url'], certificate_url)
@patch.dict(settings.FEATURES, {'CERTIFICATES_HTML_VIEW': True})
def test_web_certificate(self):
self.login_and_enroll()
self.course.cert_html_view_enabled = True
self.store.update_item(self.course, self.user.id)
with patch('courseware.grades.grade') as mock_grade:
mock_grade.return_value = {'grade': 'Pass', 'percent': 0.75}
generate_user_certificates(self.user, self.course.id)
response = self.api_response()
certificate_data = response.data[0]['certificate']
self.assertRegexpMatches(
certificate_data['url'],
r'http.*/certificates/user/{user_id}/course/{course_id}'.format(
user_id=self.user.id,
course_id=self.course.id,
)
)
def test_no_facebook_url(self):
self.login_and_enroll()
......
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