Commit 5835468d by M. Rehan Committed by GitHub

Merge pull request #13362 from edx/mushtaq/generate-verified-users-with-audit-certs

Generate certificates for verified users with audit certificate statuses
parents c01df600 65ef041a
......@@ -95,7 +95,9 @@ class CertificateStatuses(object):
readable_statuses = {
downloadable: "already received",
notpassing: "didn't receive",
error: "error states"
error: "error states",
audit_passing: "audit passing states",
audit_notpassing: "audit not passing states",
}
PASSED_STATUSES = (downloadable, generating)
......
......@@ -3,12 +3,21 @@ import contextlib
import ddt
import mock
import json
import pytz
from datetime import datetime, timedelta
from nose.plugins.attrib import attr
from django.core.urlresolvers import reverse
from django.core.exceptions import ObjectDoesNotExist
from django.test.utils import override_settings
from django.conf import settings
from course_modes.models import CourseMode
from capa.xqueue_interface import XQueueInterface
from lms.djangoapps.grades.tests.utils import mock_passing_grade
from lms.djangoapps.verify_student.tests.factories import SoftwareSecurePhotoVerificationFactory
from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
from config_models.models import cache
......@@ -344,6 +353,85 @@ class CertificatesInstructorApiTest(SharedModuleStoreTestCase):
u'the "Pending Tasks" section.'
)
@override_settings(AUDIT_CERT_CUTOFF_DATE=datetime.now(pytz.UTC) - timedelta(days=1))
@ddt.data(
(CertificateStatuses.generating, 'ID Verified', 'approved'),
(CertificateStatuses.unverified, 'Not ID Verified', 'denied'),
)
@ddt.unpack
def test_verified_users_with_audit_certs(self, expected_cert_status, verification_output, id_verification_status):
"""
Test certificate regeneration for verified users with audit certificates.
Scenario:
Enroll user in a course in audit mode,
User passed the course and now he has `audit_passing` certificate status,
User switched to verified mode and is ID verified,
Regenerate certificate for it,
Modified certificate status is `generating` if user is ID verified otherwise `unverified`.
"""
# Check that user is enrolled in audit mode.
enrollment = CourseEnrollment.get_enrollment(self.user, self.course.id)
self.assertEquals(enrollment.mode, CourseMode.AUDIT)
with mock_passing_grade():
# Generate certificate for user and check that user has a audit passing certificate.
cert_status = certs_api.generate_user_certificates(
student=self.user,
course_key=self.course.id,
course=self.course,
)
# Check that certificate status is 'audit_passing'.
self.assertEquals(cert_status, CertificateStatuses.audit_passing)
# Update user enrollment mode to verified mode.
enrollment.update_enrollment(mode=CourseMode.VERIFIED)
self.assertEquals(enrollment.mode, CourseMode.VERIFIED)
# Create and assert user's ID verification record.
SoftwareSecurePhotoVerificationFactory.create(user=self.user, status=id_verification_status)
actual_verification_status = SoftwareSecurePhotoVerification.verification_status_for_user(
self.user,
self.course.id,
enrollment.mode,
)
self.assertEquals(actual_verification_status, verification_output)
# Login the client and access the url with 'audit_passing' status.
self.client.login(username=self.global_staff.username, password='test')
url = reverse(
'start_certificate_regeneration',
kwargs={'course_id': unicode(self.course.id)}
)
with mock.patch.object(XQueueInterface, 'send_to_queue') as mock_send:
mock_send.return_value = (0, None)
response = self.client.post(
url,
{'certificate_statuses': [CertificateStatuses.audit_passing]}
)
# Assert 200 status code in response
self.assertEquals(response.status_code, 200)
res_json = json.loads(response.content)
# Assert request is successful
self.assertTrue(res_json['success'])
# Assert success message
self.assertEquals(
res_json['message'],
u'Certificate regeneration task has been started. '
u'You can view the status of the generation task in '
u'the "Pending Tasks" section.'
)
# Now, check whether user has audit certificate.
cert = certs_api.get_certificate_for_user(self.user.username, self.course.id)
self.assertNotEquals(cert['status'], CertificateStatuses.audit_passing)
self.assertEquals(cert['status'], expected_cert_status)
def test_certificate_regeneration_error(self):
"""
Test certificate regeneration errors out when accessed with either empty list of 'certificate_statuses' or
......
......@@ -2862,7 +2862,13 @@ def start_certificate_regeneration(request, course_id):
)
# Check if the selected statuses are allowed
allowed_statuses = [CertificateStatuses.downloadable, CertificateStatuses.error, CertificateStatuses.notpassing]
allowed_statuses = [
CertificateStatuses.downloadable,
CertificateStatuses.error,
CertificateStatuses.notpassing,
CertificateStatuses.audit_passing,
CertificateStatuses.audit_notpassing,
]
if not set(certificates_statuses).issubset(allowed_statuses):
return JsonResponse(
{'message': _('Please select certificate statuses from the list only.')},
......
......@@ -130,6 +130,18 @@ from openedx.core.djangolib.js_utils import dump_js_escaped_json, js_escaped_str
</div>
<div>
<label>
<input id="certificate_status_${section_data['status'].audit_passing}" type="checkbox" name="certificate_statuses" value="${section_data['status'].audit_passing}">
${_("Regenerate for learners with audit passing state. ({count})").format(count=section_data['certificate_statuses_with_count'].get(section_data['status'].audit_passing, 0))}
</label>
</div>
<div>
<label>
<input id="certificate_status_${section_data['status'].audit_notpassing}" type="checkbox" name="certificate_statuses" value="${section_data['status'].audit_notpassing}">
${_("Regenerate for learners with audit not passing state. ({count})").format(count=section_data['certificate_statuses_with_count'].get(section_data['status'].audit_notpassing, 0))}
</label>
</div>
<div>
<label>
<input id="certificate_status_${section_data['status'].error}" type="checkbox" name="certificate_statuses" value="${section_data['status'].error}">
${_("Regenerate for learners in an error state. ({count})").format(count=section_data['certificate_statuses_with_count'].get(section_data['status'].error, 0))}
</label>
......
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