Example #1
0
    def handle(self, *args, **options):
        """Resubmit certificates with status 'error'.

        Arguments:
            username (unicode): Identifier for the certificate's user.

        Keyword Arguments:
            course_key_list (list): List of course key strings.

        Raises:
            CommandError

        """
        only_course_keys = []
        for course_key_str in options.get('course_key_list', []):
            try:
                only_course_keys.append(CourseKey.from_string(course_key_str))
            except InvalidKeyError:
                raise CommandError(
                    '"{course_key_str}" is not a valid course key.'.format(
                        course_key_str=course_key_str))

        if only_course_keys:
            LOGGER.info(
                (u'Starting to re-submit certificates with status "error" '
                 u'in these courses: %s'),
                ", ".join([unicode(key) for key in only_course_keys]))
        else:
            LOGGER.info(
                u'Starting to re-submit certificates with status "error".')

        # Retrieve the IDs of generated certificates with
        # error status in the set of courses we're considering.
        queryset = (
            GeneratedCertificate.objects.select_related('user')  # pylint: disable=no-member
        ).filter(status=CertificateStatuses.error)
        if only_course_keys:
            queryset = queryset.filter(course_id__in=only_course_keys)

        resubmit_list = [(cert.user, cert.course_id) for cert in queryset]
        course_cache = {}
        resubmit_count = 0
        for user, course_key in resubmit_list:
            course = self._load_course_with_cache(course_key, course_cache)

            if course is not None:
                certs_api.generate_user_certificates(user,
                                                     course_key,
                                                     course=course)
                resubmit_count += 1
                LOGGER.info((u"Re-submitted certificate for user %s "
                             u"in course '%s'"), user.id, course_key)
            else:
                LOGGER.error(
                    (u"Could not find course for course key '%s'.  "
                     u"Certificate for user %s will not be resubmitted."),
                    course_key, user.id)

        LOGGER.info("Finished resubmitting %s certificate tasks",
                    resubmit_count)
Example #2
0
    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)

        cert_status = certificate_status_for_student(self.student,
                                                     self.course.id)
        self.assertEqual(
            certs_api.certificate_downloadable_status(self.student,
                                                      self.course.id),
            {
                'is_downloadable':
                True,
                'is_generating':
                False,
                'is_unverified':
                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,
                ),
                'uuid':
                cert_status['uuid']
            })
Example #3
0
    def test_new_cert_requests_into_xqueue_returns_generating(self):
        with self._mock_passing_grade():
            with self._mock_queue():
                certs_api.generate_user_certificates(self.student, self.course.id)

        # Verify that the certificate has status 'generating'
        cert = GeneratedCertificate.objects.get(user=self.student, course_id=self.course.id)
        self.assertEqual(cert.status, 'generating')
Example #4
0
    def test_xqueue_submit_task_error(self):
        with mock_passing_grade():
            with self._mock_queue(is_successful=False):
                certs_api.generate_user_certificates(self.student, self.course.id)

        # Verify that the certificate has been marked with status error
        cert = GeneratedCertificate.eligible_certificates.get(user=self.student, course_id=self.course.id)
        self.assertEqual(cert.status, 'error')
        self.assertIn(self.ERROR_REASON, cert.error_reason)
Example #5
0
    def test_xqueue_submit_task_error(self):
        with self._mock_passing_grade():
            with self._mock_queue(is_successful=False):
                certs_api.generate_user_certificates(self.student, self.course.id)

        # Verify that the certificate has been marked with status error
        cert = GeneratedCertificate.eligible_certificates.get(user=self.student, course_id=self.course.id)
        self.assertEqual(cert.status, 'error')
        self.assertIn(self.ERROR_REASON, cert.error_reason)
Example #6
0
    def test_new_cert_requests_into_xqueue_returns_generating(self):
        with self._mock_passing_grade():
            with self._mock_queue():
                certs_api.generate_user_certificates(self.student,
                                                     self.course.id)

        # Verify that the certificate has status 'generating'
        cert = GeneratedCertificate.objects.get(user=self.student,
                                                course_id=self.course.id)
        self.assertEqual(cert.status, 'generating')
Example #7
0
    def test_new_cert_requests_returns_generating_for_html_certificate(self):
        """
        Test no message sent to Xqueue if HTML certificate view is enabled
        """
        self._setup_course_certificate()
        with mock_passing_grade():
            certs_api.generate_user_certificates(self.student, self.course.id)

        # Verify that the certificate has status 'downloadable'
        cert = GeneratedCertificate.eligible_certificates.get(user=self.student, course_id=self.course.id)
        self.assertEqual(cert.status, CertificateStatuses.downloadable)
Example #8
0
    def test_new_cert_requests_returns_generating_for_html_certificate(self):
        """
        Test no message sent to Xqueue if HTML certificate view is enabled
        """
        self._setup_course_certificate()
        with self._mock_passing_grade():
            certs_api.generate_user_certificates(self.student, self.course.id)

        # Verify that the certificate has status 'downloadable'
        cert = GeneratedCertificate.eligible_certificates.get(user=self.student, course_id=self.course.id)
        self.assertEqual(cert.status, CertificateStatuses.downloadable)
Example #9
0
def issue(request, course_id):
    student = request.user

    # Extracts CourseLocator Object from course ID.
    course_key = locator.CourseLocator.from_string(course_id)
    # Extract the CourseOverview object of the course.
    course = modulestore().get_course(course_key)

    # Check the status of GeneratedCertificate in XQueue.
    certificate_status = \
        certificate_status_for_student(student, course.id)['status']

    # init with a fail, if it didn't match the conditions for issue.
    template = 'edraak_certificates/fail.html'

    # If user didn't issue or pass certificate, or an error happened
    # in the generation.
    if certificate_status in [CertificateStatuses.unavailable,
                              CertificateStatuses.notpassing,
                              CertificateStatuses.error]:
        # If the course is certifiable and the user has passed it.
        if is_certificate_allowed(student, course) and \
                is_student_pass(student, course_id):

            forced_grade = None
            if has_access(student, 'staff', course):
                forced_grade = "Pass"

            # generate the certificate
            generate_user_certificates(student, course.id,
                                       course=course, forced_grade=forced_grade)
            template = 'edraak_certificates/issue.html'

    elif certificate_status == CertificateStatuses.downloadable:
        cert = GeneratedCertificate.objects.get(
            user_id=student.id,
            course_id=course_key,
            status=CertificateStatuses.downloadable
        )
        return render_cert_by_uuid(request, cert.verify_uuid)

    return render_to_response(template, {
        'course_id': course_id,
        'user': student,
        'cert_course': course,
        'is_staff': has_access(student, 'staff', course),
        'studio_url': settings.CMS_BASE
    })
Example #10
0
def request_certificate(request):
    """Request the on-demand creation of a certificate for some user, course.

    A request doesn't imply a guarantee that such a creation will take place.
    We intentionally use the same machinery as is used for doing certification
    at the end of a course run, so that we can be sure users get graded and
    then if and only if they pass, do they get a certificate issued.
    """
    if request.method == "POST":
        if request.user.is_authenticated():
            username = request.user.username
            student = User.objects.get(username=username)
            course_key = SlashSeparatedCourseKey.from_deprecated_string(request.POST.get('course_id'))
            course = modulestore().get_course(course_key, depth=2)

            designation = None
            if 'openedx.stanford.djangoapps.register_cme' in settings.INSTALLED_APPS:
                designation = ExtraInfo.lookup_professional_designation(student)

            status = certificate_status_for_student(student, course_key)['status']
            if status in [CertificateStatuses.unavailable, CertificateStatuses.notpassing, CertificateStatuses.error]:
                log_msg = u'Grading and certification requested for user %s in course %s via /request_certificate call'
                log.info(log_msg, username, course_key)
                status = generate_user_certificates(student, course_key, course=course, designation=designation)
            return HttpResponse(json.dumps({'add_status': status}), content_type='application/json')
        return HttpResponse(json.dumps({'add_status': 'ERRORANONYMOUSUSER'}), content_type='application/json')
Example #11
0
    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, course_id=self.course.id  # pylint: disable=no-member
                ),
            },
        )
Example #12
0
def request_certificate(request):
    """Request the on-demand creation of a certificate for some user, course.

    A request doesn't imply a guarantee that such a creation will take place.
    We intentionally use the same machinery as is used for doing certification
    at the end of a course run, so that we can be sure users get graded and
    then if and only if they pass, do they get a certificate issued.
    """
    if request.method == "POST":
        if request.user.is_authenticated():
            username = request.user.username
            student = User.objects.get(username=username)
            course_key = SlashSeparatedCourseKey.from_deprecated_string(
                request.POST.get('course_id'))
            course = modulestore().get_course(course_key, depth=2)

            status = certificate_status_for_student(student,
                                                    course_key)['status']
            if status in [
                    CertificateStatuses.unavailable,
                    CertificateStatuses.notpassing, CertificateStatuses.error
            ]:
                log_msg = u'Grading and certification requested for user %s in course %s via /request_certificate call'
                logger.info(log_msg, username, course_key)
                status = generate_user_certificates(student,
                                                    course_key,
                                                    course=course)
            return HttpResponse(json.dumps({'add_status': status}),
                                mimetype='application/json')
        return HttpResponse(json.dumps({'add_status': 'ERRORANONYMOUSUSER'}),
                            mimetype='application/json')
Example #13
0
    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,
                ),
            }
        )
Example #14
0
 def test_new_cert_requests_into_xqueue_returns_generating(self):
     """
     mocking grade.grade and returns a summary with passing score.
     new requests saves into xqueue and returns the status
     """
     with patch('capa.xqueue_interface.XQueueInterface.send_to_queue') as mock_send_to_queue:
         mock_send_to_queue.return_value = (0, "Successfully queued")
         self.assertEqual(generate_user_certificates(self.student, self.course), 'generating')
Example #15
0
    def test_cert_api_return(self, self_paced, cert_avail_date, cert_downloadable_status):
        """
        Test 'downloadable status'
        """
        self.course.self_paced = self_paced
        self.course.certificate_available_date = cert_avail_date
        self.course.save()

        CourseEnrollment.enroll(self.student, self.course.id, mode='honor')
        self._setup_course_certificate()
        with 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'],
            cert_downloadable_status
        )
Example #16
0
    def test_new_cert_requests_into_xqueue_returns_generating(self):
        with self._mock_passing_grade():
            with self._mock_queue():
                certs_api.generate_user_certificates(self.student, self.course.id)

        # Verify that the certificate has status 'generating'
        cert = GeneratedCertificate.eligible_certificates.get(user=self.student, course_id=self.course.id)
        self.assertEqual(cert.status, CertificateStatuses.generating)
        self.assert_event_emitted(
            'edx.certificate.created',
            user_id=self.student.id,
            course_id=unicode(self.course.id),
            certificate_url=certs_api.get_certificate_url(self.student.id, self.course.id),
            certificate_id=cert.verify_uuid,
            enrollment_mode=cert.mode,
            generation_mode='batch'
        )
Example #17
0
    def test_new_cert_requests_into_xqueue_returns_generating(self):
        with mock_passing_grade():
            with self._mock_queue():
                certs_api.generate_user_certificates(self.student, self.course.id)

        # Verify that the certificate has status 'generating'
        cert = GeneratedCertificate.eligible_certificates.get(user=self.student, course_id=self.course.id)
        self.assertEqual(cert.status, CertificateStatuses.generating)
        self.assert_event_emitted(
            'edx.certificate.created',
            user_id=self.student.id,
            course_id=unicode(self.course.id),
            certificate_url=certs_api.get_certificate_url(self.student.id, self.course.id),
            certificate_id=cert.verify_uuid,
            enrollment_mode=cert.mode,
            generation_mode='batch'
        )
Example #18
0
    def test_web_certificate(self):
        CourseMode.objects.create(course_id=self.course.id, mode_display_name="Honor", mode_slug=CourseMode.HONOR)
        self.login_and_enroll()

        self.course.cert_html_view_enabled = True
        self.store.update_item(self.course, self.user.id)

        with mock_passing_grade():
            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
            ),
        )
Example #19
0
    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,
            ))
Example #20
0
 def test_new_cert_requests_into_xqueue_returns_generating(self):
     # Mock `grade.grade` and return a summary with passing score.
     # New requests save into xqueue and return the status
     with patch('capa.xqueue_interface.XQueueInterface.send_to_queue'
                ) as mock_send_to_queue:
         mock_send_to_queue.return_value = (0, "Successfully queued")
         result = certs_api.generate_user_certificates(
             self.student, self.course.id)
         self.assertEqual(result, 'generating')
Example #21
0
    def test_cert_api_return(self, self_paced, cert_avail_delta, cert_downloadable_status):
        """
        Test 'downloadable status'
        """
        cert_avail_date = datetime.now(pytz.UTC) + cert_avail_delta
        self.course.self_paced = self_paced
        self.course.certificate_available_date = cert_avail_date
        self.course.save()

        CourseEnrollment.enroll(self.student, self.course.id, mode='honor')
        self._setup_course_certificate()
        with 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'],
            cert_downloadable_status
        )
Example #22
0
    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,
            )
        )
Example #23
0
    def test_web_certificate(self):
        CourseMode.objects.create(
            course_id=self.course.id,
            mode_display_name="Honor",
            mode_slug=CourseMode.HONOR,
        )
        self.login_and_enroll()

        self.course.cert_html_view_enabled = True
        self.store.update_item(self.course, self.user.id)

        with mock_passing_grade():
            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,
            ))
Example #24
0
    def test_generate_user_certificates_with_unverified_cert_status(self):
        """
        Generate user certificate will not raise exception in case of certificate is None.
        """
        # generate certificate with unverified status.
        GeneratedCertificateFactory.create(
            user=self.student,
            course_id=self.course.id,
            status=CertificateStatuses.unverified,
            mode='verified'
        )

        with mock_passing_grade():
            with self._mock_queue(is_successful=False):
                status = certs_api.generate_user_certificates(self.student, self.course.id)
                self.assertEqual(status, None)
Example #25
0
    def test_generate_user_certificates_with_unverified_cert_status(self):
        """
        Generate user certificate will not raise exception in case of certificate is None.
        """
        # generate certificate with unverified status.
        GeneratedCertificateFactory.create(
            user=self.student,
            course_id=self.course.id,
            status=CertificateStatuses.unverified,
            mode='verified'
        )

        with mock_passing_grade():
            with self._mock_queue(is_successful=False):
                status = certs_api.generate_user_certificates(self.student, self.course.id)
                self.assertEqual(status, None)
Example #26
0
    def test_generate_user_certificates_with_unverified_cert_status(self):
        """
        Generate user certificate when the certificate is unverified
        will trigger an update to the certificate if the user has since
        verified.
        """
        self._setup_course_certificate()
        # generate certificate with unverified status.
        GeneratedCertificateFactory.create(
            user=self.student,
            course_id=self.course.id,
            status=CertificateStatuses.unverified,
            mode='verified'
        )

        with mock_passing_grade():
            with self._mock_queue():
                status = certs_api.generate_user_certificates(self.student, self.course.id)
                self.assertEqual(status, 'generating')
Example #27
0
    def test_generate_user_certificates_with_unverified_cert_status(self):
        """
        Generate user certificate when the certificate is unverified
        will trigger an update to the certificate if the user has since
        verified.
        """
        self._setup_course_certificate()
        # generate certificate with unverified status.
        GeneratedCertificateFactory.create(
            user=self.student,
            course_id=self.course.id,
            status=CertificateStatuses.unverified,
            mode='verified'
        )

        with mock_passing_grade():
            with self._mock_queue():
                status = certs_api.generate_user_certificates(self.student, self.course.id)
                self.assertEqual(status, 'generating')
Example #28
0
def generate_user_cert(request, course_id):
    """Start generating a new certificate for the user.

    Certificate generation is allowed if:
    * The user has passed the course, and
    * The user does not already have a pending/completed certificate.

    Note that if an error occurs during certificate generation
    (for example, if the queue is down), then we simply mark the
    certificate generation task status as "error" and re-run
    the task with a management command.  To students, the certificate
    will appear to be "generating" until it is re-run.

    Args:
        request (HttpRequest): The POST request to this view.
        course_id (unicode): The identifier for the course.

    Returns:
        HttpResponse: 200 on success, 400 if a new certificate cannot be generated.

    """

    if not request.user.is_authenticated():
        log.info(u"Anon user trying to generate certificate for %s", course_id)
        return HttpResponseBadRequest(
            _('You must be signed in to {platform_name} to create a certificate.'
              ).format(platform_name=configuration_helpers.get_value(
                  'PLATFORM_NAME', settings.PLATFORM_NAME)))

    student = request.user
    course_key = CourseKey.from_string(course_id)

    course = modulestore().get_course(course_key, depth=2)
    if not course:
        return HttpResponseBadRequest(_("Course is not valid"))

    if not is_course_passed(course, None, student, request):
        return HttpResponseBadRequest(
            _("Your certificate will be available when you pass the course."))

    certificate_status = certs_api.certificate_downloadable_status(
        student, course.id)

    if certificate_status["is_downloadable"]:
        return HttpResponseBadRequest(
            _("Certificate has already been created."))
    elif certificate_status["is_generating"]:
        return HttpResponseBadRequest(_("Certificate is being created."))
    else:
        # If the certificate is not already in-process or completed,
        # then create a new certificate generation task.
        # If the certificate cannot be added to the queue, this will
        # mark the certificate with "error" status, so it can be re-run
        # with a management command.  From the user's perspective,
        # it will appear that the certificate task was submitted successfully.
        base_url = settings.LMS_ROOT_URL
        MandrillClient().send_mail(
            MandrillClient.COURSE_COMPLETION_TEMPLATE, student.email, {
                'course_name':
                course.display_name,
                'course_url':
                get_course_link(course_id=course.id),
                'full_name':
                student.first_name + " " + student.last_name,
                'certificate_url':
                base_url +
                get_certificate_url(user_id=student.id, course_id=course.id),
                'course_library_url':
                base_url + '/courses',
            })
        certs_api.generate_user_certificates(student,
                                             course.id,
                                             course=course,
                                             generation_mode='self')
        _track_successful_certificate_generation(student.id, course.id)
        return HttpResponse()
Example #29
0
def generate_students_certificates(
        _xmodule_instance_args, _entry_id, course_id, task_input, action_name):
    """
    For a given `course_id`, generate certificates for only students present in 'students' key in task_input
    json column, otherwise generate certificates for all enrolled students.
    """
    start_time = time()
    students_to_generate_certs_for = CourseEnrollment.objects.users_enrolled_in(course_id)

    student_set = task_input.get('student_set')
    if student_set == 'all_whitelisted':
        # Generate Certificates for all white listed students.
        students_to_generate_certs_for = students_to_generate_certs_for.filter(
            certificatewhitelist__course_id=course_id,
            certificatewhitelist__whitelist=True
        )

    elif student_set == 'whitelisted_not_generated':
        # Whitelist students who did not get certificates already.
        students_to_generate_certs_for = students_to_generate_certs_for.filter(
            certificatewhitelist__course_id=course_id,
            certificatewhitelist__whitelist=True
        ).exclude(
            generatedcertificate__course_id=course_id,
            generatedcertificate__status__in=CertificateStatuses.PASSED_STATUSES
        )

    elif student_set == "specific_student":
        specific_student_id = task_input.get('specific_student_id')
        students_to_generate_certs_for = students_to_generate_certs_for.filter(id=specific_student_id)

    task_progress = TaskProgress(action_name, students_to_generate_certs_for.count(), start_time)

    current_step = {'step': 'Calculating students already have certificates'}
    task_progress.update_task_state(extra_meta=current_step)

    statuses_to_regenerate = task_input.get('statuses_to_regenerate', [])
    if student_set is not None and not statuses_to_regenerate:
        # We want to skip 'filtering students' only when students are given and statuses to regenerate are not
        students_require_certs = students_to_generate_certs_for
    else:
        students_require_certs = students_require_certificate(
            course_id, students_to_generate_certs_for, statuses_to_regenerate
        )

    if statuses_to_regenerate:
        # Mark existing generated certificates as 'unavailable' before regenerating
        # We need to call this method after "students_require_certificate" otherwise "students_require_certificate"
        # would return no results.
        invalidate_generated_certificates(course_id, students_to_generate_certs_for, statuses_to_regenerate)

    task_progress.skipped = task_progress.total - len(students_require_certs)

    current_step = {'step': 'Generating Certificates'}
    task_progress.update_task_state(extra_meta=current_step)

    course = modulestore().get_course(course_id, depth=0)
    # Generate certificate for each student
    for student in students_require_certs:
        task_progress.attempted += 1
        status = generate_user_certificates(
            student,
            course_id,
            course=course
        )

        if CertificateStatuses.is_passing_status(status):
            task_progress.succeeded += 1
        else:
            task_progress.failed += 1

    return task_progress.update_task_state(extra_meta=current_step)
Example #30
0
def generate_students_certificates(_xmodule_instance_args, _entry_id,
                                   course_id, task_input, action_name):
    """
    For a given `course_id`, generate certificates for only students present in 'students' key in task_input
    json column, otherwise generate certificates for all enrolled students.
    """
    start_time = time()
    students_to_generate_certs_for = CourseEnrollment.objects.users_enrolled_in(
        course_id)

    student_set = task_input.get('student_set')
    if student_set == 'all_whitelisted':
        # Generate Certificates for all white listed students.
        students_to_generate_certs_for = students_to_generate_certs_for.filter(
            certificatewhitelist__course_id=course_id,
            certificatewhitelist__whitelist=True)

    elif student_set == 'whitelisted_not_generated':
        # Whitelist students who did not get certificates already.
        students_to_generate_certs_for = students_to_generate_certs_for.filter(
            certificatewhitelist__course_id=course_id,
            certificatewhitelist__whitelist=True).exclude(
                generatedcertificate__course_id=course_id,
                generatedcertificate__status__in=CertificateStatuses.
                PASSED_STATUSES)

    elif student_set == "specific_student":
        specific_student_id = task_input.get('specific_student_id')
        students_to_generate_certs_for = students_to_generate_certs_for.filter(
            id=specific_student_id)

    task_progress = TaskProgress(action_name,
                                 students_to_generate_certs_for.count(),
                                 start_time)

    current_step = {'step': 'Calculating students already have certificates'}
    task_progress.update_task_state(extra_meta=current_step)

    statuses_to_regenerate = task_input.get('statuses_to_regenerate', [])
    if student_set is not None and not statuses_to_regenerate:
        # We want to skip 'filtering students' only when students are given and statuses to regenerate are not
        students_require_certs = students_to_generate_certs_for
    else:
        students_require_certs = students_require_certificate(
            course_id, students_to_generate_certs_for, statuses_to_regenerate)

    if statuses_to_regenerate:
        # Mark existing generated certificates as 'unavailable' before regenerating
        # We need to call this method after "students_require_certificate" otherwise "students_require_certificate"
        # would return no results.
        invalidate_generated_certificates(course_id,
                                          students_to_generate_certs_for,
                                          statuses_to_regenerate)

    task_progress.skipped = task_progress.total - len(students_require_certs)

    current_step = {'step': 'Generating Certificates'}
    task_progress.update_task_state(extra_meta=current_step)

    course = modulestore().get_course(course_id, depth=0)
    # Generate certificate for each student
    for student in students_require_certs:
        task_progress.attempted += 1
        status = generate_user_certificates(student, course_id, course=course)

        if CertificateStatuses.is_passing_status(status):
            task_progress.succeeded += 1
        else:
            task_progress.failed += 1

    return task_progress.update_task_state(extra_meta=current_step)
Example #31
0
    def handle(self, *args, **options):

        LOGGER.info(
            (
                u"Starting to create tasks for ungenerated certificates "
                u"with arguments %s and options %s"
            ),
            unicode(args),
            unicode(options)
        )

        # Will only generate a certificate if the current
        # status is in the unavailable state, can be set
        # to something else with the force flag

        if options['force']:
            valid_statuses = [getattr(CertificateStatuses, options['force'])]
        else:
            valid_statuses = [CertificateStatuses.unavailable]

        # Print update after this many students

        STATUS_INTERVAL = 500

        if options['course']:
            # try to parse out the course from the serialized form
            try:
                course = CourseKey.from_string(options['course'])
            except InvalidKeyError:
                LOGGER.warning(
                    (
                        u"Course id %s could not be parsed as a CourseKey; "
                        u"falling back to SlashSeparatedCourseKey.from_deprecated_string()"
                    ),
                    options['course']
                )
                course = SlashSeparatedCourseKey.from_deprecated_string(options['course'])
            ended_courses = [course]
        else:
            raise CommandError("You must specify a course")

        for course_key in ended_courses:
            # prefetch all chapters/sequentials by saying depth=2
            course = modulestore().get_course(course_key, depth=2)

            enrolled_students = User.objects.filter(
                courseenrollment__course_id=course_key
            )

            total = enrolled_students.count()
            count = 0
            start = datetime.datetime.now(UTC)

            for student in enrolled_students:
                count += 1
                if count % STATUS_INTERVAL == 0:
                    # Print a status update with an approximation of
                    # how much time is left based on how long the last
                    # interval took
                    diff = datetime.datetime.now(UTC) - start
                    timeleft = diff * (total - count) / STATUS_INTERVAL
                    hours, remainder = divmod(timeleft.seconds, 3600)
                    minutes, _seconds = divmod(remainder, 60)
                    print "{0}/{1} completed ~{2:02}:{3:02}m remaining".format(
                        count, total, hours, minutes)
                    start = datetime.datetime.now(UTC)

                cert_status = certificate_status_for_student(student, course_key)['status']
                LOGGER.info(
                    (
                        u"Student %s has certificate status '%s' "
                        u"in course '%s'"
                    ),
                    student.id,
                    cert_status,
                    unicode(course_key)
                )

                if cert_status in valid_statuses:

                    if not options['noop']:
                        # Add the certificate request to the queue
                        ret = generate_user_certificates(
                            student,
                            course_key,
                            course=course,
                            insecure=options['insecure']
                        )

                        if ret == 'generating':
                            LOGGER.info(
                                (
                                    u"Added a certificate generation task to the XQueue "
                                    u"for student %s in course '%s'. "
                                    u"The new certificate status is '%s'."
                                ),
                                student.id,
                                unicode(course_key),
                                ret
                            )

                    else:
                        LOGGER.info(
                            (
                                u"Skipping certificate generation for "
                                u"student %s in course '%s' "
                                u"because the noop flag is set."
                            ),
                            student.id,
                            unicode(course_key)
                        )

                else:
                    LOGGER.info(
                        (
                            u"Skipped student %s because "
                            u"certificate status '%s' is not in %s"
                        ),
                        student.id,
                        cert_status,
                        unicode(valid_statuses)
                    )

            LOGGER.info(
                (
                    u"Completed ungenerated certificates command "
                    u"for course '%s'"
                ),
                unicode(course_key)
            )
    def handle(self, *args, **options):
        """Resubmit certificates with status 'error'.

        Arguments:
            username (unicode): Identifier for the certificate's user.

        Keyword Arguments:
            course_key_list (list): List of course key strings.

        Raises:
            CommandError

        """
        only_course_keys = []
        for course_key_str in options.get('course_key_list', []):
            try:
                only_course_keys.append(CourseKey.from_string(course_key_str))
            except InvalidKeyError:
                raise CommandError(
                    '"{course_key_str}" is not a valid course key.'.format(
                        course_key_str=course_key_str
                    )
                )

        if only_course_keys:
            LOGGER.info(
                (
                    u'Starting to re-submit certificates with status "error" '
                    u'in these courses: %s'
                ), ", ".join([unicode(key) for key in only_course_keys])
            )
        else:
            LOGGER.info(u'Starting to re-submit certificates with status "error".')

        # Retrieve the IDs of generated certificates with
        # error status in the set of courses we're considering.
        queryset = (
            GeneratedCertificate.objects.select_related('user')
        ).filter(status=CertificateStatuses.error)
        if only_course_keys:
            queryset = queryset.filter(course_id__in=only_course_keys)

        resubmit_list = [(cert.user, cert.course_id) for cert in queryset]
        course_cache = {}
        resubmit_count = 0
        for user, course_key in resubmit_list:
            course = self._load_course_with_cache(course_key, course_cache)

            if course is not None:
                certs_api.generate_user_certificates(user, course_key, course=course)
                resubmit_count += 1
                LOGGER.info(
                    (
                        u"Re-submitted certificate for user %s "
                        u"in course '%s'"
                    ), user.id, course_key
                )
            else:
                LOGGER.error(
                    (
                        u"Could not find course for course key '%s'.  "
                        u"Certificate for user %s will not be resubmitted."
                    ), course_key, user.id
                )

        LOGGER.info("Finished resubmitting %s certificate tasks", resubmit_count)